Last active
April 26, 2021 19:49
-
-
Save peterhirn/8f2151afb4951a96b38137a9279a6ef6 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
open System.Text.Json | |
open System.Text.Json.Serialization | |
open MathNet.Spatial.Euclidean | |
let private convertName (options : JsonSerializerOptions) : string -> string = | |
match options.PropertyNamingPolicy with | |
| null -> id | |
| policy -> policy.ConvertName | |
let private readOrFail (reader : Utf8JsonReader byref) = | |
if not (reader.Read()) then | |
raise (JsonException "Failed to read token") | |
let private expectProperty (reader : Utf8JsonReader byref) options name = | |
readOrFail &reader | |
if reader.TokenType <> JsonTokenType.PropertyName then | |
raise (JsonException $"Expected property name token, got '{reader.TokenType}'") | |
let propertyName = reader.GetString() | |
let converted = convertName options name | |
if propertyName <> converted then | |
raise (JsonException $"Expected property name '{converted}', got '{propertyName}'") | |
readOrFail &reader | |
let private expectStartObject (reader : Utf8JsonReader byref) = | |
if reader.TokenType <> JsonTokenType.StartObject then | |
raise (JsonException $"Expected start object token, got '{reader.TokenType}'") | |
let private expectEndObject (reader : Utf8JsonReader byref) = | |
readOrFail &reader | |
if reader.TokenType <> JsonTokenType.EndObject then | |
raise (JsonException $"Expected end object token, got '{reader.TokenType}'") | |
type Vector3DConverter() = | |
inherit JsonConverter<Vector3D>() | |
let readDouble (reader : Utf8JsonReader byref) options name = | |
expectProperty &reader options name | |
reader.GetDouble() | |
override _.Read(reader : Utf8JsonReader byref, _, options : JsonSerializerOptions) = | |
expectStartObject &reader | |
let x = readDouble &reader options "X" | |
let y = readDouble &reader options "Y" | |
let z = readDouble &reader options "Z" | |
expectEndObject &reader | |
Vector3D(x, y, z) | |
override _.Write(writer : Utf8JsonWriter, vector : Vector3D, options : JsonSerializerOptions) = | |
writer.WriteStartObject() | |
let convert = convertName options | |
writer.WritePropertyName (convert "X") | |
writer.WriteNumberValue vector.X | |
writer.WritePropertyName (convert "Y") | |
writer.WriteNumberValue vector.Y | |
writer.WritePropertyName (convert "Z") | |
writer.WriteNumberValue vector.Z | |
writer.WriteEndObject() | |
type UnitVector3DConverter() = | |
inherit JsonConverter<UnitVector3D>() | |
override _.Read(reader : Utf8JsonReader byref, _, options : JsonSerializerOptions) = | |
JsonSerializer.Deserialize<Vector3D>(&reader, options).ToVector() |> UnitVector3D.OfVector | |
override _.Write(writer : Utf8JsonWriter, vector : UnitVector3D, options : JsonSerializerOptions) = | |
JsonSerializer.Serialize(writer, vector.ToVector3D(), options) | |
type Point3DConverter() = | |
inherit JsonConverter<Point3D>() | |
override _.Read(reader : Utf8JsonReader byref, _, options : JsonSerializerOptions) = | |
JsonSerializer.Deserialize<Vector3D>(&reader, options).ToVector() |> Point3D.OfVector | |
override _.Write(writer : Utf8JsonWriter, point : Point3D, options : JsonSerializerOptions) = | |
JsonSerializer.Serialize(writer, point.ToVector3D(), options) | |
type CoordinateSystemConverter() = | |
inherit JsonConverter<CoordinateSystem>() | |
let [<Literal>] Origin = "Origin" | |
let [<Literal>] XAxis = "XAxis" | |
let [<Literal>] YAxis = "YAxis" | |
let [<Literal>] ZAxis = "ZAxis" | |
let readPoint3D (reader : Utf8JsonReader byref) options name = | |
expectProperty &reader options name | |
JsonSerializer.Deserialize<Point3D>(&reader, options) | |
let readVector3D (reader : Utf8JsonReader byref) options name = | |
expectProperty &reader options name | |
JsonSerializer.Deserialize<Vector3D>(&reader, options) | |
override _.Read(reader : Utf8JsonReader byref, _, options : JsonSerializerOptions) = | |
expectStartObject &reader | |
let origin = readPoint3D &reader options Origin | |
let xAxis = readVector3D &reader options XAxis | |
let yAxis = readVector3D &reader options YAxis | |
let zAxis = readVector3D &reader options ZAxis | |
expectEndObject &reader | |
CoordinateSystem(origin, xAxis, yAxis, zAxis) | |
override _.Write(writer : Utf8JsonWriter, system : CoordinateSystem, options : JsonSerializerOptions) = | |
writer.WriteStartObject() | |
let convert = convertName options | |
writer.WritePropertyName (convert Origin) | |
JsonSerializer.Serialize(writer, system.Origin, options) | |
writer.WritePropertyName (convert XAxis) | |
JsonSerializer.Serialize(writer, system.XAxis, options) | |
writer.WritePropertyName (convert YAxis) | |
JsonSerializer.Serialize(writer, system.YAxis, options) | |
writer.WritePropertyName (convert ZAxis) | |
JsonSerializer.Serialize(writer, system.ZAxis, options) | |
writer.WriteEndObject() | |
let options = | |
lazy | |
let fsharpConverter = | |
JsonFSharpConverter( | |
unionEncoding = (JsonUnionEncoding.ThothLike ||| JsonUnionEncoding.UnwrapOption) | |
) | |
let options = JsonSerializerOptions() | |
options.Converters.Add fsharpConverter | |
options.Converters.Add (Vector3DConverter()) | |
options.Converters.Add (UnitVector3DConverter()) | |
options.Converters.Add (Point3DConverter()) | |
options.Converters.Add (CoordinateSystemConverter()) | |
options.IgnoreNullValues <- true | |
options.WriteIndented <- true | |
options.PropertyNamingPolicy <- JsonNamingPolicy.CamelCase | |
options | |
let serialize source = | |
JsonSerializer.Serialize(source, options.Value) | |
let deserialize<'a> (source : string) : 'a = | |
JsonSerializer.Deserialize(source, options.Value) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment