Enum LengthEncoding

Source
pub enum LengthEncoding<T> {
    Fixed(usize),
    LengthEncoded(IntegerSchema),
    EndPattern {
        sentinel: T,
    },
    Capacity {
        padding: T,
        capacity: usize,
    },
    TillEnd,
}
Expand description

The way the length of a variable length field is specified in an array or string schema.

The length encoding is usually given explicit with the parameter "lengthEncoding" in a schema. A length encoding is always a JSON object with a field "type". The default length encoding is "tillend".

§Length of Array and String

Depending on the surrounding schema the length encoded refers to different things. In an array schema the length denotes the number of elements in the encoded array. In a string array the length means the number of bytes required to store the UTF-8 encoded string.

Variants§

§

Fixed(usize)

Fixed Size → "@type": "fixed".

The encoded length is always the same. Only values with the fixed length are valid for this schema.

§Definition in the Schema

In contrast to other length encodings fixed is may not be given explicitly. Instead it requires "minLength" and "maxLength" for string and "minItems" and "maxItems" for array schemata be set to the same value.

If fixed is given explicitly but min and max are different or one is missing the length encoding is not valid.

§Examples
let schema = json!({
    "type": "string",
    "minLength": 2,
    "maxLength": 2
});
let schema = from_value::<StringSchema>(schema)?;
assert!(matches!(schema, StringSchema::Utf8 { length: LengthEncoding::Fixed(2) }));
let schema = json!({
    "type": "array",
    "minItems": 2,
    "lengthEncoding": { "@type": "fixed" },
    "items": { "type": "boolean" }
});
assert!(from_value::<ArraySchema>(schema).is_err());
§

LengthEncoded(IntegerSchema)

Length Encoded → "@type": "explicitlength".

Length encoded means that the length of the value encoded is encoded at the beginning of the field. How the length is encoded is defined via an integer schema.

§Example

let schema = json!({
    "type": "string",
    "lengthEncoding": {
        "@type": "explicitlength",
        "length": 1
    }
});

let mut scope = json_schema::Scope::new();
let j_schema = scope.compile_and_return(schema.clone(), false)?;
let schema = from_value::<DataSchema>(schema)?;

let value = json!("tree");
assert!(j_schema.validate(&value).is_valid());
let mut encoded = Vec::new();
schema.encode(&mut encoded, &value)?;
let expected = [ 4, b't', b'r', b'e', b'e' ];
assert_eq!(&expected, encoded.as_slice());

let mut encoded = std::io::Cursor::new(encoded);
let back = schema.decode(&mut encoded)?;
assert!(j_schema.validate(&back).is_valid());
assert_eq!(back, value);
§

EndPattern

End Pattern → "@type": "endpattern".

With End Pattern the end of a variable length string or array is marked by a sentinel value. The sentinel must be valid for the surrounding schema, i.e. for string schema it must adhere to the "format" and for array schema it must be valid for the "items" schema. Furthermore, for string schema the sentinel must be encoded as one byte, e.g. an ASCII letter or if "format": "binary" two hex-digits.

Note: The sentinel value is not allowed to be included in an encoded value!

Note2: The sentinel values should bot be used with arrays with numeric items. The sentinel is tested for equality so rounding errors may result in not being able to identify the sentinel!

§Examples

let schema = json!({
    "type": "string",
    "lengthEncoding": {
        "@type": "endpattern",
        "sentinel": "!"
    }
});

let mut scope = json_schema::Scope::new();
let j_schema = scope.compile_and_return(schema.clone(), false)?;
let schema = from_value::<DataSchema>(schema)?;

let value = json!("tree");
assert!(j_schema.validate(&value).is_valid());
let mut encoded = Vec::new();
schema.encode(&mut encoded, &value)?;
let expected = [ b't', b'r', b'e', b'e', b'!' ];
assert_eq!(&expected, encoded.as_slice());

let mut encoded = std::io::Cursor::new(encoded);
let back = schema.decode(&mut encoded)?;
assert!(j_schema.validate(&back).is_valid());
assert_eq!(back, value);
let schema = json!({
    "type": "string",
    "format": "binary",
    "lengthEncoding": {
        "@type": "endpattern",
        "sentinel": "00"
    }
});

let mut scope = json_schema::Scope::new();
let j_schema = scope.compile_and_return(schema.clone(), false)?;
let schema = from_value::<DataSchema>(schema)?;

let value = json!("beef");
assert!(j_schema.validate(&value).is_valid());
let mut encoded = Vec::new();
schema.encode(&mut encoded, &value)?;
let expected = [ 0xbe, 0xef, 0x00 ];
assert_eq!(&expected, encoded.as_slice());

let mut encoded = std::io::Cursor::new(encoded);
let back = schema.decode(&mut encoded)?;
assert!(j_schema.validate(&back).is_valid());
assert_eq!(back, value);
let schema = json!({
    "type": "array",
    "lengthEncoding": {
        "@type": "endpattern",
        "sentinel": false
    },
    "items": { "type": "boolean" }
});

let mut scope = json_schema::Scope::new();
let j_schema = scope.compile_and_return(schema.clone(), false)?;
let schema = from_value::<DataSchema>(schema)?;

let value = json!([ true, true, false ]);
let mut encoded = Vec::new();
// value contains the sentinel value `false`
assert!(schema.encode(&mut encoded, &value).is_err());

Fields

§sentinel: T
§

Capacity

Capacity → "@type": "capacity".

With capacity there is always a certain capacity reserved for the field in the encoded byte string. For string schemata the capacity is defined by "maxLength" where it refers to the maximal length of string that can be encoded. For array schemata "maxItems" defines the capacity.

Unused space is filled with "padding". The padding must fulfill the same requirements as the "sentinel" of end pattern.

A value may consume the whole reserved space. In this case no padding is inserted.

§Example

let schema = json!({
    "type": "string",
    "format": "binary",
    "maxLength": 8,
    "lengthEncoding": {
        "@type": "capacity",
        "padding": "00"
    }
});

let mut scope = json_schema::Scope::new();
let j_schema = scope.compile_and_return(schema.clone(), false)?;
let schema = from_value::<DataSchema>(schema)?;

let value = json!("beef");
assert!(j_schema.validate(&value).is_valid());
let mut encoded = Vec::new();
schema.encode(&mut encoded, &value)?;
let expected = [ 0xbe, 0xef, 0x00, 0x00 ];
assert_eq!(&expected, encoded.as_slice());

let mut encoded = std::io::Cursor::new(encoded);
let back = schema.decode(&mut encoded)?;
assert!(j_schema.validate(&back).is_valid());
assert_eq!(back, value);

Fields

§padding: T
§capacity: usize
§

TillEnd

Till End → "@type": "tillend".

Till End is the default length encoding. It simply means that the end of an array or string is determined by the end of the byte string. Accordingly, schemata with "tillend" length encoding are only allowed as the last property in an object schema.

Implementations§

Source§

impl<T> LengthEncoding<T>

Source

pub fn fixed(fixed: usize) -> Self

Source

pub fn length_encoded(schema: IntegerSchema) -> Self

Source

pub fn end_pattern(pattern: T) -> Self

Source

pub fn capacity(padding: T, capacity: usize) -> Self

Source

pub fn map<R, F>(self, f: F) -> LengthEncoding<R>
where F: FnOnce(T) -> R,

Source

pub fn try_map<R, E, F>(self, f: F) -> Result<LengthEncoding<R>, E>
where F: FnOnce(T) -> Result<R, E>,

Trait Implementations§

Source§

impl<T: Clone> Clone for LengthEncoding<T>

Source§

fn clone(&self) -> LengthEncoding<T>

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<T: Debug> Debug for LengthEncoding<T>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<T> Freeze for LengthEncoding<T>
where T: Freeze,

§

impl<T> RefUnwindSafe for LengthEncoding<T>
where T: RefUnwindSafe,

§

impl<T> Send for LengthEncoding<T>
where T: Send,

§

impl<T> Sync for LengthEncoding<T>
where T: Sync,

§

impl<T> Unpin for LengthEncoding<T>
where T: Unpin,

§

impl<T> UnwindSafe for LengthEncoding<T>
where T: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.