binary_data_schema/
boolean.rs

1//! Implementation of the boolean schema.
2//!
3//! By default [BooleanSchema] encode the Boolean values `true` and `false` to one byte.
4//! However, internally it only targets a single bit.
5//! This allows BDS to recognize [BooleanSchema] as [bitfields].
6//!
7//! # Parameters
8//!
9//! | Key           | Type   | Default | Comment |
10//! | ------------- | ------:| -------:| ------- |
11//! | `"bitoffset"` | `uint` |       0 | Number of bits the [bitfield] is shifted |
12//! | `"length"`    | `uint` |       1 | Number of bytes the field encodes |
13//!
14//! _Note:_ If the [BooleanSchema] is part of a merged [bitfield] its length must match the other bitfields.
15//!
16//! ## Validation
17//!
18//! Like for every other [bitfield] the `"bitoffset"` must not exceed the field's
19//! length, i.e.:
20//!
21//! ```text
22//! "bitoffset" + 1 <= "length" * 8
23//! ```
24//!
25//! _Note:_ The width ([`"bits"`]) of a [BooleanSchema] is always 1.
26//!
27//! # Example
28//!
29//! All parameters of [BooleanSchema] has default values.
30//! Accordingly, an empty schema is valid.
31//!
32//! ```
33//! # use binary_data_schema::*;
34//! # use valico::json_schema;
35//! # use serde_json::{json, from_value};
36//! let schema = json!({ "type": "boolean" });
37//!
38//! let mut scope = json_schema::Scope::new();
39//! let j_schema = scope.compile_and_return(schema.clone(), false)?;
40//! let schema = from_value::<DataSchema>(schema)?;
41//!
42//! let value = json!(true);
43//! assert!(j_schema.validate(&value).is_valid());
44//! let mut encoded = Vec::new();
45//! schema.encode(&mut encoded, &value)?;
46//! # let expected = [1];
47//! # assert_eq!(&expected, encoded.as_slice());
48//!
49//! let mut encoded = std::io::Cursor::new(encoded);
50//! let back = schema.decode(&mut encoded)?;
51//! assert!(j_schema.validate(&back).is_valid());
52//! assert_eq!(back, value);
53//! # Ok::<(), anyhow::Error>(())
54//! ```
55//!
56//! [bitfields]: ../object/index.html#bitfields
57//! [bitfield]: ../object/index.html#bitfields
58//! [`"bits"`]: ../integer/index.html#parameters
59
60use std::{convert::TryFrom, io};
61
62use byteorder::{ReadBytesExt, WriteBytesExt};
63use serde::{
64    de::{Deserializer, Error as DeError},
65    Deserialize,
66};
67use serde_json::Value;
68
69use crate::{integer::Bitfield, Decoder, Encoder};
70
71/// Default length of boolean schemata.
72pub const DEFAULT_LENGTH: usize = 1;
73
74/// Errors validating a [BooleanSchema].
75#[derive(Debug, thiserror::Error)]
76pub enum ValidationError {
77    #[error(transparent)]
78    InvalidBitAddressing(#[from] crate::integer::ValidationError),
79}
80
81/// Errors encoding a string with a [BooleanSchema].
82#[derive(Debug, thiserror::Error)]
83pub enum EncodingError {
84    #[error("The value '{value}' can not be encoded with a boolean schema")]
85    InvalidValue { value: String },
86    #[error("Failed to encode flag: {0}")]
87    Bitfield(#[from] crate::integer::EncodingError),
88}
89
90/// Errors decoding a string with a [BooleanSchema].
91#[derive(Debug, thiserror::Error)]
92pub enum DecodingError {
93    #[error("Failed to decode flag: {0}")]
94    Bitfield(#[from] crate::integer::DecodingError),
95}
96
97impl DecodingError {
98    pub fn due_to_eof(&self) -> bool {
99        match &self {
100            Self::Bitfield(e) => e.due_to_eof(),
101        }
102    }
103}
104
105/// Raw version of a Boolean schema. May hold invalid invariants.
106#[derive(Debug, Copy, Clone, Deserialize)]
107#[serde(rename_all = "lowercase")]
108struct RawBoolean {
109    #[serde(default = "BooleanSchema::default_length")]
110    length: usize,
111    #[serde(default, rename = "bitoffset")]
112    offset: usize,
113}
114
115/// The Boolean schema describes a Boolean value (further information on [the module's documentation](index.html)).
116///
117/// Boolean schemata always describe a bitfield with a width of 1 bit.
118#[derive(Debug, Clone)]
119pub struct BooleanSchema {
120    pub(crate) bf: Bitfield,
121}
122
123impl BooleanSchema {
124    pub fn default_length() -> usize {
125        DEFAULT_LENGTH
126    }
127    pub fn length(&self) -> usize {
128        self.bf.bytes()
129    }
130}
131
132impl From<Bitfield> for BooleanSchema {
133    fn from(bf: Bitfield) -> Self {
134        Self { bf }
135    }
136}
137
138impl TryFrom<RawBoolean> for BooleanSchema {
139    type Error = ValidationError;
140
141    fn try_from(raw: RawBoolean) -> Result<Self, Self::Error> {
142        let bf = Bitfield::new(raw.length, 1, raw.offset)?;
143
144        Ok(bf.into())
145    }
146}
147
148impl<'de> Deserialize<'de> for BooleanSchema {
149    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
150    where
151        D: Deserializer<'de>,
152    {
153        let raw = RawBoolean::deserialize(deserializer)?;
154        BooleanSchema::try_from(raw).map_err(D::Error::custom)
155    }
156}
157
158impl Encoder for BooleanSchema {
159    type Error = EncodingError;
160
161    fn encode<W>(&self, target: &mut W, value: &Value) -> Result<usize, Self::Error>
162    where
163        W: io::Write + WriteBytesExt,
164    {
165        let value = value.as_bool().ok_or_else(|| EncodingError::InvalidValue {
166            value: value.to_string(),
167        })?;
168        let int = if value { 1 } else { 0 };
169        let written = self.bf.encode(target, &int.into())?;
170
171        Ok(written)
172    }
173}
174
175impl Decoder for BooleanSchema {
176    type Error = DecodingError;
177
178    fn decode<R>(&self, target: &mut R) -> Result<Value, Self::Error>
179    where
180        R: io::Read + ReadBytesExt,
181    {
182        let int = self
183            .bf
184            .decode(target)?
185            .as_u64()
186            .expect("always u64 from BF");
187        let b = int != 0;
188        Ok(b.into())
189    }
190}
191
192#[cfg(test)]
193mod test {
194    use super::*;
195    use anyhow::Result;
196    use serde_json::{from_value, json};
197
198    #[test]
199    fn default() -> Result<()> {
200        let schema = json!({});
201        let b = from_value::<BooleanSchema>(schema)?;
202        let mut buf = [0];
203        assert_eq!(1, b.encode(&mut buf.as_mut(), &json!(true))?);
204        assert_eq!(1, buf[0]);
205
206        Ok(())
207    }
208
209    #[test]
210    fn bit3_byte2() -> Result<()> {
211        let schema = json!({
212            "bitoffset": 11,
213            "length": 2
214        });
215        let b = from_value::<BooleanSchema>(schema)?;
216        let mut buf = [0, 0];
217        assert_eq!(2, b.encode(&mut buf.as_mut(), &json!(true))?);
218        assert_eq!(1 << 3, buf[0]);
219        assert_eq!(0, buf[1]);
220        assert_eq!(2, b.encode(&mut buf.as_mut(), &json!(false))?);
221        assert_eq!(0, buf[0]);
222        assert_eq!(0, buf[1]);
223
224        Ok(())
225    }
226}