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 recursively defined message structures. #26

Open
wants to merge 3 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
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import Dict
type alias Bar =
{ field : Bool -- 1
}
type BarMessage = BarMessage Bar


barDecoder : JD.Decoder Bar
Expand All @@ -31,51 +32,54 @@ barEncoder v =


type alias Foo =
{ stringToBars : Dict.Dict String Bar -- 8
{ stringToBars : Dict.Dict String BarMessage -- 8
, stringToStrings : Dict.Dict String String -- 7
}
type FooMessage = FooMessage Foo


fooDecoder : JD.Decoder Foo
fooDecoder =
JD.lazy <| \_ -> decode Foo
|> mapEntries "stringToBars" barDecoder
|> mapEntries "stringToBars" (JD.map BarMessage barDecoder)
|> mapEntries "stringToStrings" JD.string


fooEncoder : Foo -> JE.Value
fooEncoder v =
JE.object <| List.filterMap identity <|
[ (mapEntriesFieldEncoder "stringToBars" barEncoder v.stringToBars)
[ (mapEntriesFieldEncoder "stringToBars" (\(BarMessage f) -> barEncoder f) v.stringToBars)
, (mapEntriesFieldEncoder "stringToStrings" JE.string v.stringToStrings)
]


type alias Foo_StringToBarsEntry =
{ key : String -- 1
, value : Maybe Bar -- 2
, value : Maybe BarMessage -- 2
}
type Foo_StringToBarsEntryMessage = Foo_StringToBarsEntryMessage Foo_StringToBarsEntry


foo_StringToBarsEntryDecoder : JD.Decoder Foo_StringToBarsEntry
foo_StringToBarsEntryDecoder =
JD.lazy <| \_ -> decode Foo_StringToBarsEntry
|> required "key" JD.string ""
|> optional "value" barDecoder
|> optional "value" (JD.map BarMessage barDecoder)


foo_StringToBarsEntryEncoder : Foo_StringToBarsEntry -> JE.Value
foo_StringToBarsEntryEncoder v =
JE.object <| List.filterMap identity <|
[ (requiredFieldEncoder "key" JE.string "" v.key)
, (optionalEncoder "value" barEncoder v.value)
, (optionalEncoder "value" (\(BarMessage f) -> barEncoder f) v.value)
]


type alias Foo_StringToStringsEntry =
{ key : String -- 1
, value : String -- 2
}
type Foo_StringToStringsEntryMessage = Foo_StringToStringsEntryMessage Foo_StringToStringsEntry


foo_StringToStringsEntryDecoder : JD.Decoder Foo_StringToStringsEntry
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import Json.Encode as JE
type alias File1Message =
{ field : Bool -- 1
}
type File1MessageMessage = File1MessageMessage File1Message


file1MessageDecoder : JD.Decoder File1Message
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import Json.Encode as JE
type alias File2Message =
{ field : Bool -- 1
}
type File2MessageMessage = File2MessageMessage File2Message


file2MessageDecoder : JD.Decoder File2Message
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ secondOneofEncoder v =
Just ( "boolField", JE.bool x )
OtherStringField x ->
Just ( "otherStringField", JE.string x )
type FooMessage = FooMessage Foo


fooDecoder : JD.Decoder Foo
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ enumEncoder v =
type alias SubMessage =
{ int32Field : Int -- 1
}
type SubMessageMessage = SubMessageMessage SubMessage


subMessageDecoder : JD.Decoder SubMessage
Expand Down Expand Up @@ -100,12 +101,13 @@ type alias Foo =
, boolField : Bool -- 13
, stringField : String -- 14
, enumField : Enum -- 15
, subMessage : Maybe SubMessage -- 16
, subMessage : Maybe SubMessageMessage -- 16
, repeatedInt64Field : List Int -- 17
, repeatedEnumField : List Enum -- 18
, nestedMessageField : Maybe Foo_NestedMessage -- 19
, nestedMessageField : Maybe Foo_NestedMessageMessage -- 19
, nestedEnumField : Foo_NestedEnum -- 20
}
type FooMessage = FooMessage Foo


type Foo_NestedEnum
Expand All @@ -130,10 +132,10 @@ fooDecoder =
|> required "boolField" JD.bool False
|> required "stringField" JD.string ""
|> required "enumField" enumDecoder enumDefault
|> optional "subMessage" subMessageDecoder
|> optional "subMessage" (JD.map SubMessageMessage subMessageDecoder)
|> repeated "repeatedInt64Field" intDecoder
|> repeated "repeatedEnumField" enumDecoder
|> optional "nestedMessageField" foo_NestedMessageDecoder
|> optional "nestedMessageField" (JD.map Foo_NestedMessageMessage foo_NestedMessageDecoder)
|> required "nestedEnumField" foo_NestedEnumDecoder foo_NestedEnumDefault


Expand Down Expand Up @@ -173,10 +175,10 @@ fooEncoder v =
, (requiredFieldEncoder "boolField" JE.bool False v.boolField)
, (requiredFieldEncoder "stringField" JE.string "" v.stringField)
, (requiredFieldEncoder "enumField" enumEncoder enumDefault v.enumField)
, (optionalEncoder "subMessage" subMessageEncoder v.subMessage)
, (optionalEncoder "subMessage" (\(SubMessageMessage f) -> subMessageEncoder f) v.subMessage)
, (repeatedFieldEncoder "repeatedInt64Field" numericStringEncoder v.repeatedInt64Field)
, (repeatedFieldEncoder "repeatedEnumField" enumEncoder v.repeatedEnumField)
, (optionalEncoder "nestedMessageField" foo_NestedMessageEncoder v.nestedMessageField)
, (optionalEncoder "nestedMessageField" (\(Foo_NestedMessageMessage f) -> foo_NestedMessageEncoder f) v.nestedMessageField)
, (requiredFieldEncoder "nestedEnumField" foo_NestedEnumEncoder foo_NestedEnumDefault v.nestedEnumField)
]

Expand All @@ -196,6 +198,7 @@ foo_NestedEnumEncoder v =
type alias Foo_NestedMessage =
{ int32Field : Int -- 1
}
type Foo_NestedMessageMessage = Foo_NestedMessageMessage Foo_NestedMessage


foo_NestedMessageDecoder : JD.Decoder Foo_NestedMessage
Expand All @@ -214,6 +217,7 @@ foo_NestedMessageEncoder v =
type alias Foo_NestedMessage_NestedNestedMessage =
{ int32Field : Int -- 1
}
type Foo_NestedMessage_NestedNestedMessageMessage = Foo_NestedMessage_NestedNestedMessageMessage Foo_NestedMessage_NestedNestedMessage


foo_NestedMessage_NestedNestedMessageDecoder : JD.Decoder Foo_NestedMessage_NestedNestedMessage
Expand Down Expand Up @@ -245,8 +249,9 @@ type alias FooRepeated =
, boolField : List Bool -- 13
, stringField : List String -- 14
, enumField : List Enum -- 15
, subMessage : List SubMessage -- 16
, subMessage : List SubMessageMessage -- 16
}
type FooRepeatedMessage = FooRepeatedMessage FooRepeated


fooRepeatedDecoder : JD.Decoder FooRepeated
Expand All @@ -267,7 +272,7 @@ fooRepeatedDecoder =
|> repeated "boolField" JD.bool
|> repeated "stringField" JD.string
|> repeated "enumField" enumDecoder
|> repeated "subMessage" subMessageDecoder
|> repeated "subMessage" (JD.map SubMessageMessage subMessageDecoder)


fooRepeatedEncoder : FooRepeated -> JE.Value
Expand All @@ -288,5 +293,5 @@ fooRepeatedEncoder v =
, (repeatedFieldEncoder "boolField" JE.bool v.boolField)
, (repeatedFieldEncoder "stringField" JE.string v.stringField)
, (repeatedFieldEncoder "enumField" enumEncoder v.enumField)
, (repeatedFieldEncoder "subMessage" subMessageEncoder v.subMessage)
, (repeatedFieldEncoder "subMessage" (\(SubMessageMessage f) -> subMessageEncoder f) v.subMessage)
]
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import Json.Encode as JE
type alias Message =
{ doubleValueField : Maybe Float -- 1
}
type MessageMessage = MessageMessage Message


messageDecoder : JD.Decoder Message
Expand Down
16 changes: 12 additions & 4 deletions protoc-gen-elm/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ func (fg *FileGenerator) GenerateMessageDefinition(prefix string, inMessage *des
fg.GenerateOneofEncoder(prefix, inMessage, i)
}

fg.P("type %sMessage = %sMessage %s", typeName, typeName, typeName)

return nil
}

Expand Down Expand Up @@ -248,14 +250,20 @@ func fieldElmType(inField *descriptor.FieldDescriptorProto) string {
return "Bool"
case descriptor.FieldDescriptorProto_TYPE_STRING:
return "String"
case descriptor.FieldDescriptorProto_TYPE_MESSAGE,
descriptor.FieldDescriptorProto_TYPE_ENUM:
case descriptor.FieldDescriptorProto_TYPE_ENUM:
// Well known types.
if n, ok := excludedTypes[inField.GetTypeName()]; ok {
return n
}
_, messageName := convert(inField.GetTypeName())
return messageName
case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
// Well known types.
if n, ok := excludedTypes[inField.GetTypeName()]; ok {
return n
}
_, messageName := convert(inField.GetTypeName())
return messageName + "Message"
case descriptor.FieldDescriptorProto_TYPE_BYTES:
// XXX
return "Bytes"
Expand Down Expand Up @@ -297,7 +305,7 @@ func fieldEncoderName(inField *descriptor.FieldDescriptorProto) string {
return n
}
_, messageName := convert(inField.GetTypeName())
return encoderName(messageName)
return fmt.Sprintf("(\\(%sMessage f) -> %s f)", messageName, encoderName(messageName))
case descriptor.FieldDescriptorProto_TYPE_BYTES:
return "bytesFieldEncoder"
default:
Expand Down Expand Up @@ -336,7 +344,7 @@ func fieldDecoderName(inField *descriptor.FieldDescriptorProto) string {
return n
}
_, messageName := convert(inField.GetTypeName())
return decoderName(messageName)
return fmt.Sprintf("(JD.map %sMessage %s)", messageName, decoderName(messageName))
case descriptor.FieldDescriptorProto_TYPE_BYTES:
return "bytesFieldDecoder"
default:
Expand Down
1 change: 1 addition & 0 deletions tests/Dir/Other_dir.elm
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import Json.Encode as JE
type alias OtherDir =
{ stringField : String -- 1
}
type OtherDirMessage = OtherDirMessage OtherDir


otherDirDecoder : JD.Decoder OtherDir
Expand Down
1 change: 1 addition & 0 deletions tests/Fuzzer.elm
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type alias Fuzz =
, int32ValueField : Maybe Int -- 4
, timestampField : Maybe Timestamp -- 5
}
type FuzzMessage = FuzzMessage Fuzz


fuzzDecoder : JD.Decoder Fuzz
Expand Down
2 changes: 2 additions & 0 deletions tests/Integers.elm
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type alias ThirtyTwo =
, fixed32Field : Int -- 4
, sfixed32Field : Int -- 5
}
type ThirtyTwoMessage = ThirtyTwoMessage ThirtyTwo


thirtyTwoDecoder : JD.Decoder ThirtyTwo
Expand Down Expand Up @@ -48,6 +49,7 @@ type alias SixtyFour =
, fixed64Field : Int -- 4
, sfixed64Field : Int -- 5
}
type SixtyFourMessage = SixtyFourMessage SixtyFour


sixtyFourDecoder : JD.Decoder SixtyFour
Expand Down
1 change: 1 addition & 0 deletions tests/Keywords.elm
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type alias Keywords =
, port_ : Int -- 13
, as_ : Int -- 14
}
type KeywordsMessage = KeywordsMessage Keywords


keywordsDecoder : JD.Decoder Keywords
Expand Down
57 changes: 27 additions & 30 deletions tests/Main.elm
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module Main exposing (assertEncodeDecode, decode, emptyJson, encode, foo, fooDefault, fooJson, fuzz, genFuzz, json32numbers, json32strings, json64numbers, json64strings, map, mapJson, msg, msg32, msg64, msgDefault, msgEmpty, msgExtraFieldJson, msgJson, nullJson, oo1Set, oo1SetJson, oo2Set, oo2SetJson, rec1, rec2, recDefault, recJson1, recJson2, suite, timestampFoo, timestampJson, wrappersEmpty, wrappersJsonEmpty, wrappersJsonNull, wrappersJsonSet, wrappersJsonZero, wrappersSet, wrappersZero, wrongTypeJson)

import Dir.Other_dir as OD
import Expect exposing (..)
import Fuzz exposing (..)
import Fuzzer as F
Expand All @@ -9,6 +10,7 @@ import Json.Decode as JD
import Json.Encode as JE
import Keywords as K
import Map as M
import Other as O
import Protobuf exposing (..)
import Recursive as R
import Result
Expand Down Expand Up @@ -185,14 +187,10 @@ emptyJson =
foo : T.Foo
foo =
{ s =
Just
{ int32Field = 11
}
Just <| T.SimpleMessage { int32Field = 11 }
, ss =
[ { int32Field = 111
}
, { int32Field = 222
}
[ T.SimpleMessage { int32Field = 111 }
, T.SimpleMessage { int32Field = 222 }
]
, colour = T.Red
, colours =
Expand All @@ -209,13 +207,9 @@ foo =
, bytesField = []
, stringValueField = Nothing
, otherField =
Just
{ stringField = "xxx"
}
Just <| O.OtherMessage { stringField = "xxx" }
, otherDirField =
Just
{ stringField = "yyy"
}
Just <| OD.OtherDirMessage { stringField = "yyy" }
, timestampField = Nothing
}

Expand Down Expand Up @@ -320,11 +314,12 @@ rec1 : R.Rec
rec1 =
{ int32Field = 0
, r =
R.RecField
{ int32Field = 0
, r = R.RUnspecified
, stringField = ""
}
R.RecField <|
R.RecMessage
{ int32Field = 0
, r = R.RUnspecified
, stringField = ""
}
, stringField = ""
}

Expand All @@ -344,16 +339,18 @@ rec2 : R.Rec
rec2 =
{ int32Field = 0
, r =
R.RecField
{ int32Field = 0
, r =
R.RecField
{ int32Field = 0
, r = R.RUnspecified
, stringField = ""
}
, stringField = ""
}
R.RecField <|
R.RecMessage
{ int32Field = 0
, r =
R.RecField <|
R.RecMessage
{ int32Field = 0
, r = R.RUnspecified
, stringField = ""
}
, stringField = ""
}
, stringField = ""
}

Expand Down Expand Up @@ -478,8 +475,8 @@ wrappersSet =
map : M.MessageWithMaps
map =
{ stringToMessages = Dict.fromList
[ ( "foo" , { field = True } ),
( "bar" , { field = False } )
[ ( "foo" , M.MapValueMessage { field = True } ),
( "bar" , M.MapValueMessage { field = False } )
],
stringToStrings = Dict.fromList
[
Expand Down
Loading