protocol-buffers 2.1.12 → 2.2.0
raw patch · 3 files changed
+102/−2 lines, 3 files
Files
- README.md +87/−0
- Text/ProtocolBuffers/Reflections.hs +14/−1
- protocol-buffers.cabal +1/−1
README.md view
@@ -288,3 +288,90 @@ Everything that is needed is collected into the Options data type which is passed to "run". The output style can be tweaked by changing "style" and "myMode".++New oneof implementation+------------------------++Since `protocol-buffers` version 2.6, the upstream `protocol-buffers`+supports [oneof](https://developers.google.com/protocol-buffers/docs/proto?hl=en#oneof)+keyword, which is a union of different data types.+It is very natural to combine the oneof specification into Haskell+ADT, so we implement the feature.++In `hprotoc/oneoftest`, we have an example for this. `school.proto` defines+a collection of members in a school, which is organized into dormitories. +Each member should have common attributes like `id` and `name`, but there are+attributes only specific to students, faculties or administrators.++Therefore, we define property as a oneof field which is one of student, faculty+and admin type. How it is defined should be easily understood from `school.proto`.++Once `protocol-buffers` is installed, using `hprotoc`, we can generate Haskell+source codes. Assuming we run `hprotoc` on the `oneoftest` directory and generate+source code in `hs` directory: ++```+oneoftest> hprotoc --proto_path=. --haskell_out=hs school.proto+```++We will have `School.Member` module which defines `Member` by+(I omit qualifier and strictness annotation here.)+```+data Member = Member { id :: Int32+ , name :: Utf8+ , property :: Maybe Property+ }+```+and `School.Member.Property` module defines `Property` (as `oneof`) by+```+data Property = Prop_student {prop_student :: Student }+ | Prop_faculty {prop_faculty :: Faculty }+ | Prop_admin {prop_admin :: Admin }+``` +where `Student`, `Faculty` and `Admin` are defined as ordinary nested message+data types in separate modules, respectively. Therefore, the `oneof` feature+is smoothly matched with Haskell sum types. Note that `Maybe` will be always+present for a `oneof` field in the owner data type definition (Here, `Maybe Property`+in the definition of `Member`). This is because of compatibility with other language+implementationn that treats `oneof` as a collection of `optional` fields. ++In the `oneoftest` directory, we provides a Haskell example in `hprotoc/oneoftest/hs`+and a C++ example in `hprotoc/oneoftest/cpp` to demonstrate how to use. Each example+has `encode` and `decode`.With `encode`, we start from data in memory and generate+a serialized binary file in wire format. Then,`decode` takes the file and present+some information to prove it successfully decoded the binary. One can encode from+Haskell side and decode on C++ side, or vice versa. For building, simply run+`build.sh` in each directory. For C++, one must previously install C++ `protobuf`+library and `pkg-config`. We assume that `hprotoc` was already executed as shown above. ++Here are examples.+```+hs > ./encode serialized.dat+hs > cd ../cpp+cpp> ./decode ../hs/serialized.dat+name: "Gryffindor"+members {+ id: 1+ name: "Albus Dumbledore"+ prop_faculty {+ subject: "allmighty"+ title: "headmaster"+ }+}+members {+ id: 2+ name: "Harry Potter"+ prop_student {+ grade: 5+ specialty: "defense of dark arts"+ }+} +```++```+cpp> ./encode serialized.dat+cpp> cd ../hs+hs > ./decode ../cpp/serialized.dat++Right (Dormitory {name = "Gryffindor", members = fromList [Member {id = 1, name = "Albus Dumbledore", property = Just (Prop_faculty {prop_faculty = Faculty {subject = "allmighty", title = Just "headmaster", duty = fromList []}})},Member {id = 2, name = "Harry Potter", property = Just (Prop_student {prop_student = Student {grade = 5, specialty = Just "defense of dark arts"}})}]},"")+```
Text/ProtocolBuffers/Reflections.hs view
@@ -15,6 +15,7 @@ ( ProtoName(..),ProtoFName(..),ProtoInfo(..),DescriptorInfo(..),FieldInfo(..),KeyInfo , HsDefault(..),SomeRealFloat(..),EnumInfo(..),EnumInfoApp , ReflectDescriptor(..),ReflectEnum(..),GetMessageInfo(..)+ , OneofInfo(..) , makePNF, toRF, fromRF ) where @@ -65,6 +66,7 @@ , extensionKeys :: Seq KeyInfo -- ^ top level keys , messages :: [DescriptorInfo] -- ^ all messages and groups , enums :: [EnumInfo] -- ^ all enums+ , oneofs :: [OneofInfo] , knownKeyMap :: Map ProtoName (Seq FieldInfo) -- all keys in namespace } deriving (Show,Read,Eq,Ord,Data,Typeable)@@ -72,7 +74,8 @@ data DescriptorInfo = DescriptorInfo { descName :: ProtoName , descFilePath :: [FilePath] , isGroup :: Bool- , fields :: Seq FieldInfo + , fields :: Seq FieldInfo+ , descOneofs :: Seq OneofInfo , keys :: Seq KeyInfo , extRanges :: [(FieldId,FieldId)] , knownKeys :: Seq FieldInfo@@ -82,6 +85,7 @@ } deriving (Show,Read,Eq,Ord,Data,Typeable) + -- | 'GetMessageInfo' is used in getting messages from the wire. It -- supplies the 'Set' of precomposed wire tags that must be found in -- the message as well as a 'Set' of all allowed tags (including known@@ -145,6 +149,14 @@ | isInfinite x = if 0 < x then SRF'inf else SRF'ninf | otherwise = SRF'Rational (toRational x) +data OneofInfo = OneofInfo { oneofName :: ProtoName+ , oneofFName :: ProtoFName + , oneofFilePath :: [FilePath]+ , oneofFields :: Seq (ProtoName,FieldInfo)+ , oneofMakeLenses :: Bool+ }+ deriving (Show,Read,Eq,Ord,Data,Typeable)+ data EnumInfo = EnumInfo { enumName :: ProtoName , enumFilePath :: [FilePath] , enumValues :: [(EnumCode,String)] -- ^ The String is the Haskell name to write into the generated source files@@ -152,6 +164,7 @@ deriving (Show,Read,Eq,Ord,Data,Typeable) type EnumInfoApp e = [(EnumCode,String,e)]+ class ReflectEnum e where reflectEnum :: EnumInfoApp e
protocol-buffers.cabal view
@@ -1,5 +1,5 @@ name: protocol-buffers-version: 2.1.12+version: 2.2.0 cabal-version: >= 1.6 build-type: Simple license: BSD3