forked from dotnet/fsharp
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathevent.fs
More file actions
179 lines (155 loc) · 7.86 KB
/
Copy pathevent.fs
File metadata and controls
179 lines (155 loc) · 7.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
// Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.FSharp.Control
open Microsoft.FSharp.Core
open Microsoft.FSharp.Core.LanguagePrimitives
open Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicOperators
open Microsoft.FSharp.Core.Operators
open Microsoft.FSharp.Collections
open Microsoft.FSharp.Control
open System.Reflection
open System.Diagnostics
#if FX_RESHAPED_REFLECTION
open ReflectionAdapters
type BindingFlags = ReflectionAdapters.BindingFlags
#endif
#if FX_NO_DELEGATE_DYNAMIC_METHOD
#else
#if FX_NO_DELEGATE_DYNAMIC_INVOKE
module Impl =
type System.Delegate with
member d.DynamicInvoke(args: obj[]) =
d.Method.Invoke(d.Target, BindingFlags.Default ||| BindingFlags.Public ||| BindingFlags.NonPublic , null, args, null)
open Impl
#endif
[<CompiledName("FSharpDelegateEvent`1")>]
type DelegateEvent<'Delegate when 'Delegate :> System.Delegate>() =
let mutable multicast : System.Delegate = null
member x.Trigger(args:obj[]) =
match multicast with
| null -> ()
| d -> d.DynamicInvoke(args) |> ignore
member x.Publish =
{ new IDelegateEvent<'Delegate> with
member x.AddHandler(d) =
multicast <- System.Delegate.Combine(multicast, d)
member x.RemoveHandler(d) =
multicast <- System.Delegate.Remove(multicast, d) }
type EventDelegee<'Args>(observer: System.IObserver<'Args>) =
static let makeTuple =
if Microsoft.FSharp.Reflection.FSharpType.IsTuple(typeof<'Args>) then
Microsoft.FSharp.Reflection.FSharpValue.PreComputeTupleConstructor(typeof<'Args>)
else
fun _ -> assert false; null // should not be called, one-argument case don't use makeTuple function
member x.Invoke(_sender:obj, args: 'Args) =
observer.OnNext args
member x.Invoke(_sender:obj, a, b) =
let args = makeTuple([|a; b|]) :?> 'Args
observer.OnNext args
member x.Invoke(_sender:obj, a, b, c) =
let args = makeTuple([|a; b; c|]) :?> 'Args
observer.OnNext args
member x.Invoke(_sender:obj, a, b, c, d) =
let args = makeTuple([|a; b; c; d|]) :?> 'Args
observer.OnNext args
member x.Invoke(_sender:obj, a, b, c, d, e) =
let args = makeTuple([|a; b; c; d; e|]) :?> 'Args
observer.OnNext args
member x.Invoke(_sender:obj, a, b, c, d, e, f) =
let args = makeTuple([|a; b; c; d; e; f|]) :?> 'Args
observer.OnNext args
type EventWrapper<'Delegate,'Args> = delegate of 'Delegate * obj * 'Args -> unit
[<CompiledName("FSharpEvent`2")>]
type Event<'Delegate, 'Args when 'Delegate : delegate<'Args, unit> and 'Delegate :> System.Delegate>() =
let mutable multicast : 'Delegate = Unchecked.defaultof<_>
#if FX_NO_DELEGATE_CREATE_DELEGATE_FROM_STATIC_METHOD
#else
static let mi, argTypes =
let instanceBindingFlags = BindingFlags.Instance ||| BindingFlags.Public ||| BindingFlags.NonPublic ||| BindingFlags.DeclaredOnly
let mi = typeof<'Delegate>.GetMethod("Invoke",instanceBindingFlags)
let actualTypes = mi.GetParameters() |> Array.map (fun p -> p.ParameterType)
mi, actualTypes.[1..]
// For the one-argument case, use an optimization that allows a fast call.
// CreateDelegate creates a delegate that is fast to invoke.
static let invoker =
if argTypes.Length = 1 then
(System.Delegate.CreateDelegate(typeof<EventWrapper<'Delegate,'Args>>, mi) :?> EventWrapper<'Delegate,'Args>)
else
null
#endif
// For the multi-arg case, use a slower DynamicInvoke.
static let invokeInfo =
let instanceBindingFlags = BindingFlags.Instance ||| BindingFlags.Public ||| BindingFlags.NonPublic ||| BindingFlags.DeclaredOnly
#if FX_NO_DELEGATE_CREATE_DELEGATE_FROM_STATIC_METHOD
typeof<EventDelegee<'Args>>.GetMethod("Invoke",instanceBindingFlags)
#else
let mi =
typeof<EventDelegee<'Args>>.GetMethods(instanceBindingFlags)
|> Seq.filter(fun mi -> mi.Name = "Invoke" && mi.GetParameters().Length = argTypes.Length + 1)
|> Seq.exactlyOne
if mi.IsGenericMethodDefinition then
mi.MakeGenericMethod argTypes
else
mi
#endif
member x.Trigger(sender:obj,args: 'Args) =
match box multicast with
| null -> ()
| _ ->
#if FX_NO_DELEGATE_CREATE_DELEGATE_FROM_STATIC_METHOD
#else
match invoker with
| null ->
#endif
let args = Array.append [| sender |] (Microsoft.FSharp.Reflection.FSharpValue.GetTupleFields(box args))
multicast.DynamicInvoke(args) |> ignore
#if FX_NO_DELEGATE_CREATE_DELEGATE_FROM_STATIC_METHOD
#else
| _ ->
// For the one-argument case, use an optimization that allows a fast call.
// CreateDelegate creates a delegate that is fast to invoke.
invoker.Invoke(multicast, sender, args) |> ignore
#endif
member x.Publish =
// Note, we implement each interface explicitly: this works around a bug in the CLR
// implementation on CompactFramework 3.7, used on Windows Phone 7
{ new obj() with
member x.ToString() = "<published event>"
interface IEvent<'Delegate,'Args>
interface IDelegateEvent<'Delegate> with
member e.AddHandler(d) =
multicast <- System.Delegate.Combine(multicast, d) :?> 'Delegate
member e.RemoveHandler(d) =
multicast <- System.Delegate.Remove(multicast, d) :?> 'Delegate
interface System.IObservable<'Args> with
member e.Subscribe(observer) =
let obj = new EventDelegee<'Args>(observer)
let h = System.Delegate.CreateDelegate(typeof<'Delegate>, obj, invokeInfo) :?> 'Delegate
(e :?> IDelegateEvent<'Delegate>).AddHandler(h)
{ new System.IDisposable with
member x.Dispose() = (e :?> IDelegateEvent<'Delegate>).RemoveHandler(h) } }
#endif
[<CompiledName("FSharpEvent`1")>]
type Event<'T> =
val mutable multicast : Handler<'T>
new() = { multicast = null }
member x.Trigger(arg:'T) =
match x.multicast with
| null -> ()
| d -> d.Invoke(null,arg) |> ignore
member x.Publish =
// Note, we implement each interface explicitly: this works around a bug in the CLR
// implementation on CompactFramework 3.7, used on Windows Phone 7
{ new obj() with
member x.ToString() = "<published event>"
interface IEvent<'T>
interface IDelegateEvent<Handler<'T>> with
member e.AddHandler(d) =
x.multicast <- (System.Delegate.Combine(x.multicast, d) :?> Handler<'T>)
member e.RemoveHandler(d) =
x.multicast <- (System.Delegate.Remove(x.multicast, d) :?> Handler<'T>)
interface System.IObservable<'T> with
member e.Subscribe(observer) =
let h = new Handler<_>(fun sender args -> observer.OnNext(args))
(e :?> IEvent<_,_>).AddHandler(h)
{ new System.IDisposable with
member x.Dispose() = (e :?> IEvent<_,_>).RemoveHandler(h) } }