BitEncode

Derive Macro BitEncode 

Source
#[derive(BitEncode)]
{
    // Attributes available to this derive:
    #[codec]
}
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)]
#[codec(ctx = Ctx)]
pub struct WithElementsLength {
    pub count: u32,
    pub foo: bool,
    #[codec(tag = count * __ctx.n)]
    pub data: Vec<u32>,
}

§Attributes

AttributeScopeApplicability
discriminant_typeenumrw
discriminantvariantrw
bitsfield, enumrw
flexible_array_memberfieldrw
tagfieldrw
tag_typefieldrw
write_valuefieldw
ctxcontainerrw
ctx_boundscontainerrw
defaultfieldr
pad_beforefield, structrw
pad_afterfield, structrw
magicfield, structrw

§discriminant_type

#[codec(discriminant_type = <type>)]

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

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

§discriminant

#[codec(discriminant = <value>)]

  • <value>: unique value of the discriminant’s type
#[derive(BitDecode, BitEncode)]
#[codec(discriminant_type = u8)]
enum Example {
    #[codec(discriminant = 1)]
    Variant1,
    Variant5 = 5,
}

Specify the discriminant for a variant.

§bits

#[codec(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(#[codec(bits = 4)] u8);

§flexible_array_member

#[codec(flexible_array_member)]

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

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

§tag

#[codec(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)]
pub struct WithElementsLength {
    pub count: u32,
    pub foo: bool,
    #[codec(tag = count as usize)]
    pub data: Vec<u32>,
}

§tag_type

#[codec(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)]
pub struct WithElementsLength {
    #[codec(tag_type = u16, tag_value = self.data.len() as u16, tag_bits = 13)]
    pub data: Vec<u32>,
}

§write_value

#[codec(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)]
pub struct WithElementsLengthAuto {
    #[codec(write_value = self.data.len() as u32)]
    pub count: u32,
    pub foo: bool,
    #[codec(tag = count as usize)]
    pub data: Vec<u32>,
}

§ctx

#[codec(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.

pub struct Ctx;

pub 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)]
#[codec(ctx = Ctx)]
pub struct WithCtx(NeedsCtx);

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

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

§ctx_bounds

#[codec(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.

pub trait CtxTrait {};

pub 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)]
#[codec(ctx_bounds(CtxTrait))]
pub struct WithCtx(NeedsCtx);
#[derive(BitDecode, BitEncode)]
#[codec(ctx_bounds(From<&'a i32>), ctx_generics('a))]
pub struct WithCtx;

§default

#[codec(default)]

Use Default::default instead of attempting to read field.

#[derive(BitDecode, BitEncode)]
pub struct Struct(#[codec(default)] u8);

§pad_before

#[codec(pad_before = <expr>)]

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

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

§pad_after

#[codec(pad_after = <expr>)]

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

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

§magic

#[codec(magic = <expr>)]

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

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

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