Skip to content

Instantly share code, notes, and snippets.

@SLAVONchick
Created April 29, 2020 16:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SLAVONchick/fd967ab1c9a611d0d6ca47a5e3777cde to your computer and use it in GitHub Desktop.
Save SLAVONchick/fd967ab1c9a611d0d6ca47a5e3777cde to your computer and use it in GitHub Desktop.
open System
open System.Text
open Utf8Json
[<JsonFormatter(typeof<PointFormatter>)>]
type Point =
{ Longitude: float
Latitude: float }
//type Feature =
// { geometry: GeoJson
// properties: Dictionary<string, obj> }
//
//and GeoJson =
// | Point of coordinates: Point
// | Polygon of coordinates: Point [] []
// | MultiPolygon of coordinates: Point [] [] []
// | Feature of feature: Feature
// | FeatureCollection of features: Feature []
and Feature<'T> =
{ geometry: GeoJson<'T>
properties: 'T }
and [<JsonFormatter(typedefof<GeoJsonFormatter<_>>)>] GeoJson<'T> =
| Point of coordinates: Point
| Polygon of coordinates: Point [] []
| MultiPolygon of coordinates: Point [] [] []
| Feature of feature: Feature<'T>
| FeatureCollection of features: Feature<'T> []
and [<CLIMutable>] private TmpGeoJson =
{ ``type``: string
coordinates: string
feature: string
features: string }
and PointFormatter() =
interface IJsonFormatter<Point> with
member self.Deserialize(reader: byref<JsonReader>, formatterResolver: IJsonFormatterResolver) =
let points = formatterResolver.GetFormatterWithVerify<float []>().Deserialize(&reader, formatterResolver)
{ Longitude = points.[0]; Latitude = points.[1] }
member self.Serialize(writer: byref<JsonWriter>, value: Point, formatterResolver: IJsonFormatterResolver) =
writer.WriteBeginArray()
writer.WriteDouble(value.Longitude)
writer.WriteDouble(value.Latitude)
writer.WriteEndArray()
and GeoJsonFormatter<'T>() =
interface IJsonFormatter<GeoJson<'T>> with
member self.Deserialize(reader: byref<JsonReader>, formatterResolver: IJsonFormatterResolver) =
let tmp = formatterResolver.GetFormatterWithVerify<TmpGeoJson>().Deserialize(&reader, formatterResolver)
let pointArrayToPoint (points: float []) = { Longitude = points.[0]; Latitude = points.[1] }
match tmp.``type``.ToUpperInvariant() with
| "POINT" ->
let mutable reader' = JsonReader(Encoding.UTF8.GetBytes(tmp.coordinates))
formatterResolver.GetFormatterWithVerify<Point>().Deserialize(&reader', formatterResolver) |> Point
| "POLYGON" ->
let mutable reader' = JsonReader(Encoding.UTF8.GetBytes(tmp.coordinates))
formatterResolver.GetFormatterWithVerify<Point [] []>().Deserialize(&reader', formatterResolver) |> Polygon
| "MULTIPOLYGON" ->
let mutable reader' = JsonReader(Encoding.UTF8.GetBytes(tmp.coordinates))
formatterResolver.GetFormatterWithVerify<Point [] [] []>().Deserialize(&reader', formatterResolver) |> MultiPolygon
| "FEATURE" ->
let mutable reader' = JsonReader(Encoding.UTF8.GetBytes(tmp.feature))
let feature = formatterResolver.GetFormatterWithVerify<Feature<'T>>().Deserialize(&reader', formatterResolver)
Feature feature
| "FEATURECOLLECTION" ->
let mutable reader' = JsonReader(Encoding.UTF8.GetBytes(tmp.feature))
let feature = formatterResolver.GetFormatterWithVerify<Feature<'T> []>().Deserialize(&reader', formatterResolver)
FeatureCollection feature
| _ -> failwith (sprintf "Incorrect type (%s)" tmp.``type``)
member self.Serialize(writer: byref<JsonWriter>, value: GeoJson<'T>, formatterResolver: IJsonFormatterResolver) =
match value with
| Point coords ->
formatterResolver
.GetFormatterWithVerify<{|``type``:string; coordinates: Point|}>()
.Serialize(&writer, {|``type``="Point";coordinates=coords|}, formatterResolver)
| Polygon coords ->
formatterResolver
.GetFormatterWithVerify<{|``type``:string; coordinates: Point [] []|}>()
.Serialize(&writer, {|``type``="Polygon";coordinates=coords|}, formatterResolver)
| MultiPolygon coords ->
formatterResolver
.GetFormatterWithVerify<{|``type``:string; coordinates: Point [] [] []|}>()
.Serialize(&writer, {|``type``="MultiPolygon";coordinates=coords|}, formatterResolver)
| Feature feature ->
formatterResolver
.GetFormatterWithVerify<{|``type``:string; geometry: GeoJson<'T>; properties: 'T|}>()
.Serialize(&writer, {|``type``="Feature";geometry=feature.geometry;properties=feature.properties|}, formatterResolver)
| FeatureCollection features ->
formatterResolver
.GetFormatterWithVerify<{|``type``:string; features: {|``type``:string; geometry: GeoJson<'T>; properties: 'T|} [] |}>()
.Serialize(&writer,
{| ``type``="FeatureCollection"
features=features |> Array.map (fun feature ->
{|``type``="Feature"
geometry=feature.geometry
properties=feature.properties |}) |},
formatterResolver)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment