BitEncode

Derive Macro BitEncode 

Source
#[derive(BitEncode)]
{
    // Attributes available to this derive:
    #[bin_proto]
}
Available on crate feature derive only.
Expand description

Derive the BitDecode and BitEncode traits.

§Scopes

#[container, enum]
enum Enum {
    #[variant]
    Variant {
        #[field]
        field: Type,
    }
}

#[container, struct]
struct Struct {
    #[field]
    field: Type,
}

§Using Context

The ctx and ctx_bounds attributes can be used to specify additional context used during codec. The context can be accessed as __ctx, and the tag as __tag in any attribute macro’s <expr>, for example in tag.

struct Ctx {
    n: u32,
}

#[derive(BitDecode, BitEncode)]
#[bin_proto(ctx = Ctx)]
struct WithElementsLength {
    count: u32,
    foo: bool,
    #[bin_proto(tag = count * __ctx.n)]
    data: Vec<u32>,
}

§Attributes

AttributeScopeApplicability
discriminant_typeenumrw
discriminantvariantrw
othervariantr
bitsfield, enumrw
untaggedfieldrw
tagfieldrw
tag_typefieldrw
write_valuefieldw
ctxcontainerrw
ctx_boundscontainerrw
skip_encodefield, variantw
skip_decodefield, variantr
skipfield, variantrw
pad_beforefield, structrw
pad_afterfield, structrw
magicfield, structrw

§discriminant_type

#[bin_proto(discriminant_type = <type>)]

Specify if enum variant should be determined by a string or interger representation of its discriminant.

#[derive(BitDecode, BitEncode)]
#[bin_proto(discriminant_type = u8)]
enum Example {
    Variant1 = 1,
    Variant5 = 5,
}

§discriminant

#[bin_proto(discriminant = <value>)]

  • <value>: unique value of the discriminant’s type

Specify the discriminant for a variant.

#[derive(BitDecode, BitEncode)]
#[bin_proto(discriminant_type = u8)]
enum Example {
    #[bin_proto(discriminant = 1)]
    Variant1,
    Variant5 = 5,
}

§other

#[bin_proto(other)]

Decode the specified variant if the discriminant doesn’t match any other variants. A discriminant value can still be provided for the variant, and will be used when encoding.

#[derive(BitDecode, BitEncode)]
#[bin_proto(discriminant_type = u8)]
enum Example {
    #[bin_proto(discriminant = 1)]
    Variant1,
    #[bin_proto(discriminant = 2, other)]
    CatchAll,
}

§bits

#[bin_proto(bits = <width>)]

Determine width of field in bits.

WARNING: Bitfields disregard endianness and instead have the same endianness as the underlying BitRead / BitWrite instance. If you’re using bitfields, you almost always want a big endian stream.

#[derive(BitDecode, BitEncode)]
struct Nibble(#[bin_proto(bits = 4)] u8);

§untagged

#[bin_proto(untagged)]

Variable-length field is final field in container, hence lacks a length prefix and should be read until eof.

#[derive(BitDecode, BitEncode)]
struct ReadToEnd(#[bin_proto(untagged)] Vec<u8>);

§tag

#[bin_proto(tag = <expr>)]

  • <expr>: arbitrary expression. Fields in parent container can be used without prefixing them with self.

Specify tag of field. The tag represents a length prefix for variable-length fields, and a boolean for Option.

#[derive(BitDecode, BitEncode)]
struct WithElementsLength {
    count: u32,
    foo: bool,
    #[bin_proto(tag = count as usize)]
    data: Vec<u32>,
}

§tag_type

#[bin_proto(tag_type = <type>[, tag_value = <expr>]?[, tag_bits = <expr>]?)]

  • <type>: tag’s type
  • <expr>: arbitrary expression. Fields in parent container should be prefixed with self.

Specify tag of field. The tag represents a length prefix for variable-length fields, and a boolean for Option. The tag is placed directly before the field. The tag_value only has to be specified when deriving BitEncode.

#[derive(BitDecode, BitEncode)]
struct WithElementsLength {
    #[bin_proto(tag_type = u16, tag_value = self.data.len() as u16, tag_bits = 13)]
    data: Vec<u32>,
}

§write_value

#[bin_proto(write_value = <expr>)]

  • <expr>: An expression that can be coerced to the field type. Fields in parent container should be prefixed with self.

Specify an expression that should be used as the field’s value for writing.

#[derive(BitDecode, BitEncode)]
struct WithElementsLengthAuto {
    #[bin_proto(write_value = self.data.len() as u32)]
    count: u32,
    foo: bool,
    #[bin_proto(tag = count as usize)]
    data: Vec<u32>,
}

§ctx

#[bin_proto(ctx = <type>)[, ctx_generics(<generic>[, <generic>]*)]?]

  • <type>: The type of the context. Either a concrete type, or one of the container’s generics
  • <generic>: Any generics used by the context type, with optional bounds. E.g. T: Copy for a Vec<T> context.

Specify the type of context that will be passed to codec functions.

struct Ctx;

struct NeedsCtx;

impl BitDecode<Ctx> for NeedsCtx {
    fn decode<R, E>(
        _read: &mut R,
        _ctx: &mut Ctx,
        _tag: (),
    ) -> bin_proto::Result<Self>
    where
        R: bin_proto::BitRead,
        E: bin_proto::Endianness,
    {
        // Use ctx here
        Ok(Self)
    }
}

impl BitEncode<Ctx> for NeedsCtx {
    fn encode<W, E>(
        &self,
        _write: &mut W,
        _ctx: &mut Ctx,
        _tag: (),
    ) -> bin_proto::Result<()>
    where
        W: bin_proto::BitWrite,
        E: bin_proto::Endianness,
    {
        // Use ctx here
        Ok(())
    }
}

#[derive(BitDecode, BitEncode)]
#[bin_proto(ctx = Ctx)]
struct WithCtx(NeedsCtx);

WithCtx(NeedsCtx)
    .encode_bytes_ctx(bin_proto::BigEndian, &mut Ctx, ())
    .unwrap();
#[derive(BitDecode, BitEncode)]
#[bin_proto(ctx = Ctx)]
struct NestedCodec<Ctx, A: BitDecode<Ctx> + BitEncode<Ctx>>(A, PhantomData<Ctx>);
struct Ctx<'a, T: Copy>(&'a T);

#[derive(BitDecode, BitEncode)]
#[bin_proto(ctx = Ctx<'a, T>, ctx_generics('a, T: Copy))]
struct WithCtx;

§ctx_bounds

#[bin_proto(ctx_bounds(<bound>[, <bound>]*)[, ctx_generics(<generic>[, <generic>]*)]?)]

  • <bounds>: Trait bounds that must be satisfied by the context
  • <generic>: Any generics used by the context type. E.g. 'a for a context with a From<&'a i32> bound.

Specify the trait bounds of context that will be passed to codec functions.

trait CtxTrait {};

struct NeedsCtx;

impl<Ctx: CtxTrait> BitDecode<Ctx> for NeedsCtx {
    fn decode<R, E>(
        _read: &mut R,
        _ctx: &mut Ctx,
        _tag: (),
    ) -> bin_proto::Result<Self>
    where
        R: bin_proto::BitRead,
        E: bin_proto::Endianness,
    {
        // Use ctx here
        Ok(Self)
    }
}

impl<Ctx: CtxTrait> BitEncode<Ctx> for NeedsCtx {
    fn encode<W, E>(
        &self,
        _write: &mut W,
        _ctx: &mut Ctx,
        _tag: (),
    ) -> bin_proto::Result<()>
    where
        W: bin_proto::BitWrite,
        E: bin_proto::Endianness,
    {
        // Use ctx here
        Ok(())
    }
}

#[derive(BitDecode, BitEncode)]
#[bin_proto(ctx_bounds(CtxTrait))]
struct WithCtx(NeedsCtx);
#[derive(BitDecode, BitEncode)]
#[bin_proto(ctx_bounds(From<&'a i32>), ctx_generics('a))]
struct WithCtx;

§skip_encode

#[bin_proto(skip_encode)]

If applied to a field, skip the field when encoding. If applied to an enum variant, return an Error if the variant is attempted to be encoded.

#[derive(BitDecode, BitEncode)]
struct Struct(#[bin_proto(skip_encode)] u8);
#[derive(BitEncode)]
#[bin_proto(discriminant_type = u8)]
enum Enum {
    #[bin_proto(skip_encode)]
    Skip
}

§skip_decode

#[bin_proto(skip_decode)]

If applied to a field, use Default::default instead of attempting to read field. If applied to an enum variant, don’t generate code for decoding.

#[derive(BitDecode, BitEncode)]
struct Struct(#[bin_proto(skip_decode)] u8);
#[derive(BitDecode)]
#[bin_proto(discriminant_type = u8)]
enum Enum {
    #[bin_proto(skip_decode)]
    Skip
}

§skip

#[bin_proto(skip)]

Equivalent to combining skip_encode and skip_decode.

#[derive(BitDecode, BitEncode)]
struct Struct(#[bin_proto(skip)] u8);
#[derive(BitDecode, BitEncode)]
#[bin_proto(discriminant_type = u8)]
enum Enum {
    #[bin_proto(skip)]
    Skip
}

§pad_before

#[bin_proto(pad_before = <expr>)]

Insert 0 bits when writing and skip bits when reading, prior to processing the field.

#[derive(BitDecode, BitEncode)]
struct Struct(#[bin_proto(pad_before = 3)] u8);

§pad_after

#[bin_proto(pad_after = <expr>)]

Insert 0 bits when writing and skip bits when reading, after processing the field.

#[derive(BitDecode, BitEncode)]
struct Struct(#[bin_proto(pad_after = 3)] u8);

§magic

#[bin_proto(magic = <expr>)]

  • <expr>: Must evaluate to &[u8; _]

Indicates that the value must be present immediately preceding the field or struct.

#[derive(BitDecode, BitEncode)]
#[bin_proto(magic = &[0x01, 0x02, 0x03])]
struct Magic(#[bin_proto(magic = b"123")] u8);