Derive Macro ZeekType

#[derive(ZeekType)]
Expand description

§Derive macro to convert a type from and to a zeek_websocket_types::Value

Zeek’s WebSocket API encodes Zeek record values as vectors. This derive macro adds support for automatically converting Rust types to and from the encoding. It supports structs made up of fields which implement TryFrom<Value> and Into<Value>.

#[derive(Debug, PartialEq)] // Not required.
#[derive(ZeekType)]
struct Record {
    a: i64,
    b: u64,
}

let r = Record { a: -32, b: 1024 };

let value = Value::from(r);
assert_eq!(
    value,
    Value::Vector(vec![Value::Integer(-32), Value::Count(1024)]));

let r = Record::try_from(value).unwrap();
assert_eq!(r, Record { a: -32, b: 1024 });

If more than the expected number of fields are received they are silently discarded.

let v = Value::Vector(vec![Value::Integer(1), Value::Count(2), Value::Count(3)]);
let r: Record = v.try_into().unwrap();
assert_eq!(r, Record { a: 1, b: 2 });

// Unknown fields are not magically added back when encoding. This is supported by Zeek.
let v2 = Value::from(r);
assert_eq!(v2, Value::Vector(vec![Value::Integer(1), Value::Count(2)]));

§Optional fields

Zeek record fields which can be unset are marked &optional, e.g.,

type X: record {
    a: count;
    b: int &optional;
};

This is used to evolve Zeek record types so that users do not need to be updated if more fields are added.

The WebSocket API encodes unset fields as Value::None. To work with such types the Rust type should be an Option, e.g.,

#[derive(ZeekType)]
struct X {
    a: u64,
    b: Option<i64>,
}

Value::None maps onto Option::None.

let v = Value::Vector(vec![Value::Count(1), Value::None]);
let x: X = v.try_into().unwrap();
assert_eq!(x, X { a: 1, b: None });

Anything else maps onto Option::Some.

let v = Value::Vector(vec![Value::Count(1), Value::Integer(2)]);
let x: X = v.try_into().unwrap();
assert_eq!(x, X { a: 1, b: Some(2) });

If no value was received for an optional field it is set to None. Non-Option fields are always required.

let v = Value::Vector(vec![Value::Count(1)]);
let x: X = v.try_into().unwrap();
assert_eq!(x, X { a: 1, b: None });

// Error for non-`Option` fields.
let x: Result<X, _> = Value::Vector(vec![]).try_into();
assert!(x.is_err());