From 11ccc6f2ffb6e69e30fdc25e9e2b31a29a09d5a3 Mon Sep 17 00:00:00 2001 From: mchylek Date: Fri, 4 Mar 2022 14:23:35 +0100 Subject: [PATCH 1/3] Allow custom IPicklerResolver Extend FsPickler static methods to accept IPicklerResolver parameter. --- src/FsPickler/FsPickler/FsPickler.fs | 40 ++++++++++++++-------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/FsPickler/FsPickler/FsPickler.fs b/src/FsPickler/FsPickler/FsPickler.fs index 20a32a22..ba98164f 100644 --- a/src/FsPickler/FsPickler/FsPickler.fs +++ b/src/FsPickler/FsPickler/FsPickler.fs @@ -12,7 +12,7 @@ open MBrace.FsPickler.Hashing type FsPickler private () = static let defaultSerializer = lazy(new BinarySerializer()) - static let resolver () = PicklerCache.Instance :> IPicklerResolver + static let chooseResolver (picklerResolver) = defaultArg picklerResolver (PicklerCache.Instance :> IPicklerResolver) /// /// Create a new FsPickler serializer instance that uses the built-in binary format. @@ -32,12 +32,12 @@ type FsPickler private () = new XmlSerializer(?typeConverter = typeConverter, ?indent = indent, ?picklerResolver = picklerResolver) /// Decides if given type is serializable by FsPickler - static member IsSerializableType<'T> () : bool = - resolver().IsSerializable<'T> () + static member IsSerializableType<'T> ([] ?picklerResolver : IPicklerResolver) : bool = + chooseResolver(picklerResolver).IsSerializable<'T> () /// Decides if given type is serializable by FsPickler - static member IsSerializableType (t : Type) : bool = - resolver().IsSerializable t + static member IsSerializableType (t : Type, [] ?picklerResolver : IPicklerResolver) : bool = + chooseResolver(picklerResolver).IsSerializable t /// /// Decides if given value is serializable object graph without performing an actual serialization. @@ -49,12 +49,12 @@ type FsPickler private () = with :? FsPicklerException -> false /// Auto generates a pickler for given type variable - static member GeneratePickler<'T> () : Pickler<'T> = - resolver().Resolve<'T> () + static member GeneratePickler<'T> ([] ?picklerResolver : IPicklerResolver) : Pickler<'T> = + chooseResolver(picklerResolver).Resolve<'T> () /// Auto generates a pickler for given type - static member GeneratePickler (t : Type) : Pickler = - resolver().Resolve t + static member GeneratePickler (t : Type, [] ?picklerResolver : IPicklerResolver) : Pickler = + chooseResolver(picklerResolver).Resolve t // // Misc utils @@ -68,9 +68,9 @@ type FsPickler private () = /// Value to be cloned. /// Pickler used for cloning. Defaults to auto-generated pickler. /// Streaming context used for cloning. Defaults to null streaming context. - static member Clone<'T> (value : 'T, []?pickler : Pickler<'T>, []?streamingContext : StreamingContext) : 'T = - let pickler = match pickler with None -> resolver().Resolve<'T> () | Some p -> p - let state = new CloneState(resolver(), ?streamingContext = streamingContext) + static member Clone<'T> (value : 'T, []?pickler : Pickler<'T>, []?streamingContext : StreamingContext, [] ?picklerResolver : IPicklerResolver) : 'T = + let pickler = match pickler with None -> chooseResolver(picklerResolver).Resolve<'T> () | Some p -> p + let state = new CloneState(chooseResolver(picklerResolver), ?streamingContext = streamingContext) pickler.Clone state value /// @@ -82,9 +82,9 @@ type FsPickler private () = /// Pickler to be used for traversal. Defaults to auto-generated pickler. /// Streaming context used for cloning. Defaults to null streaming context. /// A sifted wrapper together with all objects that have been sifted. - static member Sift<'T>(value : 'T, sifter : IObjectSifter, []?pickler : Pickler<'T>, []?streamingContext : StreamingContext) : Sifted<'T> * (int64 * obj) [] = - let pickler = match pickler with None -> resolver().Resolve<'T> () | Some p -> p - let state = new CloneState(resolver(), ?streamingContext = streamingContext, sifter = sifter) + static member Sift<'T>(value : 'T, sifter : IObjectSifter, []?pickler : Pickler<'T>, []?streamingContext : StreamingContext, [] ?picklerResolver : IPicklerResolver) : Sifted<'T> * (int64 * obj) [] = + let pickler = match pickler with None -> chooseResolver(picklerResolver).Resolve<'T> () | Some p -> p + let state = new CloneState(chooseResolver(picklerResolver), ?streamingContext = streamingContext, sifter = sifter) let sifted = pickler.Clone state value state.CreateSift(sifted) @@ -109,9 +109,9 @@ type FsPickler private () = /// Pickler to be used for traversal. Defaults to auto-generated pickler. /// Streaming context used for cloning. Defaults to null streaming context. /// An unsifted object graph. - static member UnSift<'T>(sifted : Sifted<'T>, values:(int64 * obj) [], []?pickler : Pickler<'T>, []?streamingContext : StreamingContext) : 'T = - let pickler = match pickler with None -> resolver().Resolve<'T> () | Some p -> p - let state = new CloneState(resolver(), ?streamingContext = streamingContext, unSiftData = (values, sifted.SiftedIndices)) + static member UnSift<'T>(sifted : Sifted<'T>, values:(int64 * obj) [], []?pickler : Pickler<'T>, []?streamingContext : StreamingContext, [] ?picklerResolver : IPicklerResolver) : 'T = + let pickler = match pickler with None -> chooseResolver(picklerResolver).Resolve<'T> () | Some p -> p + let state = new CloneState(chooseResolver(picklerResolver), ?streamingContext = streamingContext, unSiftData = (values, sifted.SiftedIndices)) pickler.Clone state sifted.Value /// Compute size in bytes for given input. @@ -136,9 +136,9 @@ type FsPickler private () = /// Streaming context used for cloning. Defaults to null streaming context. /// Object graph traversal order. Defaults to pre-order traversal. static member VisitObject(visitor : IObjectVisitor, graph : 'T, []?pickler:Pickler<'T>, - []?streamingContext:StreamingContext, []?visitOrder:VisitOrder) = + []?streamingContext:StreamingContext, []?visitOrder:VisitOrder, [] ?picklerResolver : IPicklerResolver) = - let resolver = resolver() + let resolver = chooseResolver(picklerResolver) let pickler = match pickler with None -> resolver.Resolve<'T> () | Some p -> p let state = new VisitState(resolver, visitor, ?streamingContext = streamingContext, ?visitOrder = visitOrder) pickler.Accept state graph From 360a89ea33730867ee19db5d402852923a303df4 Mon Sep 17 00:00:00 2001 From: mchylek Date: Fri, 4 Mar 2022 15:43:52 +0100 Subject: [PATCH 2/3] Update FsPickler.fs Add missing overload and update docs --- src/FsPickler/FsPickler/FsPickler.fs | 45 ++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/src/FsPickler/FsPickler/FsPickler.fs b/src/FsPickler/FsPickler/FsPickler.fs index ba98164f..dac98471 100644 --- a/src/FsPickler/FsPickler/FsPickler.fs +++ b/src/FsPickler/FsPickler/FsPickler.fs @@ -31,11 +31,17 @@ type FsPickler private () = static member CreateXmlSerializer([]?typeConverter : ITypeNameConverter, []?indent : bool, [] ?picklerResolver : IPicklerResolver) = new XmlSerializer(?typeConverter = typeConverter, ?indent = indent, ?picklerResolver = picklerResolver) - /// Decides if given type is serializable by FsPickler + /// + /// Decides if given type is serializable by FsPickler + /// + /// Specify a custom pickler resolver/cache for serialization. Defaults to the singleton pickler cache. static member IsSerializableType<'T> ([] ?picklerResolver : IPicklerResolver) : bool = chooseResolver(picklerResolver).IsSerializable<'T> () - /// Decides if given type is serializable by FsPickler + /// + /// Decides if given type is serializable by FsPickler + /// + /// Specify a custom pickler resolver/cache for serialization. Defaults to the singleton pickler cache. static member IsSerializableType (t : Type, [] ?picklerResolver : IPicklerResolver) : bool = chooseResolver(picklerResolver).IsSerializable t @@ -48,11 +54,17 @@ type FsPickler private () = try FsPickler.EnsureSerializable(graph, ?failOnCloneableOnlyTypes = failOnCloneableOnlyTypes) ; true with :? FsPicklerException -> false - /// Auto generates a pickler for given type variable + /// + /// Auto generates a pickler for given type variable + /// + /// Specify a custom pickler resolver/cache for serialization. Defaults to the singleton pickler cache. static member GeneratePickler<'T> ([] ?picklerResolver : IPicklerResolver) : Pickler<'T> = chooseResolver(picklerResolver).Resolve<'T> () - - /// Auto generates a pickler for given type + + /// + /// Auto generates a pickler for given type + /// + /// Specify a custom pickler resolver/cache for serialization. Defaults to the singleton pickler cache. static member GeneratePickler (t : Type, [] ?picklerResolver : IPicklerResolver) : Pickler = chooseResolver(picklerResolver).Resolve t @@ -68,6 +80,7 @@ type FsPickler private () = /// Value to be cloned. /// Pickler used for cloning. Defaults to auto-generated pickler. /// Streaming context used for cloning. Defaults to null streaming context. + /// Specify a custom pickler resolver/cache for serialization. Defaults to the singleton pickler cache. static member Clone<'T> (value : 'T, []?pickler : Pickler<'T>, []?streamingContext : StreamingContext, [] ?picklerResolver : IPicklerResolver) : 'T = let pickler = match pickler with None -> chooseResolver(picklerResolver).Resolve<'T> () | Some p -> p let state = new CloneState(chooseResolver(picklerResolver), ?streamingContext = streamingContext) @@ -81,6 +94,7 @@ type FsPickler private () = /// Sifting predicate implementation. /// Pickler to be used for traversal. Defaults to auto-generated pickler. /// Streaming context used for cloning. Defaults to null streaming context. + /// Specify a custom pickler resolver/cache for serialization. Defaults to the singleton pickler cache. /// A sifted wrapper together with all objects that have been sifted. static member Sift<'T>(value : 'T, sifter : IObjectSifter, []?pickler : Pickler<'T>, []?streamingContext : StreamingContext, [] ?picklerResolver : IPicklerResolver) : Sifted<'T> * (int64 * obj) [] = let pickler = match pickler with None -> chooseResolver(picklerResolver).Resolve<'T> () | Some p -> p @@ -97,9 +111,9 @@ type FsPickler private () = /// Pickler to be used for traversal. Defaults to auto-generated pickler. /// Streaming context used for cloning. Defaults to null streaming context. /// A sifted wrapper together with all objects that have been sifted. - static member Sift<'T>(value : 'T, sifter : obj -> bool, []?pickler : Pickler<'T>, []?streamingContext : StreamingContext) : Sifted<'T> * (int64 * obj) [] = + static member Sift<'T>(value : 'T, sifter : obj -> bool, []?pickler : Pickler<'T>, []?streamingContext : StreamingContext, [] ?picklerResolver : IPicklerResolver) : Sifted<'T> * (int64 * obj) [] = let sifter = { new IObjectSifter with member __.Sift(_,_,t) = sifter t } - FsPickler.Sift(value, sifter, ?pickler = pickler, ?streamingContext = streamingContext) + FsPickler.Sift(value, sifter, ?pickler = pickler, ?streamingContext = streamingContext, ?picklerResolver = picklerResolver) /// /// Unsifts a provided object graph with given values. @@ -108,6 +122,7 @@ type FsPickler private () = /// Values to be pushed in sift holes. /// Pickler to be used for traversal. Defaults to auto-generated pickler. /// Streaming context used for cloning. Defaults to null streaming context. + /// Specify a custom pickler resolver/cache for serialization. Defaults to the singleton pickler cache. /// An unsifted object graph. static member UnSift<'T>(sifted : Sifted<'T>, values:(int64 * obj) [], []?pickler : Pickler<'T>, []?streamingContext : StreamingContext, [] ?picklerResolver : IPicklerResolver) : 'T = let pickler = match pickler with None -> chooseResolver(picklerResolver).Resolve<'T> () | Some p -> p @@ -135,6 +150,7 @@ type FsPickler private () = /// Pickler to be used for traversal. Defaults to auto-generated pickler. /// Streaming context used for cloning. Defaults to null streaming context. /// Object graph traversal order. Defaults to pre-order traversal. + /// Specify a custom pickler resolver/cache for serialization. Defaults to the singleton pickler cache. static member VisitObject(visitor : IObjectVisitor, graph : 'T, []?pickler:Pickler<'T>, []?streamingContext:StreamingContext, []?visitOrder:VisitOrder, [] ?picklerResolver : IPicklerResolver) = @@ -153,7 +169,8 @@ type FsPickler private () = /// Uses FsPickler to traverse the object graph, gathering types of objects as it goes. /// /// input object graph. - static member GatherTypesInObjectGraph(graph : obj) : Type [] = + /// Specify a custom pickler resolver/cache for serialization. Defaults to the singleton pickler cache. + static member GatherTypesInObjectGraph(graph : obj, [] ?picklerResolver : IPicklerResolver) : Type [] = let gathered = new HashSet () let visitor = { @@ -179,14 +196,15 @@ type FsPickler private () = true // always continue traversal } - do FsPickler.VisitObject(visitor, graph) + do FsPickler.VisitObject(visitor, graph, ?picklerResolver = picklerResolver) gathered |> Seq.toArray /// /// Use FsPickler to traverse the object graph, gathering object instances as it goes. /// /// input object graph. - static member GatherObjectsInGraph (graph : obj) : obj [] = + /// Specify a custom pickler resolver/cache for serialization. Defaults to the singleton pickler cache. + static member GatherObjectsInGraph (graph : obj, [] ?picklerResolver : IPicklerResolver) : obj [] = let gathered = new HashSet () let visitor = { @@ -201,7 +219,7 @@ type FsPickler private () = true // continue traversal } - do FsPickler.VisitObject(visitor, graph) + do FsPickler.VisitObject(visitor, graph, ?picklerResolver = picklerResolver) gathered |> Seq.toArray @@ -210,7 +228,8 @@ type FsPickler private () = /// /// Graph to be checked. /// Fail on types that are declared cloneable only. Defaults to true. - static member EnsureSerializable (graph : 'T, [] ?failOnCloneableOnlyTypes : bool) : unit = + /// Specify a custom pickler resolver/cache for serialization. Defaults to the singleton pickler cache. + static member EnsureSerializable (graph : 'T, [] ?failOnCloneableOnlyTypes : bool, [] ?picklerResolver : IPicklerResolver) : unit = let failOnCloneableOnlyTypes = defaultArg failOnCloneableOnlyTypes true let visitor = { new IObjectVisitor with @@ -220,4 +239,4 @@ type FsPickler private () = else true } - FsPickler.VisitObject(visitor, graph, visitOrder = VisitOrder.PreOrder) \ No newline at end of file + FsPickler.VisitObject(visitor, graph, visitOrder = VisitOrder.PreOrder, ?picklerResolver = picklerResolver) \ No newline at end of file From 99aa6df6a940d015af52768bf44615000b3a6cb8 Mon Sep 17 00:00:00 2001 From: mchylek Date: Mon, 21 Mar 2022 15:45:44 +0100 Subject: [PATCH 3/3] add overloads --- src/FsPickler/FsPickler/FsPickler.fs | 162 ++++++++++++++++++++------- 1 file changed, 120 insertions(+), 42 deletions(-) diff --git a/src/FsPickler/FsPickler/FsPickler.fs b/src/FsPickler/FsPickler/FsPickler.fs index dac98471..5f5c3f2a 100644 --- a/src/FsPickler/FsPickler/FsPickler.fs +++ b/src/FsPickler/FsPickler/FsPickler.fs @@ -12,7 +12,7 @@ open MBrace.FsPickler.Hashing type FsPickler private () = static let defaultSerializer = lazy(new BinarySerializer()) - static let chooseResolver (picklerResolver) = defaultArg picklerResolver (PicklerCache.Instance :> IPicklerResolver) + static let resolver () = PicklerCache.Instance :> IPicklerResolver /// /// Create a new FsPickler serializer instance that uses the built-in binary format. @@ -34,16 +34,15 @@ type FsPickler private () = /// /// Decides if given type is serializable by FsPickler /// - /// Specify a custom pickler resolver/cache for serialization. Defaults to the singleton pickler cache. - static member IsSerializableType<'T> ([] ?picklerResolver : IPicklerResolver) : bool = - chooseResolver(picklerResolver).IsSerializable<'T> () + static member IsSerializableType<'T> () : bool = + resolver().IsSerializable<'T> () /// /// Decides if given type is serializable by FsPickler /// - /// Specify a custom pickler resolver/cache for serialization. Defaults to the singleton pickler cache. - static member IsSerializableType (t : Type, [] ?picklerResolver : IPicklerResolver) : bool = - chooseResolver(picklerResolver).IsSerializable t + /// Type to be checked. + static member IsSerializableType (t : Type) : bool = + resolver().IsSerializable t /// /// Decides if given value is serializable object graph without performing an actual serialization. @@ -57,16 +56,15 @@ type FsPickler private () = /// /// Auto generates a pickler for given type variable /// - /// Specify a custom pickler resolver/cache for serialization. Defaults to the singleton pickler cache. - static member GeneratePickler<'T> ([] ?picklerResolver : IPicklerResolver) : Pickler<'T> = - chooseResolver(picklerResolver).Resolve<'T> () + static member GeneratePickler<'T> () : Pickler<'T> = + resolver().Resolve<'T> () /// /// Auto generates a pickler for given type /// - /// Specify a custom pickler resolver/cache for serialization. Defaults to the singleton pickler cache. - static member GeneratePickler (t : Type, [] ?picklerResolver : IPicklerResolver) : Pickler = - chooseResolver(picklerResolver).Resolve t + /// Type for which pickler will be generated. + static member GeneratePickler (t : Type) : Pickler = + resolver().Resolve t // // Misc utils @@ -80,10 +78,21 @@ type FsPickler private () = /// Value to be cloned. /// Pickler used for cloning. Defaults to auto-generated pickler. /// Streaming context used for cloning. Defaults to null streaming context. - /// Specify a custom pickler resolver/cache for serialization. Defaults to the singleton pickler cache. - static member Clone<'T> (value : 'T, []?pickler : Pickler<'T>, []?streamingContext : StreamingContext, [] ?picklerResolver : IPicklerResolver) : 'T = - let pickler = match pickler with None -> chooseResolver(picklerResolver).Resolve<'T> () | Some p -> p - let state = new CloneState(chooseResolver(picklerResolver), ?streamingContext = streamingContext) + static member Clone<'T> (value : 'T, []?pickler : Pickler<'T>, []?streamingContext : StreamingContext) : 'T = + FsPickler.Clone(value, resolver(), ?pickler = pickler, ?streamingContext = streamingContext) + + /// + /// Performs an in-memory, deep cloning of provided serializable object graph. + /// Cloning is performed on a node-to-node basis and does not make use of intermediate + /// serialization buffers. + /// + /// Value to be cloned. + /// Specify a custom pickler resolver/cache for serialization. + /// Pickler used for cloning. Defaults to auto-generated pickler. + /// Streaming context used for cloning. Defaults to null streaming context. + static member Clone<'T> (value : 'T, picklerResolver : IPicklerResolver, []?pickler : Pickler<'T>, []?streamingContext : StreamingContext) : 'T = + let pickler = match pickler with None -> picklerResolver.Resolve<'T> () | Some p -> p + let state = new CloneState(picklerResolver, ?streamingContext = streamingContext) pickler.Clone state value /// @@ -94,11 +103,23 @@ type FsPickler private () = /// Sifting predicate implementation. /// Pickler to be used for traversal. Defaults to auto-generated pickler. /// Streaming context used for cloning. Defaults to null streaming context. - /// Specify a custom pickler resolver/cache for serialization. Defaults to the singleton pickler cache. /// A sifted wrapper together with all objects that have been sifted. - static member Sift<'T>(value : 'T, sifter : IObjectSifter, []?pickler : Pickler<'T>, []?streamingContext : StreamingContext, [] ?picklerResolver : IPicklerResolver) : Sifted<'T> * (int64 * obj) [] = - let pickler = match pickler with None -> chooseResolver(picklerResolver).Resolve<'T> () | Some p -> p - let state = new CloneState(chooseResolver(picklerResolver), ?streamingContext = streamingContext, sifter = sifter) + static member Sift<'T>(value : 'T, sifter : IObjectSifter, []?pickler : Pickler<'T>, []?streamingContext : StreamingContext) : Sifted<'T> * (int64 * obj) [] = + FsPickler.Sift(value, sifter, resolver(), ?pickler = pickler, ?streamingContext = streamingContext) + + /// + /// Creates a clone of the provided object graph, sifting objects from the graph as specified by the provided sifter implementation. + /// Only reference types can be sifted from a graph. + /// + /// Value to be sifted. + /// Sifting predicate implementation. + /// Specify a custom pickler resolver/cache for serialization. + /// Pickler to be used for traversal. Defaults to auto-generated pickler. + /// Streaming context used for cloning. Defaults to null streaming context. + /// A sifted wrapper together with all objects that have been sifted. + static member Sift<'T>(value : 'T, sifter : IObjectSifter, picklerResolver : IPicklerResolver, []?pickler : Pickler<'T>, []?streamingContext : StreamingContext) : Sifted<'T> * (int64 * obj) [] = + let pickler = match pickler with None -> picklerResolver.Resolve<'T> () | Some p -> p + let state = new CloneState(picklerResolver, ?streamingContext = streamingContext, sifter = sifter) let sifted = pickler.Clone state value state.CreateSift(sifted) @@ -111,9 +132,22 @@ type FsPickler private () = /// Pickler to be used for traversal. Defaults to auto-generated pickler. /// Streaming context used for cloning. Defaults to null streaming context. /// A sifted wrapper together with all objects that have been sifted. - static member Sift<'T>(value : 'T, sifter : obj -> bool, []?pickler : Pickler<'T>, []?streamingContext : StreamingContext, [] ?picklerResolver : IPicklerResolver) : Sifted<'T> * (int64 * obj) [] = + static member Sift<'T>(value : 'T, sifter : obj -> bool, []?pickler : Pickler<'T>, []?streamingContext : StreamingContext) : Sifted<'T> * (int64 * obj) [] = + FsPickler.Sift(value, sifter, resolver(), ?pickler = pickler, ?streamingContext = streamingContext) + + /// + /// Creates a clone of the provided object graph, sifting objects from the graph as specified by the provided sifter implementation. + /// Only reference types can be sifted from a graph. + /// + /// Value to be sifted. + /// Sifting predicate implementation. + /// Specify a custom pickler resolver/cache for serialization. + /// Pickler to be used for traversal. Defaults to auto-generated pickler. + /// Streaming context used for cloning. Defaults to null streaming context. + /// A sifted wrapper together with all objects that have been sifted. + static member Sift<'T>(value : 'T, sifter : obj -> bool, picklerResolver : IPicklerResolver, []?pickler : Pickler<'T>, []?streamingContext : StreamingContext) : Sifted<'T> * (int64 * obj) [] = let sifter = { new IObjectSifter with member __.Sift(_,_,t) = sifter t } - FsPickler.Sift(value, sifter, ?pickler = pickler, ?streamingContext = streamingContext, ?picklerResolver = picklerResolver) + FsPickler.Sift(value, sifter, picklerResolver, ?pickler = pickler, ?streamingContext = streamingContext) /// /// Unsifts a provided object graph with given values. @@ -122,11 +156,24 @@ type FsPickler private () = /// Values to be pushed in sift holes. /// Pickler to be used for traversal. Defaults to auto-generated pickler. /// Streaming context used for cloning. Defaults to null streaming context. - /// Specify a custom pickler resolver/cache for serialization. Defaults to the singleton pickler cache. /// An unsifted object graph. - static member UnSift<'T>(sifted : Sifted<'T>, values:(int64 * obj) [], []?pickler : Pickler<'T>, []?streamingContext : StreamingContext, [] ?picklerResolver : IPicklerResolver) : 'T = - let pickler = match pickler with None -> chooseResolver(picklerResolver).Resolve<'T> () | Some p -> p - let state = new CloneState(chooseResolver(picklerResolver), ?streamingContext = streamingContext, unSiftData = (values, sifted.SiftedIndices)) + static member UnSift<'T>(sifted : Sifted<'T>, values:(int64 * obj) [], []?pickler : Pickler<'T>, []?streamingContext : StreamingContext) : 'T = + let pickler = match pickler with None -> resolver().Resolve<'T> () | Some p -> p + let state = new CloneState(resolver(), ?streamingContext = streamingContext, unSiftData = (values, sifted.SiftedIndices)) + pickler.Clone state sifted.Value + + /// + /// Unsifts a provided object graph with given values. + /// + /// Sifted object graph to be unsifted. + /// Values to be pushed in sift holes. + /// Specify a custom pickler resolver/cache for serialization. + /// Pickler to be used for traversal. Defaults to auto-generated pickler. + /// Streaming context used for cloning. Defaults to null streaming context. + /// An unsifted object graph. + static member UnSift<'T>(sifted : Sifted<'T>, values:(int64 * obj) [], picklerResolver : IPicklerResolver, []?pickler : Pickler<'T>, []?streamingContext : StreamingContext) : 'T = + let pickler = match pickler with None -> picklerResolver.Resolve<'T> () | Some p -> p + let state = new CloneState(picklerResolver, ?streamingContext = streamingContext, unSiftData = (values, sifted.SiftedIndices)) pickler.Clone state sifted.Value /// Compute size in bytes for given input. @@ -150,13 +197,23 @@ type FsPickler private () = /// Pickler to be used for traversal. Defaults to auto-generated pickler. /// Streaming context used for cloning. Defaults to null streaming context. /// Object graph traversal order. Defaults to pre-order traversal. - /// Specify a custom pickler resolver/cache for serialization. Defaults to the singleton pickler cache. static member VisitObject(visitor : IObjectVisitor, graph : 'T, []?pickler:Pickler<'T>, - []?streamingContext:StreamingContext, []?visitOrder:VisitOrder, [] ?picklerResolver : IPicklerResolver) = + []?streamingContext:StreamingContext, []?visitOrder:VisitOrder) = + FsPickler.VisitObject(visitor, graph, resolver(), ?streamingContext = streamingContext, ?visitOrder = visitOrder) - let resolver = chooseResolver(picklerResolver) - let pickler = match pickler with None -> resolver.Resolve<'T> () | Some p -> p - let state = new VisitState(resolver, visitor, ?streamingContext = streamingContext, ?visitOrder = visitOrder) + /// + /// Visits all reference types that appear in the given object graph. + /// + /// Visitor implementation. + /// Object graph. + /// Specify a custom pickler resolver/cache for serialization. + /// Pickler to be used for traversal. Defaults to auto-generated pickler. + /// Streaming context used for cloning. Defaults to null streaming context. + /// Object graph traversal order. Defaults to pre-order traversal. + static member VisitObject(visitor : IObjectVisitor, graph : 'T, picklerResolver : IPicklerResolver, []?pickler:Pickler<'T>, + []?streamingContext:StreamingContext, []?visitOrder:VisitOrder) = + let pickler = match pickler with None -> picklerResolver.Resolve<'T> () | Some p -> p + let state = new VisitState(picklerResolver, visitor, ?streamingContext = streamingContext, ?visitOrder = visitOrder) pickler.Accept state graph /// Compute size and hashcode for given input. @@ -169,8 +226,15 @@ type FsPickler private () = /// Uses FsPickler to traverse the object graph, gathering types of objects as it goes. /// /// input object graph. - /// Specify a custom pickler resolver/cache for serialization. Defaults to the singleton pickler cache. - static member GatherTypesInObjectGraph(graph : obj, [] ?picklerResolver : IPicklerResolver) : Type [] = + static member GatherTypesInObjectGraph(graph : obj) : Type [] = + FsPickler.GatherTypesInObjectGraph(graph, resolver()) + + /// + /// Uses FsPickler to traverse the object graph, gathering types of objects as it goes. + /// + /// input object graph. + /// Specify a custom pickler resolver/cache for serialization. + static member GatherTypesInObjectGraph(graph : obj, picklerResolver : IPicklerResolver) : Type [] = let gathered = new HashSet () let visitor = { @@ -196,15 +260,22 @@ type FsPickler private () = true // always continue traversal } - do FsPickler.VisitObject(visitor, graph, ?picklerResolver = picklerResolver) + do FsPickler.VisitObject(visitor, graph, picklerResolver) gathered |> Seq.toArray /// /// Use FsPickler to traverse the object graph, gathering object instances as it goes. /// /// input object graph. - /// Specify a custom pickler resolver/cache for serialization. Defaults to the singleton pickler cache. - static member GatherObjectsInGraph (graph : obj, [] ?picklerResolver : IPicklerResolver) : obj [] = + static member GatherObjectsInGraph (graph : obj) : obj [] = + FsPickler.GatherObjectsInGraph(graph, resolver()) + + /// + /// Use FsPickler to traverse the object graph, gathering object instances as it goes. + /// + /// input object graph. + /// Specify a custom pickler resolver/cache for serialization. + static member GatherObjectsInGraph (graph : obj, picklerResolver : IPicklerResolver) : obj [] = let gathered = new HashSet () let visitor = { @@ -219,17 +290,24 @@ type FsPickler private () = true // continue traversal } - do FsPickler.VisitObject(visitor, graph, ?picklerResolver = picklerResolver) + do FsPickler.VisitObject(visitor, graph, picklerResolver) gathered |> Seq.toArray - /// /// Traverses the object graph, completing if serializable or raising a serialization exception if not. /// /// Graph to be checked. /// Fail on types that are declared cloneable only. Defaults to true. - /// Specify a custom pickler resolver/cache for serialization. Defaults to the singleton pickler cache. - static member EnsureSerializable (graph : 'T, [] ?failOnCloneableOnlyTypes : bool, [] ?picklerResolver : IPicklerResolver) : unit = + static member EnsureSerializable (graph : 'T, [] ?failOnCloneableOnlyTypes : bool) : unit = + FsPickler.EnsureSerializable(graph, resolver(), ?failOnCloneableOnlyTypes = failOnCloneableOnlyTypes) + + /// + /// Traverses the object graph, completing if serializable or raising a serialization exception if not. + /// + /// Graph to be checked. + /// Specify a custom pickler resolver/cache for serialization. + /// Fail on types that are declared cloneable only. Defaults to true. + static member EnsureSerializable (graph : 'T, picklerResolver : IPicklerResolver, [] ?failOnCloneableOnlyTypes : bool) : unit = let failOnCloneableOnlyTypes = defaultArg failOnCloneableOnlyTypes true let visitor = { new IObjectVisitor with @@ -239,4 +317,4 @@ type FsPickler private () = else true } - FsPickler.VisitObject(visitor, graph, visitOrder = VisitOrder.PreOrder, ?picklerResolver = picklerResolver) \ No newline at end of file + FsPickler.VisitObject(visitor, graph, picklerResolver, visitOrder = VisitOrder.PreOrder) \ No newline at end of file