Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for ResizeArray #57

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions FSharp.Json.Tests/Collections.fs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ module Collections =
let actual = Json.serializeU value
Assert.AreEqual(expected, actual)

[<Test>]
let ``ResizeArray serialization to JSON array`` () =
let expected = """["some","text"]"""
let value = [ "some"; "text" ] |> ResizeArray
let actual = Json.serializeU value
Assert.AreEqual(expected, actual)

[<Test>]
let ``Array serialization/deserialization`` () =
let expected = [|"some"; "text"|]
Expand All @@ -32,6 +39,13 @@ module Collections =
let actual = Json.deserialize<string list> json
Assert.AreEqual(expected, actual)

[<Test>]
let ``ResizeArray serialization/deserialization`` () =
let expected = [ "some"; "text" ] |> ResizeArray
let json = Json.serialize (expected)
let actual = Json.deserialize<ResizeArray<string>> json
Assert.AreEqual(expected, actual)

[<Test>]
let ``Array empty serialization/deserialization`` () =
let expected = [||]
Expand All @@ -45,3 +59,10 @@ module Collections =
let json = Json.serialize(expected)
let actual = Json.deserialize<string list> json
Assert.AreEqual(expected, actual)

[<Test>]
let ``ResizeArray empty serialization/deserialization`` () =
let expected = ResizeArray<string>()
let json = Json.serialize (expected)
let actual = Json.deserialize<ResizeArray<string>> json
Assert.AreEqual(expected, actual)
20 changes: 17 additions & 3 deletions FSharp.Json/Core.fs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ module internal Core =
JsonValue.String ((value :?> Guid).ToString())
| t when t.IsEnum ->
serializeEnum t jsonField value
| t when isTuple t || isList t || isArray t || isMap t || isRecord t || isUnion t ->
| t when isTuple t || isList t || isArray t || isMap t || isRecord t || isUnion t || isResizeArray t ->
serialize config t value
| _ -> failSerialization <| sprintf "Unknown type: %s" t.Name
| true ->
Expand Down Expand Up @@ -263,6 +263,7 @@ module internal Core =
| t when isList t -> serializeEnumerable (value :?> IEnumerable)
| t when isTuple t -> serializeTupleItems (getTupleElements t) (FSharpValue.GetTupleFields value)
| t when isUnion t -> serializeUnion t value
| t when isResizeArray t -> serializeEnumerable (value :?> IEnumerable)
| t ->
let msg = sprintf "Failed to serialize, must be one of following types: record, map, array, list, tuple, union. Type is: %s." t.Name
failSerialization msg
Expand Down Expand Up @@ -370,7 +371,7 @@ module internal Core =
JsonValueHelpers.getGuid path jvalue :> obj
| t when t.IsEnum ->
deserializeEnum path t jsonField jvalue
| t when isTuple t || isList t || isArray t || isMap t || isRecord t || isUnion t ->
| t when isTuple t || isList t || isArray t || isMap t || isRecord t || isUnion t || isResizeArray t ->
deserialize config path t jvalue
| _ -> failDeserialization path <| sprintf "Not supported type: %s" t.Name
transformFromTargetType jsonField.Transform jvalue
Expand Down Expand Up @@ -427,6 +428,19 @@ module internal Core =
arrayValues |> List.ofSeq |> createList itemType
| _ -> failDeserialization path "Failed to parse list from JSON that is not array."

let deserializeResizeArray (path: JsonPath) (t: Type) (jvalue: JsonValue) : obj =
match jvalue with
| JsonValue.Array jvalues ->
let itemType = getResizeArrayItemType t

let arrayValues =
deserializeArrayItems path itemType jvalues

arrayValues
|> List.ofSeq
|> createResizeArray itemType
| _ -> failDeserialization path "Failed to parse resize array from JSON that is not array."

let deserializeArray (path: JsonPath) (t: Type) (jvalue: JsonValue): obj =
match jvalue with
| JsonValue.Array jvalues ->
Expand Down Expand Up @@ -545,5 +559,5 @@ module internal Core =
| t when isList t -> deserializeList path t jvalue
| t when isTuple t -> deserializeTuple path t jvalue
| t when isUnion t -> deserializeUnion path t jvalue
| t when isResizeArray t -> deserializeResizeArray path t jvalue
| _ -> failDeserialization path <| sprintf "Failed to serialize, must be one of following types: record, map, array, list, tuple, union. Type is: %s." t.Name

36 changes: 36 additions & 0 deletions FSharp.Json/Reflection.fs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,19 @@ module internal Reflection =
let getListEmptyProperty_ (t: Type) =
t.GetProperty("Empty")

let isResizeArray_ (t: Type) =
t.IsGenericType
&& t.GetGenericTypeDefinition() = typedefof<ResizeArray<_>>

let getResizeArrayType_ (itemType: Type) =
typedefof<ResizeArray<_>>.MakeGenericType ([| itemType |])

let getResizeArrayItemType_ (t: Type) = t.GetGenericArguments().[0]

let getResizeArrayConstructor_ (t: Type) = t.GetConstructor([||])

let getResizeArrayAdd_ (t: Type) = t.GetMethod("Add")

let isMap_ (t: Type) =
t.IsGenericType && t.GetGenericTypeDefinition() = typedefof<Map<_,_>>

Expand Down Expand Up @@ -72,6 +85,13 @@ module internal Reflection =
let getListConstructor: Type -> MethodInfo = getListConstructor_ |> cacheResult
let getListEmptyProperty: Type -> PropertyInfo = getListEmptyProperty_ |> cacheResult

let isResizeArray : Type -> bool = isResizeArray_ |> cacheResult
let getResizeArrayType : Type -> Type = getResizeArrayType_ |> cacheResult
let getResizeArrayItemType : Type -> Type = getResizeArrayItemType_ |> cacheResult
let getResizeArrayAdd : Type -> MethodInfo = getResizeArrayAdd_ |> cacheResult
let getResizeArrayConstructor : Type -> ConstructorInfo =
getResizeArrayConstructor_ |> cacheResult

let isMap: Type -> bool = isMap_ |> cacheResult
let getMapKeyType: Type -> Type = getMapKeyType_ |> cacheResult
let getMapValueType: Type -> Type = getMapValueType_ |> cacheResult
Expand All @@ -98,6 +118,22 @@ module internal Reflection =
let theList = (getListEmptyProperty listType).GetValue(null)
List.foldBack addItem items theList

let createResizeArray (itemType: Type) (items: obj list) =
let resizeArrayType = getResizeArrayType itemType

let resizeArrayAdd resizeArray item =
(getResizeArrayAdd resizeArrayType)
.Invoke(resizeArray, [| item |])
|> ignore

resizeArray

let newResizeArray =
(getResizeArrayConstructor resizeArrayType)
.Invoke([||])

List.fold resizeArrayAdd newResizeArray items

let KvpKey (value: obj): obj =
let keyProperty = value.GetType().GetProperty("Key")
keyProperty.GetValue(value, null)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ option | option is not represented by itself<br>`None` value might be represente
tuple | list
record | object
map | object
array<br>list | list
array<br>list<br>ResizeArray | list
union | object with special structure<br>read more in [Unions](#unions) section
obj | read [Untyped Data](#untyped-data) section

Expand Down