<?xml version="1.0" encoding="utf-8"?>
<!-- vim: set et ts=2 sw=2 : -->
<!-- RFCXML Template

- https://authors.ietf.org/en/templates-and-schemas
- https://github.com/ietf-authors/rfcxml-templates-and-schemas

Copyright (c) 2021 IETF Trust and the persons identified as authors of the
code. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice, this
 list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright notice,
 this list of conditions and the following disclaimer in the documentation
 and/or other materials provided with the distribution.

 * Neither the name of Internet Society, IETF or IETF Trust, nor the names of
 specific contributors, may be used to endorse or promote products derived
 from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS”
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-->
<?xml-model href="rfc7991bis.rnc"?>
<!DOCTYPE rfc [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">
  <!ENTITY RFC2119 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.2119.xml">
  <!ENTITY RFC8174 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.8174.xml">
  <!ENTITY RFC3629 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.3629.xml">
  <!ENTITY RFC5234 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.5234.xml">
  <!ENTITY IEEE.754.1985 SYSTEM "https://xml2rfc.tools.ietf.org/public/rfc/bibxml-ieee/reference.IEEE.754.1985.xml">
]>
<rfc
  xmlns:xi="http://www.w3.org/2001/XInclude"
  category="info"
  docName="draft-devault-bare-14"
  ipr="trust200902"
  obsoletes=""
  updates=""
  submissionType="independent"
  xml:lang="en"
  version="3">
  <front>
    <title abbrev="BARE">Binary Application Record Encoding (BARE)</title>
    <seriesInfo name="Internet-Draft" value="draft-devault-bare-14"/>
    <author fullname="Drew DeVault" initials="D." surname="DeVault">
      <organization>SourceHut</organization>
      <address>
        <postal>
          <street>454 E. Girard Ave #2R</street>
          <city>Philadelphia</city>
          <region>PA</region>
          <code>19125</code>
          <country>US</country>
        </postal>
        <phone>+1 719 213 5473</phone>
        <email>sir@cmpwn.com</email>
        <uri>https://sourcehut.org/</uri>
      </address>
    </author>

    <date year="2025"/>

    <area>General</area>
    <workgroup>Internet Engineering Task Force</workgroup>

    <keyword>encoding</keyword>
    <keyword>bare</keyword>

    <abstract>
      <t>
        The Binary Application Record Encoding (BARE) is a data format used to
        represent application records for storage or transmission between
        programs. BARE messages are concise and have a well-defined schema, and
        implementations may be simple and broadly compatible. A schema language
        is also provided to express message schemas out-of-band.
      </t>
    </abstract>

    <note title="Comments">
      <t>
        Comments are solicited and should be addressed to the mailing list at
        ~sircmpwn/public-inbox@lists.sr.ht and/or the author(s).
      </t>
    </note>
  </front>

  <middle>
    <section>
      <name>Introduction</name>
      <t>
        The purpose of the BARE message encoding, like hundreds of others, is
        to encode application messages. The goals of such encodings vary
        (leading to their proliferation); BARE's goals are the following:
      </t>
      <ul>
        <li>Concise messages</li>
        <li>A well-defined message schema</li>
        <li>Broad compatibility with programming environments</li>
        <li>Simplicity of implementation</li>
      </ul>
      <t>
        This document specifies the BARE message encoding, as well as a schema
        language that may be used to describe the layout of a BARE message. The
        schema of a message must be agreed upon in advance by each party
        exchanging a BARE message; message structure is not encoded into the
        representation. The schema language is useful for this purpose but not
        required.
      </t>

      <section>
        <name>Requirements Language</name>
        <t>The key words "MUST", "MUST NOT", "REQUIRED", "SHALL",
          "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT
          RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be
          interpreted as described in BCP 14 <xref target="RFC2119"/>
          <xref target="RFC8174"/> when, and only when, they appear in
          all capitals, as shown here.</t>
      </section>

      <section>
        <name>Use-cases</name>
        <t>
          The goals of a concise, binary, strongly-typed, and
          broadly-compatible structured message encoding format support a broad
          number of use-cases. Examples include:
        </t>
        <ul>
          <li>Self-describing authentication tokens for web services</li>
          <li>
            Opaque messages for transmitting arbitrary state between unrelated
            internet services
          </li>
          <li>A representation for packets in an internet protocol</li>
          <li>
            A structured data format for encrypted or signed application
            messages
          </li>
          <li>
            A structured data format for storing data in persistent storage
          </li>
        </ul>
        <t>
          The conciseness of a BARE-encoded message enables representing
          structured data under strict limitations on message length in a large
          variety of contexts. The simple binary format may also be easily
          paired with additional tools, such as plain-text encodings,
          compression, or cryptography algorithms, as demanded by the
          application's needs, without increasing the complexity of the message
          encoding. A BARE message has a comparable size and entropy to the
          underlying state it represents.
        </t>
        <t>
          The BARE schema language also provides a means of describing the
          format of BARE messages without implementation-specific details. This
          encourages applications that utilize BARE to describe their state in
          a manner that other programmers can easily utilize for application
          interoperation. The conservative set of primitives offered by BARE
          aids in making such new implementations easy to write.
        </t>
      </section>
    </section>

    <section>
      <name>Specification of the BARE Message Encoding</name>
      <t>
        A BARE message is a single value of a pre-defined type, which may be of
        an aggregate type enclosing multiple values. Unless otherwise specified,
        there is no additional container or structure around the value; it is
        encoded plainly.
      </t>
      <t>
        A BARE message does not necessarily have a fixed length, but the schema
        author may make a deliberate choice to constrain themselves to types of
        well-defined lengths if this is desired.
      </t>
      <t>
        The names for each type are provided to establish a vocabulary for
        describing a BARE message schema out-of-band, by parties who plan to
        exchange BARE messages. The type names used here are provided for this
        informative purpose, but are more rigourously specified by the schema
        language specification in <xref target="schema_language" />.
      </t>

      <section>
        <name>Primitive Types</name>
        <t>Primitive types represent exactly one value.</t>
        <dl indent="8" newline="true">
          <dt>uint</dt>
          <dd>
            <t>
              A variable-length unsigned integer encoded using the Unsigned
              Little Endian Base 128 (ULEB128). Every octet of the encoded
              value has the most-significant bit set, except for the last
              octet. The remaining bits are the zero-extended integer value in
              7-bit groups, the least-significant group first.
            </t>
            <t>
              The encoder MUST encode uint using the minimum necessary number
              of octets, and the decoder SHOULD raise an error if it encounters
              the opposite.
            </t>
            <t>
              The maximum precision of such a number is 64-bits. The maximum
              length of an encoded uint is therefore 10 octets.
            </t>
            <t>
              Numbers that require all ten octets will have 6 bits in the final
              octet that do not have meaning, between the least- and
              most-significant bits. The implementation MUST set these to zero.
            </t>
          </dd>

          <dt>int</dt>
          <dd>
            <t>
              A signed integer with variable-length encoding. Signed integers
              are represented as uint using a "zig-zag" encoding: positive
              values x are written as 2x + 0, negative values as -2x - 1.
              Another way of looking at it is that negative numbers are
              complemented, and whether to complement is encoded in bit 0.
            </t>
            <t>
              The encoder MUST encode int using the minimum necessary number
              of octets, and the decoder SHOULD raise an error if it
              encounters the opposite.
            </t>
            <t>
              The maximum precision of such a number is 64-bits. The maximum
              length of an encoded int is therefore 10 octets.
            </t>
            <t>
              Numbers that require all ten octets will have 6 bits in the
              final octet that do not have meaning, between the least- and
              most-significant bits. The implementation MUST set these to
              zero.
            </t>
          </dd>

          <dt>u8, u16, u32, u64</dt>
          <dd>
            <t>
              Unsigned integers of a fixed precision, respectively 8, 16, 32,
              and 64 bits. They are encoded in little-endian (least significant
              octet first).
            </t>
          </dd>

          <dt>i8, i16, i32, i64</dt>
          <dd>
            <t>
              Signed integers of a fixed precision, respectively 8, 16, 32,
              and 64 bits. They are encoded in little-endian (least
              significant octet first), with two's complement notation.
            </t>
          </dd>

          <dt>f32, f64</dt>
          <dd>
            <t>
              Floating-point numbers represented with the
              <xref target="IEEE.754.1985">IEEE 754</xref>
              binary32 and binary64 floating point number formats.
            </t>
          </dd>

          <dt>bool</dt>
          <dd>
            <t>
              A boolean value, either true or false, encoded as a u8 type with
              a value of one or zero, respectively representing true or false.
            </t>
            <t>
              If a value other than one or zero is found in the u8
              representation of the bool, the message is considered invalid,
              and the decoder SHOULD raise an error if it encounters such a
              value.
            </t>
          </dd>

          <dt>str</dt>
          <dd>
            <t>
              A string of text. The length of the text in octets is encoded
              first as a uint, followed by the text data represented with the
              <xref target="RFC3629">UTF-8 encoding</xref>.
            </t>
            <t>
              If the data is found to contain invalid UTF-8 sequences, it is
              considered invalid, and the decoder SHOULD raise an error if it
              encounters such a value.
            </t>
          </dd>

          <dt>data</dt>
          <dd>
            <t>
              Arbitrary data of a variable length. The length (in octets) is
              encoded first as a uint, followed by the data itself encoded
              literally.
            </t>
          </dd>

          <dt>data[length]</dt>
          <dd>
            <t>
              Arbitrary data of a fixed "length", e.g. data[16]. The length (in
              octets) is not encoded into the message. The data is encoded
              literally in the message.
            </t>
          </dd>

          <dt>void</dt>
          <dd>
            <t>
              A type with zero length. It is not encoded into BARE messages.
            </t>
          </dd>

          <dt>enum</dt>
          <dd>
            <t>
              An unsigned integer value from a set of named values agreed upon
              in advance, encoded with the uint type.
            </t>
            <t>
              An enum whose uint value is not a member of the values agreed
              upon in advance is considered invalid, and the decoder SHOULD
              raise an error if it encounters such a value.
            </t>
            <t>
              Note that this makes the enum type unsuitable for representing
              several enum values that have been combined with a bitwise OR
              operation.
            </t>
            <t>
              Using uint for enum value makes it possible to encode named
              values with different number of octets. Constant-length enum can
              be achieved when all the enum values are encoded by uints with
              the same number of octets.
            </t>
          </dd>
        </dl>
      </section>

      <section>
        <name>Aggregate Types</name>
        <t>
          Aggregate types may store zero or more primitive or aggregate values.
        </t>
        <dl indent="8" newline="true">
          <dt>optional&lt;type&gt;</dt>
          <dd>
            <t>
              A value of "type" that may or may not be present, e.g.
              optional&lt;u32&gt;. Represented as either a u8 with a value of
              zero, indicating that the optional value is unset; or a u8 with a
              value of one, followed by the encoded data of the optional type.
            </t>
            <t>
              An optional value whose initial u8 is set to a number other than
              zero or one is considered invalid, and the decoder SHOULD raise
              an error if it encounters such a value.
            </t>
          </dd>

          <dt>list&lt;type&gt;</dt>
          <dd>
            <t>
              A variable-length list of "type" values, e.g. list&lt;str&gt;.
              The length of the list (number of values) is encoded as a uint,
              followed by the encoded values of each member of the list
              concatenated.
            </t>
          </dd>

          <dt>list&lt;type&gt;[length]</dt>
          <dd>
            <t>
              A list of "length" values of "type", e.g. list&lt;uint&gt;[10].
              The length is not encoded into the message. The encoded values of
              each member of the list are concatenated to form the encoded
              list.
            </t>
          </dd>

          <dt>map&lt;type A&gt;&lt;type B&gt;</dt>
          <dd>
            <t>
              A mapping of "type B" values keyed by "type A" values, e.g.
              map&lt;u32&gt;&lt;str&gt;. The encoded representation of a map
              begins with the number of key/value pairs encoded as a uint,
              followed by the encoded key/value pairs concatenated. Each
              key/value pair is encoded as the encoded key concatenated with
              the encoded value.
            </t>
            <t>
              A message with repeated keys is considered invalid, and the
              decoder SHOULD raise an error if it encounters such a value.
            </t>
          </dd>

          <dt>union</dt>
          <dd>
            <t>
              A tagged union whose value may be one of any type from a set of
              types agreed upon in advance. Every type in the set is assigned a
              numeric identifier. The value is encoded as the selected type's
              identifier represented with the uint encoding, followed by the
              encoded value of that type.
            </t>
            <t>
              A union with a tag value that does not have a corresponding type
              assigned is considered invalid, and the decoder SHOULD raise an
              error if it encounters such a value.
            </t>
          </dd>

          <dt>struct</dt>
          <dd>
            <t>
              A set of values of arbitrary types concatenated in an order
              agreed upon in advance. Each value is called "field", and the
              field has a name and type.
            </t>
          </dd>
        </dl>
      </section>

      <section>
        <name>User-Defined Types</name>
        <t>
          A user-defined type gives a name to another type. This creates a
          distinct type whose representation is equivalent to the named type.
          An arbitrary number of user-defined types may be used for the same
          underlying type; each is distinct from the other.
        </t>
      </section>

      <section>
        <name>Invariants</name>
        <t>The following invariants are specified:</t>
        <ul>
          <li>
            Any type that is ultimately a void type (either directly or via a
            user-defined type) MUST NOT be used as an optional type, list
            value, map key, map value, or struct field type. Void types may
            only be used as members of the set of types in a tagged union.
          </li>

          <li>
            Enums MUST have at least one named value, and each named value of
            an enum MUST be unique.
          </li>

          <li>
            The lengths of fixed-length data and fixed-length list types MUST
            be at least one and MUST NOT be longer than
            18,446,744,073,709,551,615 octets (the maximum value of a u64).
          </li>

          <li>
            Any map key type (directly or via a user-defined type) MUST be of a
            primitive type that is not f32, f64, or void.
          </li>

          <li>
            Unions MUST have at least one type, each type of a union MUST be
            unique and each numeric identifier assigned to a type MUST be
            unique.
          </li>

          <li>
            Structs MUST have at least one field, and each field of a struct
            MUST have a unique name.
          </li>

          <li>
            Any user-defined type MUST be defined before used. Any user-defined
            type MUST NOT be defined recursively (directly or indirectly).
          </li>
        </ul>
      </section>
    </section>

    <section anchor="schema_language">
      <name>BARE Schema Language Specification</name>
      <t>
        The use of the schema language is optional. Implementations SHOULD
        support decoding arbitrary BARE messages without a schema document, by
        defining the schema in a manner that utilizes more native tools
        available from the programming environment.
      </t>
      <t>
        However, it may be useful to have a schema document for use with code
        generation, documentation, or interoperability. A domain-specific
        language is provided for this purpose.
      </t>

      <section>
        <name>Lexical Analysis</name>
        <t>
          During lexical analysis, "#" is used for comments; if encountered,
          the "#" character and any subsequent characters are discarded until a
          line feed (%x0A) is found.
        </t>
      </section>

      <section>
        <name>ABNF Grammar</name>
        <t>
          The syntax of the schema language is provided here in
          <xref target="RFC5234">Augmented Backus-Naur Form</xref>.
          However, this grammar differs from <xref target="RFC5234"/>
          in that literal text strings are case-sensitive (e.g. "type" does not
          match "TypE").
        </t>
          <artwork type="abnf"><![CDATA[
schema            =  [WS] user-types [WS]

user-types        =  user-type [WS user-types]
user-type         =  "type" WS user-type-name WS any-type
user-type-name    =  UPPER *(ALPHA / DIGIT) ; first letter is uppercase

any-type          =  "uint" / "u8"  / "u16" / "u32" / "u64"
any-type          =/ "int" / "i8"  / "i16" / "i32" / "i64"
any-type          =/ "f32" / "f64"
any-type          =/ "bool"
any-type          =/ "str"
any-type          =/ "data" [length]
any-type          =/ "void"
any-type          =/ "enum" [WS] "{" [WS] enum-values [WS] "}"
any-type          =/ "optional" type
any-type          =/ "list" type [length]
any-type          =/ "map" type type
any-type          =/ "union" [WS] "{" [[WS] "|"] [WS] union-members [WS] ["|" [WS]] "}"
any-type          =/ "struct" [WS] "{" [WS] struct-fields [WS] "}"
any-type          =/ user-type-name

length            =  [WS] "[" [WS] integer [WS] "]"
integer           =  1*DIGIT

enum-values       =  enum-value [WS enum-values]
enum-value        =  enum-value-name [[WS] "=" [WS] integer]
enum-value-name   =  UPPER *(UPPER / DIGIT / "_")

type              =  [WS] "<" [WS] any-type [WS] ">"

union-members     =  union-member [[WS] "|" [WS] union-members]
union-member      =  any-type [[WS] "=" [WS] integer]

struct-fields     =  struct-field [WS struct-fields]
struct-field      =  struct-field-name [WS] ":" [WS] any-type
struct-field-name =  LOWER *(ALPHA / DIGIT / "_")

UPPER             =  %x41-5A                ; uppercase ASCII letters, i.e., A-Z
LOWER             =  %x61-7A                ; lowercase ASCII letters, i.e., a-z
ALPHA             =  UPPER / LOWER
DIGIT             =  %x30-39                ; 0-9

WS                =  1*(%x0A / %x09 / " ")  ; whitespace
]]></artwork>
        <t>
          See <xref target="appx_example_schema"/>
          for an example schema written in this language.
        </t>
      </section>

      <section>
        <name>Semantic Elements</name>
        <t>
          The names of fields and user-defined types are informational: they
          are not represented in BARE messages. They may be used by code
          generation tools to inform the generation of field and type names in
          the native programming environment.
        </t>
        <t>
          Enum values are also informational. Values without an integer token
          are assigned automatically in the order that they appear, starting
          from zero and incrementing by one for each subsequent unassigned
          value. If a value is explicitly specified, automatic assignment
          continues from that value plus one for subsequent enum values.
          Values MUST be in ascending order, and code generation tools SHOULD
          raise error if not.
        </t>
        <t>
          Union type members are assigned a tag in the order that they appear,
          starting from zero and incrementing by one for each subsequent type.
          If a tag value is explicitly specified, automatic assignment
          continues from that value plus one for subsequent values.
          Tags MUST be in ascending order, and code generation tools SHOULD
          raise error if not.
        </t>
      </section>
    </section>

    <section>
      <name>Application Considerations</name>
      <t>
        Message authors who wish to design a schema that is backwards- and
        forwards-compatible with future messages are encouraged to use union
        types for this purpose. New types may be appended to the members of a
        union type while retaining backwards compatibility with older message
        types. The choice to do this must be made from the first message
        version -- moving a struct into a union <em>does not</em> produce a
        backwards-compatible message.
      </t>
      <t>The following schema provides an example:</t>
      <artwork><![CDATA[
type MessageV1 ...

type MessageV2 ...

type MessageV3 ...

type Message union {MessageV1 | MessageV2 | MessageV3}
]]></artwork>
      <t>
        An updated schema that adds a MessageV4 type would still be able to
        decode versions 1, 2, and 3.
      </t>
      <t>
        If a message version is later deprecated, it may be removed in a manner
        compatible with future versions 2 and 3 if the initial tag is specified
        explicitly.
      </t>
      <artwork><![CDATA[
type Message union {MessageV2 = 1 | MessageV3}
]]></artwork>
      <t>
        Message authors who wish to deliver the message using a stream protocol
        should add a length as the first field of the message to explicitly
        indicate the boundaries of the message.
      </t>
      <t>The following schema provides an example:</t>
      <artwork><![CDATA[
type MessageWithLength struct {
  len: u32
  msg: Message
}
]]></artwork>
      <t>
        Thus, the reception of the message over a stream protocol consists of
        two phases. First, the reception and decoding of the length. Second,
        the reception and decoding of the message.
      </t>
    </section>

    <section>
      <name>Future Considerations</name>
      <t>
        To ensure message compatibility between implementations and backwards-
        and forwards-compatibility of messages, constraints on vendor
        extensions are required. This specification is final, and new types or
        extensions will not be added in the future. Implementors MUST NOT
        define extensions to this specification.
      </t>
      <t>
        To support the encoding of novel data structures, the implementor
        SHOULD make use of user-defined types in combination with the data or
        data[length] types.
      </t>
    </section>

    <section anchor="IANA">
      <name>IANA Considerations</name>
      <t>This memo includes no request to IANA.</t>
    </section>

    <section anchor="Security">
      <name>Security Considerations</name>
      <t>
        Message decoders are common vectors for security vulnerabilities. BARE
        addresses this by making the message format as simple as possible.
        However, the decoder MUST be prepared to handle a number of error cases
        when decoding untrusted messages, such as a union type with an invalid
        tag, or an enum with an invalid value. Such errors may also arise by
        mistake, for example when attempting to decode a message with the wrong
        schema.
      </t>
      <t>
        Support for data types of an arbitrary, message-defined length (lists,
        maps, strings, etc) is commonly exploited to cause the implementation
        to exhaust its resources while decoding a message. However, legitimate
        use-cases for extremely large data types (possibly larger than the
        system has the resources to store all at once) do exist. The decoder
        MUST manage its resources accordingly, and SHOULD provide the
        application a means of providing their own decoder implementation for
        values that are expected to be large.
      </t>
      <t>
        There is only one valid interpretation of a BARE message for a given
        schema, and different decoders and encoders should be expected to
        provide that interpretation. If an implementation has limitations
        imposed from the programming environment (such as limits on numeric
        precision), the implementor MUST document these limitations, and
        prevent conflicting interpretations from causing undesired behavior.
      </t>
    </section>
  </middle>

  <back>
    <references>
      <name>Normative References</name>
      &RFC2119;
      &RFC8174;
      &RFC5234;
      &RFC3629;
      &IEEE.754.1985;
    </references>

    <section>
      <name>Example Values</name>
      <t>
        This section lists example values in decimal, as string, or as named
        value (left or top), and their encoded representation in hexadecimal
        (right or bottom).
      </t>
      <dl indent="8" newline="true">
        <dt>uint</dt>
        <dd>
          <artwork type="ascii-art"><![CDATA[
0                  00
1                  01
126                7e
127                7f
128                80 01
129                81 01
255                FF 01
]]></artwork>
        </dd>

        <dt>int</dt>
        <dd>
          <artwork type="ascii-art"><![CDATA[
0                  00
1                  02
-1                 01
63                 7e
-63                7d
64                 80 01
-64                7f
65                 82 01
-65                81 01
255                FE 03
-255               FD 03
]]></artwork>
        </dd>

        <dt>u32</dt>
        <dd>
          <artwork type="ascii-art"><![CDATA[
0                  00 00 00 00
1                  01 00 00 00
255                FF 00 00 00
]]></artwork>
        </dd>

        <dt>i16</dt>
        <dd>
          <artwork type="ascii-art"><![CDATA[
0                  00 00
1                  01 00
-1                 FF FF
255                FF 00
-255               01 FF
]]></artwork>
        </dd>

        <dt>f64</dt>
        <dd>
          <artwork type="ascii-art"><![CDATA[
0.0                00 00 00 00 00 00 00 00
1.0                00 00 00 00 00 00 f0 3f
2.55               66 66 66 66 66 66 04 40
-25.5              00 00 00 00 00 80 39 C0
]]></artwork>
        </dd>

        <dt>bool</dt>
        <dd>
          <artwork type="ascii-art"><![CDATA[
true               01
false              00
]]></artwork>
        </dd>

        <dt>str</dt>
        <dd>
          <artwork type="ascii-art"><![CDATA[
"BARE"             04 42 41 52 45
]]></artwork>
        </dd>

        <dt>data</dt>
        <dd>
          <t>Example value is in hexadecimal.</t>
          <artwork type="ascii-art"><![CDATA[
aa ee ff ee dd cc bb aa ee dd cc bb ee dd cc bb
]]></artwork>
          <artwork type="ascii-art"><![CDATA[
10 aa ee ff ee dd cc bb aa ee dd cc bb ee dd cc
bb
]]></artwork>
        </dd>

        <dt>data[16]</dt>
        <dd>
          <t>Example value is in hexadecimal.</t>
          <artwork type="ascii-art"><![CDATA[
aa ee ff ee dd cc bb aa ee dd cc bb ee dd cc bb
]]></artwork>
          <artwork type="ascii-art"><![CDATA[
aa ee ff ee dd cc bb aa ee dd cc bb ee dd cc bb
]]></artwork>
        </dd>

        <dt>void</dt>
        <dd>
          <t>Not encoded.</t>
        </dd>

        <dt>enum {FOO BAR = 255 BUZZ}</dt>
        <dd>
          <artwork type="ascii-art"><![CDATA[
FOO                00
BAR                FF 01
BUZZ               80 02
]]></artwork>
        </dd>

        <dt>optional&lt;u32&gt;</dt>
        <dd>
          <artwork type="ascii-art"><![CDATA[
(unset)            00
0                  01 00 00 00 00
1                  01 01 00 00 00
255                01 FF 00 00 00
]]></artwork>
        </dd>

        <dt>list&lt;str&gt;</dt>
        <dd>
          <artwork type="ascii-art"><![CDATA[
"foo" "bar" "buzz"
]]></artwork>
          <artwork type="ascii-art"><![CDATA[
03 03 66 6f 6f 03 62 61 72 04 62 75 7A 7A
]]></artwork>
        </dd>

        <dt>list&lt;uint&gt;[10]</dt>
        <dd>
          <artwork type="ascii-art"><![CDATA[
0 1 254 255 256 257 126 127 128 129
]]></artwork>
          <artwork type="ascii-art"><![CDATA[
00 01 FE 01 FF 01 80 02 81 02 7E 7F 80 01 81 01
]]></artwork>
        </dd>

        <dt>map&lt;u32&gt;&lt;str&gt;</dt>
        <dd>
          <artwork type="ascii-art"><![CDATA[
0 => "zero"
1 => "one"
255 => "two hundreds and fifty five"
]]></artwork>
          <artwork type="ascii-art"><![CDATA[
03 00 00 00 00 04 7A 65 72 6F 01 00 00 00 03 6F
6E 65 FF 00 00 00 1B 74 77 6F 20 68 75 6E 64 72
65 64 73 20 61 6E 64 20 66 69 66 74 79 20 66 69
76 65
]]></artwork>
        </dd>

        <dt>union {int | uint = 255 | str}</dt>
        <dd>
          <artwork type="ascii-art"><![CDATA[
0                  00 00
1                  00 02
1                  FF 01 01
-1                 00 01
255                00 FE 03
255                FF 01 FF 01
-255               00 FD 03
"BARE"             80 02 04 42 41 52 45
]]></artwork>
        </dd>

        <dt>struct {foo: uint bar: int buzz: str}</dt>
        <dd>
          <artwork type="ascii-art"><![CDATA[
foo => 255
bar => -255
buzz => "BARE"
]]></artwork>
          <artwork type="ascii-art"><![CDATA[
FF 01 FD 03 04 42 41 52 45
]]></artwork>
        </dd>
      </dl>
    </section>

    <section>
      <name>Example Company</name>
      <t>
        An example company that uses BARE to encode data about customers and
        employees.
      </t>
      <section anchor="appx_example_schema">
        <name>Message Schema</name>
        <t>
          The following is an example of a schema written in the BARE schema
          language.
        </t>
        <artwork><![CDATA[
type PublicKey data[128]
type Time str # ISO 8601

type Department enum {
  ACCOUNTING
  ADMINISTRATION
  CUSTOMER_SERVICE
  DEVELOPMENT

  # Reserved for the CEO
  JSMITH = 99
}

type Address list<str>[4] # street, city, state, country

type Customer struct {
  name: str
  email: str
  address: Address
  orders: list<struct {
    orderId: i64
    quantity: i32
  }>
  metadata: map<str><data>
}

type Employee struct {
  name: str
  email: str
  address: Address
  department: Department
  hireDate: Time
  publicKey: optional<PublicKey>
  metadata: map<str><data>
}

type TerminatedEmployee void

type Person union {Customer | Employee | TerminatedEmployee}
]]></artwork>
      </section>

      <section>
        <name>Encoded Messages</name>
        <t>
          Some basic example messages in hexadecimal are provided for the
          schema specified in <xref target="appx_example_schema"/>.
        </t>

        <t>A "Person" value of type "Customer" with the following values:</t>
        <dl indent="16">
          <dt>name</dt>
          <dd>James Smith</dd>

          <dt>email</dt>
          <dd>jsmith@example.org</dd>

          <dt>address</dt>
          <dd>123 Main St; Philadelphia; PA; United States</dd>

          <dt>orders (1)</dt>
          <dd>orderId: 4242424242; quantity: 5</dd>

          <dt>metadata</dt>
          <dd>(unset)</dd>
        </dl>
        <t>Encoded BARE message:</t>
        <artwork><![CDATA[
00 0b 4a 61 6d 65 73 20 53 6d 69 74 68 12 6a 73
6d 69 74 68 40 65 78 61 6d 70 6c 65 2e 6f 72 67
0b 31 32 33 20 4d 61 69 6e 20 53 74 0c 50 68 69
6c 61 64 65 6c 70 68 69 61 02 50 41 0d 55 6e 69
74 65 64 20 53 74 61 74 65 73 01 b2 41 de fc 00
00 00 00 05 00 00 00 00
]]></artwork>
        <t>
          Encoded BARE message, but characters of strings are decoded:
        </t>
        <artwork><![CDATA[
00 0b  J  a  m  e  s     S  m  i  t  h 12  j  s
 m  i  t  h  @  e  x  a  m  p  l  e  .  o  r  g
0b  1  2  3     M  a  i  n     S  t 0c  P  h  i
 l  a  d  e  l  p  h  i  a 02  P  A 0d  U  n  i
 t  e  d     S  t  a  t  e  s 01 b2 41 de fc 00
00 00 00 05 00 00 00 00
]]></artwork>


        <t>A "Person" value of type "Employee" with the following values:</t>
        <dl indent="16">
          <dt>name</dt>
          <dd>Tiffany Doe</dd>

          <dt>email</dt>
          <dd>tiffanyd@acme.corp</dd>

          <dt>address</dt>
          <dd>123 Main St; Philadelphia; PA; United States</dd>

          <dt>department</dt>
          <dd>ADMINISTRATION</dd>

          <dt>hireDate</dt>
          <dd>2020-06-21T21:18:05Z</dd>

          <dt>publicKey</dt>
          <dd>(unset)</dd>

          <dt>metadata</dt>
          <dd>(unset)</dd>
        </dl>
        <t>Encoded BARE message:</t>
        <artwork><![CDATA[
01 0b 54 69 66 66 61 6e 79 20 44 6f 65 12 74 69
66 66 61 6e 79 64 40 61 63 6d 65 2e 63 6f 72 70
0b 31 32 33 20 4d 61 69 6e 20 53 74 0c 50 68 69
6c 61 64 65 6c 70 68 69 61 02 50 41 0d 55 6e 69
74 65 64 20 53 74 61 74 65 73 01 14 32 30 32 30
2d 30 36 2d 32 31 54 32 31 3a 31 38 3a 30 35 5a
00 00
]]></artwork>
        <t>
          Encoded BARE message, but characters of strings are decoded:
        </t>
        <artwork><![CDATA[
01 0b  T  i  f  f  a  n  y     D  o  e 12  t  i
 f  f  a  n  y  d  @  a  c  m  e  .  c  o  r  p
0b  1  2  3     M  a  i  n     S  t 0c  P  h  i
 l  a  d  e  l  p  h  i  a 02  P  A 0d  U  n  i
 t  e  d     S  t  a  t  e  s 01 14  2  0  2  0
 -  0  6  -  2  1  T  2  1  :  1  8  :  0  5  Z
00 00
]]></artwork>

        <t>A "Person" value of type "TerminatedEmployee".</t>
        <t>Encoded BARE message:</t>
        <artwork><![CDATA[02]]></artwork>
      </section>
    </section>

    <section>
      <name>Complex Data</name>
      <t>
        BARE schema examples for complex data structures.
      </t>
      <section>
        <name>Simple Hierarchical Data</name>
        <t>
          Recursive data types are forbidden in BARE. The following examples
          show how linked list and binary tree, widely used recursive data
          types, can be encoded in BARE messages.
        </t>
        <t>
          As BARE supports variable-length lists, encoding of linked list is
          straightforward.
        </t>
        <artwork><![CDATA[
type Element struct {
  what: str
}

type LinkedList list<Element>
]]></artwork>
        <t>
          A binary tree can be encoded to BARE's variable-length list with 2x +
          1 and 2x + 2 indexing.
        </t>
        <artwork><![CDATA[
type Node optional<struct {
  what: str
}>

type BinaryTree list<Node>
]]></artwork>
      </section>
      <section>
        <name>JSON Schema</name>
        <t>
          Sometimes it is needed to deal with generic format of data. When the
          use-case for recursive types is encountered, each element to encode
          needs to be identified.
        </t>
        <artwork><![CDATA[
type ElementId uint

type False void
type True void
type Null void

type Object map<str><ElementId>
type Array list<ElementId>

type Element union {
  | False
  | True
  | Null
  | f64
  | str
  | Object
  | Array
}

type JSONDocument list<Element>
]]></artwork>
      </section>
      <section>
        <name>Graph</name>
        <t>
          It is not possible to encode pointers in BARE. However, an arbitrary
          graph can be encoded in the lists of nodes and connections.
        </t>
        <artwork><![CDATA[
type NodeId uint

type Node struct {
  what: str
}

type Connection struct {
  from: NodeId
  to: NodeId
  why: str
}

type Graph struct {
  nodes: map<NodeId><Node>
  edges: list<Connection>
}
]]></artwork>
      </section>
    </section>

    <section>
      <name>Design Decisions</name>
      <t>
        This section documents the reasoning behind the decisions made during
        BARE specification process.
      </t>
      <dl indent="3" newline="true">
        <dt><strong>
          f32 and f64 are fully compliant with
          <xref target="IEEE.754.1985">IEEE 754</xref>
        </strong></dt>
        <dd>
          <t>
            The use-case is a sensor sending NaN values or encoding of infinity
            in scientific applications.
          </t>
          <t>
            The consequences are that encoded values of f32 and f64 types are
            not canonical, and therefore forbidden as map keys.
          </t>
        </dd>

        <dt><strong>
          Types of a union needs to be unique
        </strong></dt>
        <dd>
          <t>
            However, user-defined types are distinct types, so it is not a
            problem overall.
          </t>
        </dd>

        <dt><strong>
          Recursive types are forbidden
        </strong></dt>
        <dd>
          <t>
            Recursive types bring the possibility to encode arbitrary tree data
            structures for the price of:
          </t>
          <ol>
          <li>
            runtime errors for cyclic references,
          </li>
          <li>
            possible stack overflows during encoding/decoding when recursive
            encoders/decoders are used,
          </li>
          <li>
            confusion because they do not come with pointers, although data
            to encode usually uses pointers.
          </li>
          </ol>
          <t>
            It is not worth it.
          </t>
          <t>
            The consequence is that recursive types need to be mapped to
            non-recursive types when used.
          </t>
        </dd>

        <dt><strong>
          Namespaces or imports are not used
        </strong></dt>
        <dd>
          <t>
            It would increase complexity. BARE schema language is simple.
          </t>
        </dd>

        <dt><strong>
          There is no bitmap type
        </strong></dt>
        <dd>
          <t>
            Use data[length] instead. Note that BARE is octet-aligned.
          </t>
        </dd>

        <dt><strong>
          There is no date/time type
        </strong></dt>
        <dd>
          <t>
            It is better to use str for ISO 8601 or u64 for timestamp.
          </t>
        </dd>

        <dt><strong>
          There is no ordered map type
        </strong></dt>
        <dd>
          <t>
            Ordered maps are not widely supported in programming environments.
            Users that want to use ordered maps can use a list of pairs:
          </t>
          <artwork><![CDATA[
list<struct {
  key: KeyType
  val: ValType
}>
]]></artwork>
        </dd>
      </dl>
    </section>
 </back>
</rfc>
