The Extensions module contributes two main things. The first
is the definition and implementation of extensible message
features. This means that the
ExtField data type is exported but
its constructor is (in an ideal world) hidden.
This first part also includes the keys for the extension fields:
Key data type. These are typically defined in code generated
hprotoc from '.proto' file definitions.
Access to extension fields is strictly though keys. There is not currently any way to query or change or clear any other extension field data.
This module is likely to get broken up into pieces.
- getKeyFieldId :: Key c msg v -> FieldId
- getKeyFieldType :: Key c msg v -> FieldType
- getKeyDefaultValue :: Key c msg v -> v
- data Key c msg v where
- class ExtKey c where
- class MessageAPI msg a b | msg a -> b where
- wireSizeExtField :: ExtField -> WireSize
- wirePutExtField :: ExtField -> Put
- loadExtension :: (ReflectDescriptor a, ExtendMessage a) => FieldId -> WireType -> a -> Get a
- notExtension :: (ReflectDescriptor a, ExtendMessage a, Typeable a) => FieldId -> WireType -> a -> Get a
- class (Mergeable a, Default a, Wire a, Show a, Typeable a, Eq a, Ord a) => GPB a
- newtype ExtField = ExtField (Map FieldId ExtFieldValue)
- class Typeable msg => ExtendMessage msg where
- data ExtFieldValue
Query functions for
This allows reflection, in this case it gives the numerical
FieldId of the key, from 1 to 2^29-1 (excluding 19,000 through
External types and classes
Key data type is used with the
ExtKey class to put, get,
and clear external fields of messages. The
Key can also be used
MessagesAPI to get a possibly default value and to check
whether a key has been set in a message.
Key type (opaque to the user) has a phantom type of Maybe
or Seq that corresponds to Optional or Repeated fields. And a
second phantom type that matches the message type it must be used
with. The third type parameter corresonds to the Haskell value
When code is generated all of the known keys are taken into account in the deserialization from the wire. Unknown extension fields are read as a collection of raw byte sequences. If a key is then presented it will be used to parse the bytes.
There is no guarantee for what happens if two Keys disagree about
the type of a field; in particular there may be undefined values
and runtime errors. The data constructor for
Key has to be
exported to the generated code, but is not exposed to the user by
Change or clear the value of a key in a message. Passing
Nothing with an optional key or an empty
Seq with a repeated
key clears the value. This function thus maintains the invariant
that having a field number in the
ExtField map means that the
field is set and not empty.
This should be only way to set the contents of a extension field.
Access the key in the message. Optional have type
msg v) and return type
(Maybe v) while repeated fields have
(Key Seq msg v) and return type
There are a few sources of errors with the lookup of the key:
- It may find unparsed bytes from loading the message.
getExtwill attempt to parse the bytes as the key's value type, and may fail. The parsing is done with the
parseWireExtmethod (which is not exported to user API).
- The wrong optional-key versus repeated-key type is a failure
- The wrong type of the value might be found in the map and * cause a failure
The failures above should only happen if two different keys are used with the same field number.
Access data in a message. The first argument is always the message. The second argument can be one of 4 categories.
- The field name of a required field acts a simple retrieval of the data from the message.
- The field name of an optional field will retreive the data if it is set or lookup the default value if it is not set.
- The field name of a repeated field always retrieves the
- A Key for an optional or repeated value will act as the field name does above, but if there is a type mismatch or parse error it will use the defaultValue for optional types and an empty sequence for repeated types.
Check whether data is present in the message.
- Required fields always return
- Optional fields return whether a value is present.
- Repeated field return
Falseif there are no values, otherwise they return
- Keys return as optional or repeated, but checks only if the field # is present. This assumes that there are no collisions where more that one key refers to the same field number of this message type.
|MessageAPI msg (msg -> Word64) Word64|
|MessageAPI msg (msg -> Word32) Word32|
|MessageAPI msg (msg -> Int64) Int64|
|MessageAPI msg (msg -> Int32) Int32|
|MessageAPI msg (msg -> Float) Float|
|MessageAPI msg (msg -> Double) Double|
|MessageAPI msg (msg -> Utf8) Utf8|
|MessageAPI msg (msg -> ByteString) ByteString|
|(Default msg, Default a) => MessageAPI msg (msg -> Maybe a) a|
|MessageAPI msg (msg -> Seq a) (Seq a)|
|Default v => MessageAPI msg (Key Maybe msg v) v|
|Default v => MessageAPI msg (Key Seq msg v) (Seq v)|
Internal types, functions, and classes
This is used by the generated code. The data is serialized in order of increasing field number.
get a value from the wire into the message's ExtField. This is
ExtField is a newtype'd map from the numeric FieldId key to the ExtFieldValue. This allows for the needed class instances.
This only used internally.
The WireType is used to ensure the Seq is homogenous. The ByteString is the unparsed input after the tag. The WireSize includes all tags.
|ExtFromWire !WireType !(Seq ByteString)|
|ExtOptional !FieldType !GPDyn|
|ExtRepeated !FieldType !GPDynSeq|