git.iko.soy/rowtype-yoga/purescript-protobuf
on master help sign in
WIP v2
commit82a3f034f7b7ba86c93be23082e41d62452a8fd1 authorJames Brock <jamesbrock@gmail.com> dateSun 4 Apr 2021, 02:18 (6 years ago) parentb05ba41
3 files changed+66−2
CHANGELOG.md+26 src/Protobuf/Common.purs+38−1 src/ProtocPlugin/Main.purs+2−1
CHANGELOG.md+26
@@ -1,3 +1,29 @@
1+# v2.0.0
2+
3+For __purescript-protobuf__ version 2, we’re trying to strictly conform
4+to Protocol Buffers version 3.11.4?
5+To that end, we're no longer using `Maybe` for field values, and instead we’re
6+using the Protobuf
7+[default values](https://developers.google.com/protocol-buffers/docs/proto3#default).
8+
9+There is a new type class `Default`. In version 1, all message fields were
10+`Maybe`s. In version 2, no message fields are `Maybe`s, and all message fields
11+have a `Default` instance.
12+
13+So this is a pretty big breaking change, but it brings our implementation into
14+closer agreement with what Google has designed Protobuf to be (optimized for C++
15+structs), rather than what we wish it were (optimized for a language with sum types.)
16+
17+In version 1, we had to be mindful that sometimes when we received a field
18+value of `Nothing` it actually meant *0*. In version 2, we have to be mindful
19+that sometimes when we receive a field value of *0* it actually means `Nothing`.
20+We have introduced a `fromDefault` function to help us remember.
21+
22+We’re still ignoring the `REQUIRED`/`OPTIONAL` distinction, even though it
23+appears that Jeff Dean has caved and
24+[allowed it back in](https://chromium.googlesource.com/external/github.com/protocolbuffers/protobuf/+/refs/heads/master/docs/implementing_proto3_presence.md) in the form of
25+“synthetic oneofs.”
26+
127Elide default values when encoding optional fields.
228
329
src/Protobuf/Common.purs+38−1
@@ -4,6 +4,10 @@ module Protobuf.Common
44( FieldNumber
55, WireType(..)
66, Bytes(..)
7+, class Default
8+, default
9+, fromDefault
10+, toDefault
711)
812where
913
@@ -13,11 +17,15 @@ import Data.ArrayBuffer.ArrayBuffer as AB
1317import Data.ArrayBuffer.Typed as TA
1418import Data.ArrayBuffer.Types (ArrayBuffer, Uint8Array)
1519import Data.Enum (class Enum, fromEnum, class BoundedEnum, Cardinality(..))
20+import Data.Float32 (Float32)
21+import Data.Float32 as Float32
1622import Data.Generic.Rep (class Generic)
1723import Data.Generic.Rep.Show (genericShow)
24+import Data.Long.Internal (Long, Signed, Unsigned, fromLowHighBits)
1825import Data.Maybe (Maybe(..))
1926import Data.Newtype (class Newtype)
2027import Data.UInt (UInt)
28+import Data.UInt as UInt
2129import Effect (Effect)
2230import Effect.Unsafe (unsafePerformEffect)
2331
@@ -84,4 +92,33 @@ instance eqBytes :: Eq Bytes
8492 r' <- TA.whole r :: Effect Uint8Array
8593 TA.eq l' r'
8694
87−derive instance newtypeBytes :: Newtype Bytes _
95+derive instance newtypeBytes :: Newtype Bytes _
96+
97+-- | Default values
98+-- |
99+-- | https://developers.google.com/protocol-buffers/docs/proto3#default
100+class Default a
101+ where
102+ default :: a
103+
104+instance defaultString :: Default String where default = ""
105+instance defaultInt :: Default Int where default = 0
106+instance defaultNumber :: Default Number where default = 0.0
107+instance defaultLongSigned :: Default (Long Signed) where default = fromLowHighBits 0 0
108+instance defaultLongUnsigned :: Default (Long Unsigned) where default = fromLowHighBits 0 0
109+instance defaultFloat32 :: Default Float32 where default = Float32.fromNumber' 0.0
110+instance defaultBoolean :: Default Boolean where default = false
111+instance defaultUInt :: Default UInt where default = UInt.fromInt 0
112+instance defaultArray :: Default a => Default (Array a) where default = []
113+instance defaultBytes :: Default Bytes where default = Bytes $ unsafePerformEffect $ AB.empty 0
114+
115+-- Maybe we want to rip off? https://pursuit.purescript.org/packages/purescript-data-default/0.3.2/docs/Data.Default#t:GDefault
116+
117+-- | Turns a `default` value into `Nothing`. Sometimes convenient for decoding.
118+fromDefault :: forall a. Default a => Eq a => a -> Maybe a
119+fromDefault x = if x==default then Nothing else Just x
120+
121+-- | Turns `Nothing` into a `default` value. Sometimes convenient for encoding.
122+toDefault :: forall a. Default a => Maybe a -> a
123+toDefault Nothing = default
124+toDefault (Just x) = x
src/ProtocPlugin/Main.purs+2−1
@@ -359,7 +359,8 @@ genFile proto_file (FileDescriptorProto
359359 -- https://developers.google.com/protocol-buffers/docs/reference/cpp-generated#message
360360 -- For now we just say `(const false)`, the message is never default.
361361 go _ FieldDescriptorProto_Type_TYPE_MESSAGE (Just tname) =
362− Right $ Just $ " Runtime.putOptional " <> show fnumber <> " r." <> fname <> " (const false) $ Runtime.putLenDel " <> mkFieldType "put" tname
362+ -- Right $ Just $ " Runtime.putOptional " <> show fnumber <> " r." <> fname <> " (const false) $ Runtime.putLenDel " <> mkFieldType "put" tname
363+ Right $ Just $ " Runtime.putOptional " <> show fnumber <> " r." <> fname <> " (_==(Newtype.wrap " <> mkFieldType "default" tname <> ")) $ Runtime.putLenDel " <> mkFieldType "put" tname
363364 go _ FieldDescriptorProto_Type_TYPE_MESSAGE _ =
364365 Left "Failed genFieldPut missing FieldDescriptorProto type_name"
365366 go FieldDescriptorProto_Label_LABEL_REPEATED FieldDescriptorProto_Type_TYPE_BYTES _ =