Skip to content

Commit a1e9994

Browse files
committed
minimal (rather ugly) fix for #87
1 parent 8518de2 commit a1e9994

3 files changed

Lines changed: 98 additions & 5 deletions

File tree

src/FSharp.Data.Adaptive/AdaptiveValue/AdaptiveValue.fs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
namespace FSharp.Data.Adaptive
22

33
open System
4+
#nowarn "7331"
45

56
type IAdaptiveValue =
67
inherit IAdaptiveObject
@@ -108,7 +109,13 @@ module AVal =
108109
[<StructuredFormatDisplay("{AsString}")>]
109110
type MapNonAdaptiveVal<'a, 'b>(mapping : 'a -> 'b, input : aval<'a>) =
110111

111-
override x.ToString() = input.ToString()
112+
override x.ToString() =
113+
if input.OutOfDate then
114+
"aval*"
115+
else
116+
let v = input.GetValue AdaptiveToken.Top
117+
sprintf "aval(%A)" (mapping v)
118+
112119
member x.AsString = x.ToString()
113120

114121
member x.Mapping = mapping
@@ -150,8 +157,19 @@ module AVal =
150157
#else
151158
typeof<'b>
152159
#endif
153-
member x.GetValueUntyped(t) = input.GetValue(t) |> mapping :> obj
154-
member x.GetValue(t) = input.GetValue(t) |> mapping
160+
member x.GetValueUntyped(t) =
161+
if Unchecked.isNull t.caller then
162+
input.GetValue t |> mapping :> obj
163+
else
164+
let c = DecoratedObject.Create(t.caller, x)
165+
input.GetValue(t.WithCaller c) |> mapping :> obj
166+
167+
member x.GetValue(t) =
168+
if Unchecked.isNull t.caller then
169+
input.GetValue t |> mapping
170+
else
171+
let c = DecoratedObject.Create(t.caller, x)
172+
input.GetValue(t.WithCaller c) |> mapping
155173

156174
type Caster<'a, 'b> private() =
157175
static let cast =

src/FSharp.Data.Adaptive/Core/Transaction.fs

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
open System
44
open System.Threading
55

6+
#nowarn "7331"
7+
68
[<AutoOpen>]
79
module internal LockingExtensions =
810
type IAdaptiveObject with
@@ -29,6 +31,50 @@ exception LevelChangedException of
2931
/// The new level for the top-level object.
3032
newLevel : int
3133

34+
/// internal type used for properly handling of decorator objects (as introduced in AVal.mapNonAdaptive)
35+
/// Note that it should never be necessary to use this in user-code.
36+
[<CompilerMessage("internal", 7331)>]
37+
type internal DecoratedObject private(real : IAdaptiveObject, decorator : IAdaptiveObject) =
38+
let mutable weak : WeakReference<IAdaptiveObject> = null
39+
40+
interface IAdaptiveObject with
41+
member x.Tag
42+
with get() = null
43+
and set _ = ()
44+
45+
member x.IsConstant = false
46+
member x.Weak =
47+
// Note that we accept the race conditon here since locking the object
48+
// would potentially cause deadlocks and the worst case is, that we
49+
// create two different WeakReferences for the same object
50+
let w = weak
51+
if isNull w then
52+
let w = WeakReference<_>(x :> IAdaptiveObject)
53+
weak <- w
54+
w
55+
else
56+
w
57+
member x.Outputs = Unchecked.defaultof<_>
58+
member x.Mark() = false
59+
member x.AllInputsProcessed(_) = ()
60+
member x.InputChanged(_, _) = ()
61+
62+
member x.OutOfDate
63+
with get() = false
64+
and set o = ()
65+
66+
member x.Level
67+
with get() = real.Level
68+
and set l = real.Level <- l
69+
70+
member x.Real = real
71+
member x.Decorator = decorator
72+
73+
static member Create(real : IAdaptiveObject, decorator : IAdaptiveObject) =
74+
match real with
75+
| :? DecoratedObject as r -> r
76+
| _ -> DecoratedObject(real, decorator)
77+
3278

3379
/// Holds a set of adaptive objects which have been changed and shall
3480
/// therefore be marked as outOfDate. Committing the transaction propagates
@@ -180,8 +226,13 @@ type Transaction() =
180226
for i in 0 .. outputCount - 1 do
181227
let o = outputs.[i]
182228
outputs.[i] <- Unchecked.defaultof<_>
183-
o.InputChanged(x, e)
184-
x.Enqueue o
229+
match o with
230+
| :? DecoratedObject as o ->
231+
o.Real.InputChanged(x, o.Decorator)
232+
x.Enqueue o.Real
233+
| _ ->
234+
o.InputChanged(x, e)
235+
x.Enqueue o
185236

186237
current <- Unchecked.defaultof<_>
187238

src/Test/FSharp.Data.Adaptive.Tests/AVal.fs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,4 +235,28 @@ let ``[AVal] ChangeableLazyVal working``() =
235235
test.OutOfDate |> should be False
236236
()
237237

238+
[<Test>]
239+
let ``[AVal] map non-adaptive and bind``() =
240+
let v = AVal.init true
241+
let a = AVal.constant 0
242+
let b = AVal.constant 1
243+
244+
let output = v |> AVal.map id |> AVal.mapNonAdaptive id |> AVal.bind (fun flag -> if flag then a else b)
245+
246+
output |> AVal.force |> should equal 0
247+
248+
transact (fun () -> v.Value <- false)
249+
output |> AVal.force |> should equal 1
250+
251+
[<Test>]
252+
let ``[AVal] multi map non-adaptive and bind``() =
253+
let v = AVal.init true
254+
let a = AVal.constant 0
255+
let b = AVal.constant 1
256+
257+
let output = v |> AVal.map id |> AVal.mapNonAdaptive id |> AVal.mapNonAdaptive id |> AVal.bind (fun flag -> if flag then a else b)
258+
259+
output |> AVal.force |> should equal 0
238260

261+
transact (fun () -> v.Value <- false)
262+
output |> AVal.force |> should equal 1

0 commit comments

Comments
 (0)