Cedarbridge Language Specification 1.2.0
The specification makes reference to the
Unicode
character set which, at the time of writing, is at version 13.0.0. The specification
often references specific
Unicode characters, and does so using the standard notation
U+NNNN, where
N
represents a hexadecimal digit. For example,
U+03BB
corresponds to the lowercase lambda symbol
λ.
The specification gives grammar definitions in
ISO/IEC 14977:1996
Extended Backus-Naur form.
Because EBNF was designed prior to the existence of Unicode, it is necessary to extend
the syntax to be able to
refer to Unicode characters in grammar definitions. This specification makes use of
the standard unicode
U+NNNN
syntax in grammar definitions, to refer to specific Unicode characters. It also makes
use of the syntax
\p{t}
which should be understood to represent any Unicode character with the property
t. For example,
\p{Lowercase_Letter}
describes the set of characters that are both letters and are lowercase. The syntax
\P{t}
should be understood as the negation of \p{t}; it describes the set of characters
without the property t.
The Cedarbridge language uses s-expressions as the base for
all syntax. An s-expression is described by the following EBNF grammar:
As shown, the Cedarbridge language uses an extension of basic s-expressions that allow
for the optional use of either square brackets or parentheses to increase the readability
of large nested
expressions. These should be treated as interchangeable, but must be correctly balanced
as shown by the grammar.
For example, the expression [] is semantically equivalent to
(), but the expression [) is invalid.
Declarative type rules describe the precise rules for assigning types to terms. If
no type rule matches a term,
then that term is considered ill-typed.
Type rules are given as zero or more premises, and a single
conclusion, separated by a horizontal line. For a given rule, when all of the premises
are true, then the conclusion is true. If a rule has no premises then the rule is
taken as an
axiom.
The gamma symbol Γ (U+0393) represents the current typing environment and can be
thought of as a mapping from distinct variables to their types, with the set of variables
in environment denoted
by dom(Γ) (the domain of Γ). The notation Γ ⊢ P reads
"Γ implies P" and is used in type rules to assign types to terms. The empty typing
environment is represented by ∅
(U+2205). The diamond symbol ◇ (U+25C7) should be read as "is well-formed", so
Γ ⊢ ◇
should be read as "the current typing environment is well-formed". The concept of
well-formedness is often
type-system-specific and is usually described when the rules are given.
The
Cedarbridge language is designed to describe
schemas
that describe
message-based protocols. Schemas consist of a set of
packages, each containing
types and
protocols.
Type declarations
express the structure of values exchanged in message protocols, and
protocol declarations
express which types are present in each defined version of a protocol.
This version of the specification describes the
Cedarbridge language
version
1.0. This version of the language can be requested explicitly
by schema authors by using the
language statement.
The text of a Cedarbridge schema is a combination of the texts of separate
compilation units, where a compilation unit typically
corresponds to a file in the operating system under
which the compiler is running.
Compilation units consist of a series of
s-expressions separated by whitespace.
This specification makes references to a
schema context. The
schema context can be thought of as the current state of the schema being constructed
during the execution of the language compiler. For example, the
package statement modifies the
schema context by introducing a new package name and setting the
new package as the
current package to which all subsequent statements will apply.
A statement in the Cedarbridge language can be seen as an
instruction that performs some action on the current schema context (such as
introducing a new type, introducing a new package, importing a package into the current
scope, etc), yielding
a new context that may be changed in some manner.
A package is the top level organizational unit for schema objects. A package has a
unique fully-qualified name of the form:
An example of a valid package name is com.io7m.cedarbridge.
A type in the Cedarbridge language is a basic description of
the structure of a value. A type has a unique name within a package, and the format
of valid type names is as follows:
A
protocol in the
Cedarbridge language is a set of
versions, each of which contains a set of
types. A type can be present in any number of protocols
and protocol versions concurrently. A protocol has a unique name within a package,
and the format of valid
protocol names matches that of types.
The Cedarbridge language uses the U+003B SEMICOLON
character to denote line comments. When encountered outside of a quoted string, any
text between the
; character and the next end-of-line character is ignored.
language
- Declare the language that will be used.
The language statement declares which language will be used for the subsequent
statements in the compilation unit.
A language statement, if present, MUST be the first
statement in a compilation unit.
The language statement can appear at most once in a compilation unit.
If a language statement names an unrecognized language, parsing of the
compilation unit MUST be aborted, and all subsequent statements in the compilation
unit ignored.
If a language statement names an unrecognized language major version, parsing of the
compilation unit MUST be aborted, and all subsequent statements in the compilation
unit ignored.
If a language statement names an unrecognized language minor version, parsing of the
compilation unit MAY produce a warning, but compilation of the unit must continue as if
known minor version had been specified .
The following statement declares that the compilation unit is written in Cedarbridge
1.0:
package
- Begin the declaration of a
package.
The package statement begins the declaration of a package.
A package statement that names a package
p
sets the current package of the schema context to p. There
can be at most one current package in the schema context at any given time.
If the package statement is evaluated when the schema context already has a
current package, the statement is rejected with an error.
If the package statement is evaluated with package name
r, where r is already defined within the schema context, the statement is
rejected with an error.
The package named by a
package statement is
defined
iff the compilation of all subsequent statements in the compilation unit succeeds.
Once a package is
defined, it becomes accessible to other packages via the use of
import statements. At the end of the compilation
unit, the
current package of the schema context becomes unset.
The following statement begins the declaration of a package named
com.io7m.cedarbridge:
The import statement imports a package for use in the current package.
An import statement (import p q)
makes the type declarations in package p visible via qualification using
the short name q. For example, if a type
T was declared in p, it can be used in a type
declaration in the current package by referring to the type as q:T. Formally,
a package s imports a package
t if s contains an
(import t x) statement, for any x.
It is an error for two import statements to use the same
short name.
It is an error for any package to import itself directly or indirectly. That is, the
graph of packages
produced by packages importing other packages must be free of cycles. More formally,
it is an error for
any of the following conditions to be true:
An
import statement, if present,
MUST occur with
a package set in the current
schema context.
In practical terms, this means that
import statements
MUST appear
after the
package statement
in a given compilation unit.
The following statement imports a package named
com.io7m.cedarbridge and makes it accessible as cb:
record
- Declare a record type
The record statement declares a new record type.
A
record statement, if present,
MUST occur with
a package set in the current
schema context.
In practical terms, this means that
record statements
MUST appear
after the
package statement
in a given compilation unit.
A record statement is a type declaration.
The statement (record T ...) introduces a new type name
T
within the current package in the schema context. Type names are unique within a package;
it is an error for
two or more type declarations to name the same type.
The names of fields declared using field declarations within
a record statement are unique within that record type. It is an error for two
or more fields within a record to have the same name.
The declaration order of fields within a record type is significant; changing the
order of field declarations will change the semantics and serialized form of
values of the record type.
The names of type parameters declared using parameter
declarations within a record statement are unique within that record
type. It is an error for two or more type parameters within a record to have the same
name.
The declaration order of type parameters with respect to other
type parameters within a record type is significant; changing
the order of parameter declarations will change the semantics
and serialized form of values of the record type. The declaration order of
type parameters with respect to field declarations
is not significant.
The precise type rules for record type declarations are described in the
typing rules section for type expressions.
The following statement declares a parameterized Pair type
with two fields:
variant
- Declare a variant type
The variant statement declares a new variant type.
A
variant statement, if present,
MUST occur with
a package set in the current
schema context.
In practical terms, this means that
variant statements
MUST appear
after the
package statement
in a given compilation unit.
A variant statement is a type declaration.
The statement (variant T ...) introduces a new type name
T
within the current package in the schema context. Type names are unique within a package;
it is an error for
two or more type declarations to name the same type.
The names of cases declared using case declarations within
a variant statement are unique within that variant type. It is an error for two
or more cases within a variant to have the same name.
The declaration order of cases within a variant type is significant; changing the
order of case declarations will change the semantics and serialized form of
values of the variant type.
The names of type parameters declared using parameter
declarations within a variant statement are unique within that variant
type. It is an error for two or more type parameters within a variant to have the same
name.
The declaration order of type parameters with respect to other
type parameters within a variant type is significant; changing
the order of parameter declarations will change the semantics
and serialized form of values of the variant type. The declaration order of
type parameters with respect to case declarations
is not significant.
The precise type rules for variant type declarations are described in the
typing rules section for type expressions.
For a given field
(field x t) within a
case
declaration, the
type expression t must have kind
*.
The following statement declares a parameterized Option type:
The following type declarations are equivalent:
protocol
- Declare a protocol
The protocol statement declares a new protocol.
A
protocol statement, if present,
MUST occur with
a package set in the current
schema context.
In practical terms, this means that
protocol statements
MUST appear
after the
package statement
in a given compilation unit.
The statement (protocol T ...) introduces a new protocol
name T within the current package in the schema context. Protocol names
are unique within a package; it is an error for two or more protocol declarations to
name the same protocol.
A protocol statement declares a contiguous ordered set of
versions, with each
version naming a set of
types
that are included within that version by nature of being added to or removed from
the previous version.
Accordingly, the intersections of the sets of types between versions are allowed to
be non-empty. That is, for versions
v and
w,
if
P(v) is the set of types in version
v and
P(w) is the set of types in version
w, then
it is not an error if
P(v) ∩ P(w) ≠ ∅.
A (types-added ...) declaration adds a set of types to a protocol version
relative to the previous version.
A (types-removed ...) declaration removes a set of types from a protocol version
relative to the previous version.
A (types-removed-all) declaration is a convenient declaration that removes
all types from a protocol version. It is equivalent to a (types-removed ...)
declaration where the declaration names all the types that are present in the previous
version.
Each type named in each protocol version must have kind *.
For each protocol version vc, additions and removals are processed as follows:
Let tp be the set of types present in the version vp
that is the version immediately previous to vc. If vc
is the first version in the protocol, tp = ∅. All the types in all of the
(types-added ...) declarations in vc are
collected into the addition set ta.
All the types in all of the
(types-removed ...) declarations in vc are
collected into the removal set tr.
If a (types-removed-all) declaration is
present, then tr = tp.
Then, for each type r in tr,
r is removed from
tp.
Then, for each type
a in ta,
a is added to tp. tp
is now considered to be the set of types present in vc.
It is an error if the set of types in a version is empty after all additions and removals
have been
processed.
It is an error if a type named by a (types-removed ...) declaration
is not present in the protocol version prior to additions and removals being processed.
That is, it is not
valid to attempt to remove a type from a protocol version when that type is not present
in the protocol
version in the first place.
It is an error if a type named by a (types-added ...) declaration
is already present in the protocol version prior to additions and removals being processed.
That is, it is not
valid to attempt to redundantly add a type to a protocol version when that type is
already present in the protocol
version.
The declaration order of type additions and removals within a
version is
NOT significant; changing the order of version declarations will not change the
semantics or serialized form of the protocol as the declarations MUST be reordered
by the compiler into ascending lexicographical order of the type names.
The first version in a protocol cannot have any
(types-removed ...) declarations.
The declaration order of versions within a protocol is
NOT significant; changing the order of version declarations will not change the
semantics or serialized form of the protocol as the declarations MUST be reordered
by the compiler into ascending order by their declared version number.
The following statements declare a simple Echo protocol with two versions:
The first version consists of types { Hello, Speak, Goodbye } whilst the
second version consists of types { Hello2, Speak, Goodbye }.
documentation - Add documentation to an element
The documentation statement specifies a paragraph of documentation for an element.
A documentation statement (documentation T s)
adds the documentation string s to the object T.
The documentation statement may appear:
Documentation statements may refer to objects that are yet to be defined.
For example, it is possible to specify documentation for a record field before that
record field is defined.
However, it is an error to refer to objects that are never defined. Implementations
are encouraged to perform
binding analyses of documentation statements in a separate pass after the definitions
of other objects are
checked.
The following statement adds documentation to a Color record type:
A type expression yields a type when
evaluated.
A
type expression is an expression that, when
evaluated,
yields a
type. The evaluation of type expressions, ultimately, terminates in the
evaluation of a
type constructor that can take zero or more type parameters.
record and
variant statements declare new
type constructors.
Evaluation of type expressions implicitly occurs as part of
type-checking during compilation.
Types are categorized by kind; a type constructor that takes
no parameters has kind *. A type constructor that takes one parameter has
kind * → *. Applying a type constructor to arguments conceptually reduces
the kind: A type constructor with kind * → * -> * -> * applied to three
arguments has kind *.
The partial application of type constructors is not supported: It is an error
if the number of arguments supplied to a type constructor does not match the number
of declared parameters
for the type constructor.
The initial, empty type environment is well-formed, and adding a type to the environment
that does not already
exist results in a well-formed type environment.
A
record
T declared with
n
type parameters and any number of fields has kind
*₀ → ... → *ₙ
and introduces
T into the environment:
A
variant T
declared with
n type parameters any number of cases has kind
*₀ → ... → *ₙ and introduces
T into the environment:
The application of a type constructor f that takes n-1
parameters to n-1 type expressions (each of kind *)
is well-formed:
The list of provided arguments must be non-empty.
The
Cedarbridge language defines a set of standard
packages that all implementations of the
language are required to provide.
The com.io7m.cedarbridge package declares a set of generally useful types.
The Boolean type holds simple true or false values.
The IntegerUnsigned8 type is an opaque type that can hold values in the range
[0, 255].
The IntegerUnsigned16 type is an opaque type that can hold values in the range
[0, 65535].
The IntegerUnsigned32 type is an opaque type that can hold values in the range
[0, 4294967295].
The IntegerUnsigned64 type is an opaque type that can hold values in the range
[0, 18446744073709551615].
The IntegerSigned8 type is an opaque type that can hold values in the range
[-128, 127].
The IntegerSigned16 type is an opaque type that can hold values in the range
[-32768, 32767].
The IntegerSigned32 type is an opaque type that can hold values in the range
[-2147483648, 2147483647].
The IntegerSigned64 type is an opaque type that can hold values in the range
[-9223372036854775808, 9223372036854775807].
The String type is an opaque type that can hold a sequence of at most
4294967295 octets of UTF-8 encoded data.
The ByteArray type is an opaque type that can hold a sequence of at most
4294967295 octets of data.
The Float16 type is an opaque type that can hold a single
IEEE-754 Binary16 value.
The Float32 type is an opaque type that can hold a single
IEEE-754 Binary32 value.
The Float64 type is an opaque type that can hold a single
IEEE-754 Binary64 value.
The List type is an opaque type that can hold a sequence
of values of a type equal to the single type parameter.
The Option type is a type that can hold zero or one values
of a type equal to the single type parameter. The type is equivalent to the following
variant declaration:
The
MapEntry type is a type used to hold a single entry in
a
Map. The type is equivalent to the following
record declaration:
The
Map type is a type used to hold a sequence of
entries. The type is equivalent to the following
record declaration:
The
UUID type represents an
RFC 4122
universally unique identifier value. The type is equivalent to the following
record declaration:
The 64 most significant bits are held in the msb field, and the
64 least significant bits are held in the lsb field.
The
URI type represents an
RFC 3986
URI value. The type is equivalent to the following record declaration:
The value field holds the UTF-8 encoded string representation of the URI.
The com.io7m.cedarbridge.time package declares a set of types related to times
and dates.
The Duration type holds a quantity of time in terms of seconds and nanoseconds.
The seconds field holds the number of seconds in the duration.
The nanoseconds field holds the number of nanoseconds in the duration. This
value is added to the seconds field to produce the full duration. The value
of the nanoseconds field may only be in the range
[0, 999999999].
The LocalDate type represents a date in an unspecified time zone.
The year field holds the year.
The month field holds the month of the year in the range
[1, 12].
The day field holds the day of the month in the range
[1, 31].
Not all combinations of month field and
day field values are guaranteed to produce valid dates. Implementations
are expected to validate dates after deserialization.
The LocalTime type represents a time in an unspecified time zone.
The hour field holds the hour in the range
[0, 23].
The minute field holds the minute in the range
[0, 59].
The second field holds the second in the range
[0, 59].
The nanos field holds the nanosecond in the range
[0, 999999999].
The LocalDateTime type represents a date and time in an unspecified time zone.
The ZoneOffset type represents a timezone offset.
The seconds field holds the offset in the range
[-64800, 64800].
The OffsetDateTime type represents a date and time in a specific time zone.
The Cedarbridge language is defined without reference to any particular set of rules
for actually encoding values of the various user-defined types for transmission. This
specification
section defines a canonical format for binary encoding,
CCBE, that all implementations are expected to be able to understand.
The CCBE is defined as following:
A byte is an eight-bit quantity with the individual bits written to the
transmission medium in
decreasing order of significance. That is, the most signficant bit
is written to the output first, and the least signficant bit is
written last. When the individual bits of an N-bit value
are enumerated, it is to be understood that the most signficant bit is numbered
0 and the least signficant bit is numbered
N-1. A byte can therefore be described as the following
product type:
For the purposes of specification, we assume the existence of a function
bit(n, x) : ℕ → α → 𝔹
that, given an arbitrary input value x of type α,
returns the value of bit n of the input value according to the above ordering and
bit numbering rules. This is merely a notational aid and should be understood to be
something that implementations
are actually required to implement.
A
byte sequence is, unsuprisingly, a sequence of
bytes. The notation
[]
denotes a sequence of length
0, and the operator
⊕
prepends a byte to a
byte sequence. The operator
⊕ is
right-associative, so
∀x y z. x ⊕ y ⊕ z = x ⊕ (y ⊕ z).
The kind CCBE denotes the disjoint set of types present in the
encoding rules. The definition is as follows:
For each of the types in CCBE, we describe a function
encode(x) : (τ : CCBE) → (α : τ) → ByteSequence (where
τ is an implicit parameter that can be inferred
from α). The purpose of the encode
function is to describe how to transform a value of a given type to a byte sequence
that can
be written to the destination transmission medium.
The S8 type is an opaque type that can hold a value in the range
[-128, 127].
Values of type S8 are encoded as follows:
The S16 type is an opaque type that can hold a value in the range
[-32768, 32767].
Values of type S16 are encoded as follows:
The S32 type is an opaque type that can hold a value in the range
[-2147483648, 2147483647].
Values of type S32 are encoded as follows:
The S64 type is an opaque type that can hold a value in the range
[-9223372036854775808, 9223372036854775807].
Values of type S64 are encoded as follows:
The U8 type is an opaque type that can hold a value in the range
[0, 255].
Values of type U8 are encoded as follows:
The U16 type is an opaque type that can hold a value in the range
[0, 65535].
Values of type U16 are encoded as follows:
The U32 type is an opaque type that can hold a value in the range
[0, 4294967295].
Values of type U32 are encoded as follows:
The U64 type is an opaque type that can hold a value in the range
[0, 18446744073709551615].
Values of type U64 are encoded as follows:
The F16 type is an opaque type that can hold a value in the value
set of the IEEE 754 binary16 type.
Values of type F16 are encoded as follows:
The F32 type is an opaque type that can hold a value in the value
set of the IEEE 754 binary32 type.
Values of type F32 are encoded as follows:
The F64 type is an opaque type that can hold a value in the value
set of the IEEE 754 binary64 type.
Values of type F64 are encoded as follows:
The ByteArray type is an opaque sequence of bytes. A value
b of type ByteArray has a fixed length
n denoted length(b) : ℕ = n. The property
∀x. 0 ≤ length(x) ≤ 4294967295 always holds.
The byte at position m (where 0 ≤ m < n)
is denoted byte(m, b) : Byte.
Values of type
ByteArray are encoded as follows: For a value
x, a byte sequence
k ⊕ p ⊕ [] is constructed,
where
k is the result of encoding
length(x)
as if it were a value of type
U32, and
p is simply
byte(m, x) for all
m | 0 ≤ m < length(x).
The List type is parameterized type describing a sequence of values. A value
x of type List α has a fixed length
n denoted length(x) : ℕ = n. The property
∀x. 0 ≤ length(x) ≤ 4294967295 always holds.
The value at position m (where 0 ≤ m < n)
is denoted value(m, x) : α.
Values of type
List are encoded as follows: For a value
x, a byte sequence
k ⊕ p ⊕ [] is constructed,
where
k is the result of encoding
length(x)
as if it were a value of type
U32, and
p is the byte sequence obtained by concatenating the
results of encoding
value(m, x) for all
m | 0 ≤ m < length(x).
The
Cedarbridge String
type is encoded as if it were a
ByteArray after
having first converted the sequence of characters to a sequence of
UTF-8 encoded bytes.
A value of a
record type
r is encoded by concatenating the byte sequences produced by encoding
the
fields of
r in the order that the fields
were declared in the type of
r.
A value of a
variant type
r is encoded by first determining the
variant index
v of
r. The
variant
index is the number of the
case that was used
to construct
r, assuming that cases are numbered in declaration order starting
at
0. For the case
c that was used to
construct
r, the byte sequence produced for
r
is
k ⊕ p ⊕ [], where
k is the result of encoding
v as if it were a value of type
U32, and
p
is the concatenation of the byte sequences produced by encoding the fields of
r in the order that the fields
were declared in the declaration of
c.
Conceptually, each
type present in
a protocol version is added to one effectively anonymous variant type per version.
The cases of
the variant are ordered lexicographically by the names of the types. This anonymous
variant type
is then encoded exactly as regular
variant types
are normally encoded.
For example, assuming the following definitions:
When a message M is encoded in versioned form, we use
the notation V(M) to refer to the versioned nature of
the message.
In protocol version 1, the expression
V(A 23) : A is encoded as the byte sequence
0x00 0x00 0x00 0x00 0x17. That is, the first
four bytes specify the type at case 0 of the
anonymous variant implicitly defined by the [version 1 ...]
declaration, followed by the encoded form of (A 23) : A.
In protocol version 2, the expression
V(C1 23) : C is encoded as the byte sequence
0x00 0x00 0x00 0x02 0x00 0x00 0x00 0x01 0x17. That is, the first
four bytes specify the type at case 2 of the
anonymous variant implicitly defined by the [version 2 ...]
declaration, followed by the encoded form of (C1 23) : C.
In protocol version 3, the expression
P (B 23) : B is encoded as the byte sequence
0x00 0x00 0x00 0x00 0x17. That is, the first
four bytes specify the type at case 0 of the
anonymous variant implicitly defined by the [version 3 ...]
declaration. Because the type A was removed in version 3,
B is now the type at case 0,
whereas it was previously the type at case 1 in versions 1
and 2.
The expression (Some 23) : [Option IntegerUnsigned32] is encoded
as the byte sequence 0x00 0x00 0x00 0x01 0x00 0x00 0x00 0x17. This encoding
comes from the fact that Option is a variant type,
Some is case number 1, and the value
of the one and only field of Some is 23 (0x17).
The expression None : [Option IntegerUnsigned32] is encoded
as the byte sequence 0x00 0x00 0x00 0x00. This encoding
comes from the fact that Option is a variant type,
None is case number 0, and there
are no fields in the case.
Assuming the following type:
The expression [Vector3f 17.0 199.0 1.00781238] is encoded as the byte
sequence 0x41 0x88 0x00 0x00 0x43 0x47 0x00 0x00 0x3f 0x80 0xff 0xff. This
is simply three IEEE 754 binary32 values.
The string "hello" is encoded as the byte sequence
0x00 0x00 0x00 0x05 0x68 0x65 0x6c 0x6c 0x6f. This is the number of UTF-8
encoded bytes (5) followed by the UTF-8 encoded bytes of the string.
The expression [List 17038 27297 17288] : List IntegerSigned16 is encoded
as the byte sequence 0x00 0x00 0x00 0x03 0x42 0x8e 0x6a 0xa1 0x43 0x88. This
is the length of the list (3) followed by the encoded forms of
17038 (0x428e), 27297 (0x6aa1),
and 17288 (0x4388), respectively.
This specification section defines a simple protocol for performing version negotiation
for application protocols.
The protocol assumes a configuration analogous to a
client and
server. That is, one party (the
client) initiates a connection
to the other party (the
server). The two parties can then communicate over the
created two-way connection. A server and client communicating over the open internet
using TCP would satisfy
this configuration. Alternatively, two microcontrollers communicating over
UART
could also be made to satisfy this configuration. For the purposes of keeping the
specification straightforward,
the initiator of the connection will be referred to as the
client, and the
other party will be referred to as the
server.
The dialogue between a client c and server s is as follows:
The messages described here are expected to be encoded to binary using
CCBE. However, certain exceptions have been made
in order to keep each message type at a fixed size. Protocols such as this container
protocol constitute
a
bootstrapping problem in
that, if all of the messages were defined in
Cedarbridge,
the two communicating parties would have to speak
Cedarbridge in order to ask each
other if they can both speak
Cedarbridge. We instead use the
Cedarbridge language to document the basic structure of the messages, but assume
that the protocol messages will be manually read, written, and parsed without necessarily
using
Cedarbridge compiler generated code. For this reason, the protocol does
not use
Cedarbridge's versioning facilities.
The value of the code field MUST be exactly
0x43420000.
The values of the containerProtocolMinimum and
containerProtocolMaximum fields define a half-open range describing the
range of supported container protocol versions. Currently, the only supported values
of
containerProtocolMinimum and
containerProtocolMaximum are 1 and
1, respectively.
The value of the containerProtocolMinimum field MUST be ≤
containerProtocolMaximum.
The values of the reserved0, reserved1,
reserved2, reserved3, and
reserved4 fields MUST be 0.
The
appProtocolId specifies the bits of a
UUID
value that uniquely identifies the application protocol. The
Cedarbridge
compiler automatically generates these values for
protocol declarations.
The values of the appProtocolMinimum and
appProtocolMaximum fields define a half-open range describing the
range of supported container protocol versions. The value of the
appProtocolMinimum field MUST be ≤
appProtocolMaximum.
The size of the Available message, when encoded as a byte sequence, MUST be exactly
64 bytes.
The value of the code field MUST be exactly
0x43420001.
The value of the containerProtocol specifies the container protocol to be
used. Currently, the only supported value of containerProtocol is
1.
The
appProtocolId specifies the bits of a
UUID
value that uniquely identifies the application protocol. The
Cedarbridge
compiler automatically generates these values for
protocol declarations.
The value of the appProtocol field specifies the version of the
application protocol that will be used. The value of this field MUST be
appProtocolMinimum ≤ appProtocol ≤ appProtocolMaximum.
The size of the Available message, when encoded as a byte sequence, MUST be exactly
32 bytes.
The value of the code field MUST be exactly
0x43420002.
The value of the ok field MUST be exactly
0 if the client tried to use an unsupported protocol. The
value of the ok field MUST be exactly
1 if the client tried to use a supported protocol.
The value of the message field provides a humanly-readable
message explaining why version negotiation failed.
The size of the Response message, when encoded as a byte sequence, MUST be exactly
256 bytes. Padding bytes with values equal to 0x00
must be appended to the end of the structure if the message
field is shorter than 244 bytes.