Skip to content

Using FsPickler

aszabo314 edited this page Aug 29, 2017 · 1 revision

FsPickler

For saving and loading data to file, we use FsPickler (http://mbraceproject.github.io/FsPickler/). It's a tool that can automatically convert any value type (additive/multiplicative types ... i.e. your program state) to a byte array. From a byte array, it automatically restores all types. Example usage:

  • Add a dependency to FsPickler (and FsPickler.Json for readable json serialization) to your project
  • In code:
open FsPickler  //or FsPickler.Json
  
//examples
type Stuff = { something : float; bla : list<Octree> }
let stuff = { something = 3.1415; bla = [laserscan_berlin; prague; london] }
  
//pickle them!
let pickler = FsPickler.CreateBinarySerializer()        //or CreateJsonSerializer(indent = true) for readability
let bytes = pickler.Pickle stuff                        //if json, use PickleToString
do System.Io.File.WriteAllBytes(bytes, "C:\bla\test")   //if json, use File.WriteAllText
  
//unpickle from disk
let bytes = System.Io.File.ReadAllBytes(bytes, "C:\bla\test")   //if json, File.ReadAllText
let stuff = pickler.UnPickle bytes                              //if json, UnPickleOfString
  
//done

This is very practical since it is quick and easy to use and it just works. However, FsPickler only works out of the box with value types (the library is pure). This means that for reference types, like mutables, refs and changeable values, including ModRefs, a custom pickler needs to be written which handles the logic of creating a new cell and applying the serialized value.

ModRefs

The custom pickler for ModRefs handles doing things with its value. When writing, the value is forced and serialzed. When reading, the deserialized value is applied to a new ModRef cell. An implementation is here in the type/module ModRefP:

open System

open Aardvark.Base
open Aardvark.Base.Incremental

open MBrace.FsPickler

[<AutoOpen>]
module PicklerableModRef =

    [<CustomPickler>]
    type ModRefP<'a>(value : 'a) =
        inherit AdaptiveObject()

        let mutable value = value
        let mutable cache = value
        let tracker = ChangeTracker.trackVersion<'a>

        let mutable changed = None

        let getChanged() =
            match changed with
                | None -> 
                    let c = Event<EventHandler<EventArgs>, EventArgs>()
                    changed <- Some c
                    c
                | Some c ->
                    c


        member x.UnsafeCache
            with get() = value
            and set v = value <- v

        member x.Value
            with get() = value
            and set v =
                if tracker v || not <| Object.Equals(v, value) then
                    value <- v
                    let fin = 
                        match changed with
                            | Some c -> Some (fun () -> c.Trigger(x, EventArgs.Empty))
                            | None -> None

                    x.MarkOutdated(fin)


        member x.GetValue(caller : IAdaptiveObject) =
            x.EvaluateAlways caller (fun () ->
                if x.OutOfDate then
                    cache <- value
            
                cache
            )

        static member CreatePickler (resolver : IPicklerResolver) =
            let aResolver = resolver.Resolve<'a> ()

            let writer (ws : WriteState) (modref : ModRefP<'a>) =
                aResolver.Write ws "Value" (modref |> Mod.force)

            let reader (rs : ReadState) =
                let a = aResolver.Read rs "Value"
                ModRefP a

            Pickler.FromPrimitives(reader,writer)

        [<CLIEvent>]
        member x.Changed =
            getChanged().Publish

        override x.ToString() =
           sprintf "{ value = %A }" value

        interface IMod with
            member x.IsConstant = false
            member x.GetValue(caller) = x.GetValue(caller) :> obj

        interface IMod<'a> with
            member x.GetValue(caller) = x.GetValue(caller)

        interface IModRef<'a> with
            member x.Value 
                with get () = x.Value
                and set v = x.Value <- v
            member x.UnsafeCache
                with get() = x.UnsafeCache
                and set v = x.UnsafeCache <- v

            [<CLIEvent>]
            member x.Changed = x.Changed

    module Modp =
        let init v = ModRefP v
Clone this wiki locally
You can’t perform that action at this time.