Skip to content

Commit c77be4c

Browse files
authored
Merge pull request #46 from CSBiology/deepCopy
Deep copy improvements
2 parents 073da2d + fd57ba5 commit c77be4c

File tree

17 files changed

+3481
-68
lines changed

17 files changed

+3481
-68
lines changed

src/DynamicObj/DynObj.fs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,4 +216,34 @@ module DynObj =
216216
/// Prints a formatted string containing all static and dynamic properties of the given DynamicObj
217217
/// </summary>
218218
/// <param name="dynObj">The DynamicObj for which to print a formatted string for</param>
219-
let print (dynObj:DynamicObj) = printfn "%s" (dynObj |> format)
219+
let print (dynObj:DynamicObj) = printfn "%s" (dynObj |> format)
220+
221+
/// <summary>
222+
/// function to deep copy a boxed object (if possible)
223+
///
224+
/// The following cases are handled (in this precedence):
225+
///
226+
/// - Basic F# types (bool, byte, sbyte, int16, uint16, int, uint, int64, uint64, nativeint, unativeint, float, float32, char, string, unit, decimal)
227+
///
228+
/// - ResizeArrays and Dictionaries containing any combination of basic F# types
229+
///
230+
/// - Dictionaries containing DynamicObj as keys or values in any combination with DynamicObj or basic F# types as keys or values
231+
///
232+
/// - array&lt;DynamicObj&gt;, list&lt;DynamicObj&gt;, ResizeArray&lt;DynamicObj&gt;: These collections of DynamicObj are copied as a new collection with recursively deep copied elements.
233+
///
234+
/// - System.ICloneable: If the property implements ICloneable, the Clone() method is called on the property.
235+
///
236+
/// - DynamicObj (and derived classes): properties that are themselves DynamicObj instances are deep copied recursively.
237+
/// if a derived class has static properties (e.g. instance properties), these will be copied as dynamic properties on the new instance.
238+
///
239+
/// Note on Classes that inherit from DynamicObj:
240+
///
241+
/// Classes that inherit from DynamicObj will match the `DynamicObj` typecheck if they do not implement ICloneable.
242+
/// The deep copied instances will be cast to DynamicObj with static/instance properties AND dynamic properties all set as dynamic properties.
243+
/// It should be possible to 'recover' the original type by checking if the needed properties exist as dynamic properties,
244+
/// and then passing them to the class constructor if needed.
245+
/// </summary>
246+
/// <param name="o">The object that should be deep copied</param>
247+
/// <param name="includeInstanceProperties">Whether to include instance properties (= 'static' properties on the class) as dynamic properties on the new instance for matched DynamicObj.</param>
248+
let tryDeepCopyObj (includeInstanceProperties:bool) (o:DynamicObj) =
249+
CopyUtils.tryDeepCopyObj(o, includeInstanceProperties)

src/DynamicObj/DynamicObj.fs

Lines changed: 582 additions & 23 deletions
Large diffs are not rendered by default.

src/DynamicObj/FableJS.fs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,4 +168,11 @@ module FableJS =
168168
let cloneICloneable (o:obj) : obj =
169169
jsNative
170170

171+
module Dictionaries =
172+
[<Emit("""$0 instanceof Map""")>]
173+
let isMap (o:obj) : bool =
174+
jsNative
175+
[<Emit("""$0 instanceof Dictionary""")>]
176+
let isDict (o:obj) : bool =
177+
jsNative
171178
#endif

src/DynamicObj/FablePy.fs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,4 +220,10 @@ module FablePy =
220220
[<Emit("""$0.System_ICloneable_Clone()""")>]
221221
let cloneICloneable (o:obj) : obj =
222222
nativeOnly
223+
224+
module Dictionaries =
225+
[<Emit("""isinstance($0, dict)""")>]
226+
let isDict (o:obj) : bool =
227+
nativeOnly
228+
223229
#endif

src/DynamicObj/Playground.fsx

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,10 @@
1313
open Fable.Pyxpecto
1414
open DynamicObj
1515

16-
type T(dyn:string, stat:string) as this=
17-
inherit DynamicObj()
16+
let r1 = ResizeArray([1; 2])
17+
let r2 = ResizeArray([1; 2])
18+
let r3 = r1
1819

19-
do
20-
this.SetProperty("Dyn", dyn)
21-
22-
member this.Stat = stat
23-
24-
let first = T("dyn1", "stat1")
25-
let second = T("dyn2", "stat2")
26-
27-
let _ = second.ShallowCopyDynamicPropertiesTo(first)
28-
29-
first |> DynObj.print
30-
second |> DynObj.print
20+
printfn "%A" (LanguagePrimitives.PhysicalEquality r1 r2)
21+
printfn "%A" (LanguagePrimitives.PhysicalEquality r2 r2)
22+
printfn "%A" (LanguagePrimitives.PhysicalEquality r3 r1)

tests/CSharpTests/CSharpTests.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFramework>net6.0</TargetFramework>
4+
<TargetFramework>net8.0</TargetFramework>
55
<IsPackable>false</IsPackable>
66
</PropertyGroup>
77

tests/DynamicObject.Tests/CopyUtils.tryDeepCopyObj/Dictionaries.fs

Lines changed: 2563 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
module DeepCopyDynamicObj
2+
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
module DeepCopyDynamicObjCollections
2+
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
module DeepCopyICloneable
2+

0 commit comments

Comments
 (0)