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);
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>
impl<T> LengthEncoding<T>
pub fn fixed(fixed: usize) -> Self
pub fn length_encoded(schema: IntegerSchema) -> Self
pub fn end_pattern(pattern: T) -> Self
pub fn capacity(padding: T, capacity: usize) -> Self
pub fn map<R, F>(self, f: F) -> LengthEncoding<R>where
F: FnOnce(T) -> R,
pub fn try_map<R, E, F>(self, f: F) -> Result<LengthEncoding<R>, E>
Trait Implementations§
Source§impl<T: Clone> Clone for LengthEncoding<T>
impl<T: Clone> Clone for LengthEncoding<T>
Source§fn clone(&self) -> LengthEncoding<T>
fn clone(&self) -> LengthEncoding<T>
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read more