use core::convert::Infallible;
use alloc::{boxed::Box, vec, vec::Vec};
use crate::codec::{
CodecError, DataFormat, DataHeader, Decodable, Encodable, Format, ReadsDecodable,
UnexpectedDataFormatSnafu, WritesEncodable,
};
pub mod binary;
pub mod cryptography;
pub mod dynamic;
pub mod list;
pub mod map;
pub mod number;
mod text;
pub use dynamic::Unspecified;
pub use text::*;
#[non_exhaustive]
#[derive(Default, Debug, Clone, PartialEq)]
pub enum Type {
#[default]
Unspecified,
U8,
U16,
U32,
U64,
I8,
I16,
I32,
I64,
F32,
F64,
Bool,
Text,
Data(DataType),
List(Box<Type>),
Map(Box<(Type, Type)>),
}
impl Type {
pub const fn ordinal(&self) -> u8 {
match self {
Type::Unspecified => 0,
Type::U8 => 255,
Type::U16 => 254,
Type::U32 => 253,
Type::U64 => 252,
Type::I8 => 251,
Type::I16 => 250,
Type::I32 => 249,
Type::I64 => 248,
Type::F32 => 247,
Type::F64 => 246,
Type::Bool => 245,
Type::Text => 244,
Type::Data(data) => data.format.as_data_format().ordinal,
Type::List(_) => 243,
Type::Map(_) => 242,
}
}
pub fn from_ordinal(ordinal: u8) -> Option<Self> {
match ordinal {
0 => Some(Type::Unspecified),
255 => Some(Type::U8),
254 => Some(Type::U16),
253 => Some(Type::U32),
252 => Some(Type::U64),
251 => Some(Type::I8),
250 => Some(Type::I16),
249 => Some(Type::I32),
248 => Some(Type::I64),
247 => Some(Type::F32),
246 => Some(Type::F64),
245 => Some(Type::Bool),
244 => Some(Type::Text),
243 => Some(Type::List(Type::Unspecified.into())),
242 => Some(Type::Map((Type::Unspecified, Type::Unspecified).into())),
_ => None,
}
}
pub const fn format(&self) -> Format {
match self {
Type::Unspecified => Format::Fluid,
Type::U8 => u8::FORMAT,
Type::U16 => u16::FORMAT,
Type::U32 => u32::FORMAT,
Type::U64 => u64::FORMAT,
Type::I8 => i8::FORMAT,
Type::I16 => i16::FORMAT,
Type::I32 => i32::FORMAT,
Type::I64 => i64::FORMAT,
Type::F32 => f32::FORMAT,
Type::F64 => f64::FORMAT,
Type::Bool => bool::FORMAT,
Type::Text => Text::FORMAT,
Type::Data(data) => data.format,
Type::List(typing) => typing.format().as_data_format().as_format(),
Type::Map(..) => DataFormat {
blob_size: 0,
data_fields: 2,
ordinal: 0,
}
.as_format(),
}
}
pub fn from_name(name: &str) -> Option<Self> {
match name {
"unspecified" => Some(Type::Unspecified),
"u8" => Some(Type::U8),
"u16" => Some(Type::U16),
"u32" => Some(Type::U32),
"u64" => Some(Type::U64),
"i8" => Some(Type::I8),
"i16" => Some(Type::I16),
"i32" => Some(Type::I32),
"i64" => Some(Type::I64),
"f32" => Some(Type::F32),
"f64" => Some(Type::F64),
"bool" => Some(Type::Bool),
"text" => Some(Type::Text),
_ => None,
}
}
}
#[derive(Default, Debug, Clone, PartialEq)]
pub struct Coda {
pub global_name: Text,
pub local_name: Text,
pub docs: Option<Text>,
pub(crate) data: Vec<DataType>,
}
impl Coda {
pub fn new(global_name: Text, local_name: Text, docs: Option<Text>, data: &[DataType]) -> Self {
Self {
global_name,
local_name,
docs,
data: Vec::from(data),
}
}
pub fn iter(&self) -> impl Iterator<Item = &DataType> {
self.data.iter()
}
#[cfg(feature = "parse")]
pub(crate) fn type_from_name(&self, name: &str) -> Option<Type> {
for data in self.data.iter() {
if data.name.eq_ignore_ascii_case(name) {
return Some(Type::Data(data.clone()));
}
}
Type::from_name(name)
}
}
#[derive(Default, Debug, Clone, PartialEq)]
pub struct DataType {
pub name: Text,
pub docs: Option<Text>,
blob_fields: Vec<DataField>,
data_fields: Vec<DataField>,
format: Format,
}
impl DataType {
pub fn new(
name: Text,
docs: Option<Text>,
ordinal: u8,
blob_fields: &[DataField],
data_fields: &[DataField],
) -> Self {
let mut format = Format::data(ordinal);
let mut i = 0;
while i < blob_fields.len() {
let field = &blob_fields[i];
format = format.with(field.typing.format());
i += 1;
}
let mut i = 0;
while i < data_fields.len() {
let field = &data_fields[i];
format = format.with(field.typing.format());
i += 1;
}
Self {
name,
docs,
blob_fields: Vec::from(blob_fields),
data_fields: Vec::from(data_fields),
format,
}
}
pub const fn new_fluid(name: Text, docs: Option<Text>) -> Self {
Self {
name,
docs,
blob_fields: vec![],
data_fields: vec![],
format: Format::Fluid,
}
}
pub fn iter(&self) -> impl Iterator<Item = &DataField> {
self.blob_fields.iter().chain(self.data_fields.iter())
}
pub fn with(mut self, field: DataField) -> Self {
if matches!(self.format, Format::Fluid) {
todo!("it should be an error to add fields to a type defined as fluid")
}
let field_format = field.typing.format();
if field.optional {
let boxed_format = Format::data(0).with(field_format);
self.format = self.format.with(boxed_format);
self.data_fields.push(field);
} else {
self.format = self.format.with(field_format);
match field_format {
Format::Blob(..) => {
self.blob_fields.push(field);
}
Format::Data(..) | Format::Fluid => {
self.data_fields.push(field);
}
};
}
self
}
pub const fn format(&self) -> &Format {
&self.format
}
}
#[derive(Default, Clone, Debug, PartialEq)]
pub struct DataField {
pub name: Text,
pub docs: Option<Text>,
pub typing: Type,
pub optional: bool,
pub flattened: bool,
}
pub trait TryAsFormat<D> {
type Error;
fn try_as_format(&self) -> Result<&D, Self::Error>;
}
impl<T> TryAsFormat<T> for T {
type Error = Infallible;
fn try_as_format(&self) -> Result<&T, Self::Error> {
Ok(self)
}
}
impl Encodable for Type {
const FORMAT: Format = Format::Fluid;
fn encode(&self, writer: &mut (impl WritesEncodable + ?Sized)) -> Result<(), CodecError> {
match self {
Type::Data(typing) => writer.write_data(typing),
Type::List(typing) => writer.write_data(typing.as_ref()),
Type::Map(typing) => {
writer.write_data(&typing.as_ref().0)?;
writer.write_data(&typing.as_ref().1)?;
Ok(())
}
_ => Ok(()),
}
}
fn encode_header(
&self,
writer: &mut (impl WritesEncodable + ?Sized),
) -> Result<(), CodecError> {
let format = match self {
Type::Map(_) => Format::data(self.ordinal())
.with(Type::FORMAT)
.with(Type::FORMAT)
.as_data_format(),
Type::Data(..) | Type::List(_) => Format::data(self.ordinal())
.with(Type::FORMAT)
.as_data_format(),
_ => Format::data(self.ordinal()).as_data_format(),
};
DataHeader { count: 1, format }.encode(writer)
}
}
impl Decodable for Type {
fn decode(
&mut self,
reader: &mut (impl ReadsDecodable + ?Sized),
header: Option<DataHeader>,
) -> Result<(), CodecError> {
let header = header.ok_or_else(|| {
UnexpectedDataFormatSnafu {
expected: Self::FORMAT,
actual: None::<DataHeader>,
}
.build()
})?;
if header.count != 1 {
return UnexpectedDataFormatSnafu {
expected: Self::FORMAT,
actual: Some(header),
}
.fail();
}
match Type::from_ordinal(header.format.ordinal) {
Some(Type::List(_)) => {
if header.format.blob_size != 0 || header.format.data_fields != 1 {
return UnexpectedDataFormatSnafu {
expected: Self::FORMAT,
actual: Some(header),
}
.fail();
}
let mut typing = Type::default();
reader.read_data_into(&mut typing)?;
*self = Type::List(typing.into());
}
Some(Type::Map(_)) => {
if header.format.blob_size != 0 || header.format.data_fields != 2 {
return UnexpectedDataFormatSnafu {
expected: Self::FORMAT,
actual: Some(header),
}
.fail();
}
let mut key_typing = Type::default();
reader.read_data_into(&mut key_typing)?;
let mut value_typing = Type::default();
reader.read_data_into(&mut value_typing)?;
*self = Type::Map((key_typing, value_typing).into());
}
Some(simple) => {
if header.format.blob_size != 0 || header.format.data_fields != 0 {
return UnexpectedDataFormatSnafu {
expected: Self::FORMAT,
actual: Some(header),
}
.fail();
}
*self = simple;
}
None => {
if header.format.blob_size != 0 || header.format.data_fields != 1 {
return UnexpectedDataFormatSnafu {
expected: Self::FORMAT,
actual: Some(header),
}
.fail();
}
let mut typing = DataType::default();
reader.read_data_into(&mut typing)?;
*self = Type::Data(typing);
}
}
Ok(())
}
}
impl Encodable for Coda {
const FORMAT: crate::codec::Format = Format::data(0)
.with(Text::FORMAT)
.with(Text::FORMAT)
.with(Text::FORMAT)
.with(Vec::<DataType>::FORMAT);
fn encode(
&self,
writer: &mut (impl crate::codec::WritesEncodable + ?Sized),
) -> Result<(), crate::codec::CodecError> {
writer.write_data(&self.global_name)?;
writer.write_data(&self.local_name)?;
writer.write_data(&self.docs)?;
writer.write_data(&self.data)?;
Ok(())
}
}
impl Decodable for Coda {
fn decode(
&mut self,
reader: &mut (impl crate::codec::ReadsDecodable + ?Sized),
header: Option<crate::codec::DataHeader>,
) -> Result<(), crate::codec::CodecError> {
let _ = Self::ensure_header(header, &[0])?;
reader.read_data_into(&mut self.global_name)?;
reader.read_data_into(&mut self.local_name)?;
reader.read_data_into(&mut self.docs)?;
reader.read_data_into(&mut self.data)?;
Ok(())
}
}
impl Encodable for DataType {
const FORMAT: Format = Format::data(0)
.with(Text::FORMAT)
.with(Option::<Text>::FORMAT)
.with(Vec::<DataField>::FORMAT)
.with(Vec::<DataField>::FORMAT)
.with(Format::FORMAT);
fn encode(&self, writer: &mut (impl WritesEncodable + ?Sized)) -> Result<(), CodecError> {
writer.write_data(&self.name)?;
writer.write_data(&self.docs)?;
writer.write_data(&self.blob_fields)?;
writer.write_data(&self.data_fields)?;
writer.write_data(&self.format)?;
Ok(())
}
}
impl Decodable for DataType {
fn decode(
&mut self,
reader: &mut (impl ReadsDecodable + ?Sized),
header: Option<DataHeader>,
) -> Result<(), CodecError> {
let _ = Self::ensure_header(header, &[0])?;
reader.read_data_into(&mut self.name)?;
reader.read_data_into(&mut self.docs)?;
reader.read_data_into(&mut self.blob_fields)?;
reader.read_data_into(&mut self.data_fields)?;
reader.read_data_into(&mut self.format)?;
Ok(())
}
}
impl Encodable for DataField {
const FORMAT: Format = Format::data(0)
.with(bool::FORMAT)
.with(bool::FORMAT)
.with(Text::FORMAT)
.with(Option::<Text>::FORMAT)
.with(Type::FORMAT);
fn encode(&self, writer: &mut (impl WritesEncodable + ?Sized)) -> Result<(), CodecError> {
writer.write_data(&self.optional)?;
writer.write_data(&self.flattened)?;
writer.write_data(&self.name)?;
writer.write_data(&self.docs)?;
writer.write_data(&self.typing)?;
Ok(())
}
}
impl Decodable for DataField {
fn decode(
&mut self,
reader: &mut (impl ReadsDecodable + ?Sized),
header: Option<DataHeader>,
) -> Result<(), CodecError> {
let _ = Self::ensure_header(header, &[0])?;
reader.read_data_into(&mut self.optional)?;
reader.read_data_into(&mut self.flattened)?;
reader.read_data_into(&mut self.name)?;
reader.read_data_into(&mut self.docs)?;
reader.read_data_into(&mut self.typing)?;
Ok(())
}
}
impl<T> Encodable for Option<T>
where
T: Default + Encodable + 'static,
{
const FORMAT: Format = Format::data(0).with(T::FORMAT);
fn encode(&self, writer: &mut (impl WritesEncodable + ?Sized)) -> Result<(), CodecError> {
match self {
None => Ok(()),
Some(value) => writer.write_data(value),
}
}
fn encode_header(
&self,
writer: &mut (impl WritesEncodable + ?Sized),
) -> Result<(), CodecError> {
DataHeader {
count: if self.is_some() { 1 } else { 0 },
format: if self.is_some() {
Self::FORMAT.as_data_format()
} else {
DataFormat::default()
},
}
.encode(writer)
}
}
impl<T> Decodable for Option<T>
where
T: Decodable + Default + 'static,
{
fn decode(
&mut self,
reader: &mut (impl ReadsDecodable + ?Sized),
header: Option<DataHeader>,
) -> Result<(), CodecError> {
let h = header.ok_or_else(|| {
UnexpectedDataFormatSnafu {
expected: Self::FORMAT,
actual: None::<DataHeader>,
}
.build()
})?;
if h.count > 1 {
return UnexpectedDataFormatSnafu {
expected: Self::FORMAT,
actual: Some(h),
}
.fail();
}
if h.count == 0 {
if h.format != DataFormat::default() {
return UnexpectedDataFormatSnafu {
expected: Self::FORMAT,
actual: Some(h),
}
.fail();
}
*self = None;
} else {
if h.format != Self::FORMAT.as_data_format() {
return UnexpectedDataFormatSnafu {
expected: Self::FORMAT,
actual: Some(h),
}
.fail();
}
let mut value = T::default();
reader.read_data_into(&mut value)?;
*self = Some(value);
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use crate::codec::{Decodable, WritesEncodable};
use super::*;
#[derive(Clone, Debug, Default, PartialEq)]
pub struct TestData {
pub number: i32,
pub floaty: f64,
pub text_list: Vec<Text>,
pub text: Text,
pub nested: NestedTestData,
pub two_d: Vec<Vec<Text>>,
}
impl TestData {
pub fn typing() -> DataType {
let blob_fields = vec![
DataField {
name: Text::from("number"),
docs: None,
typing: Type::I32,
optional: false,
flattened: false,
},
DataField {
name: Text::from("floaty"),
docs: None,
typing: Type::F64,
optional: false,
flattened: false,
},
];
let data_fields = vec![
DataField {
name: Text::from("text_list"),
docs: None,
typing: Type::List(Type::Text.into()),
optional: false,
flattened: false,
},
DataField {
name: Text::from("text"),
docs: None,
typing: Type::Text,
optional: false,
flattened: false,
},
DataField {
name: Text::from("nested"),
docs: None,
typing: Type::Data(NestedTestData::typing()),
optional: false,
flattened: false,
},
DataField {
name: Text::from("two_d"),
docs: None,
typing: Type::List(Type::List(Type::Text.into()).into()),
optional: false,
flattened: false,
},
];
let typing = DataType::new(Text::from("Testdata"), None, 1, &blob_fields, &data_fields);
assert_eq!(Self::FORMAT, *typing.format());
typing
}
}
impl Encodable for TestData {
const FORMAT: Format = Format::data(1)
.with(i32::FORMAT)
.with(f64::FORMAT)
.with(Vec::<Text>::FORMAT)
.with(Text::FORMAT)
.with(NestedTestData::FORMAT)
.with(Vec::<Vec<Text>>::FORMAT);
fn encode(&self, writer: &mut (impl WritesEncodable + ?Sized)) -> Result<(), CodecError> {
writer.write_data(&self.number)?;
writer.write_data(&self.floaty)?;
writer.write_data(&self.text_list)?;
writer.write_data(&self.text)?;
writer.write_data(&self.nested)?;
writer.write_data(&self.two_d)?;
Ok(())
}
}
impl Decodable for TestData {
fn decode(
&mut self,
reader: &mut (impl ReadsDecodable + ?Sized),
header: Option<DataHeader>,
) -> Result<(), CodecError> {
let _ = Self::ensure_header(header, &[1])?;
reader.read_data_into(&mut self.number)?;
reader.read_data_into(&mut self.floaty)?;
reader.read_data_into(&mut self.text_list)?;
reader.read_data_into(&mut self.text)?;
reader.read_data_into(&mut self.nested)?;
reader.read_data_into(&mut self.two_d)?;
Ok(())
}
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct NestedTestData {
pub boolean: bool,
}
impl NestedTestData {
pub fn typing() -> DataType {
let blob_fields = vec![DataField {
name: Text::from("boolean"),
docs: None,
typing: Type::Bool,
optional: false,
flattened: false,
}];
let data_fields = vec![];
let typing = DataType::new(
Text::from("NestedTestdata"),
None,
2,
&blob_fields,
&data_fields,
);
assert_eq!(Self::FORMAT, *typing.format());
typing
}
}
impl Encodable for NestedTestData {
const FORMAT: Format = Format::data(2).with(bool::FORMAT);
fn encode(&self, writer: &mut (impl WritesEncodable + ?Sized)) -> Result<(), CodecError> {
writer.write_data(&self.boolean)?;
Ok(())
}
}
impl Decodable for NestedTestData {
fn decode(
&mut self,
reader: &mut (impl ReadsDecodable + ?Sized),
header: Option<DataHeader>,
) -> Result<(), CodecError> {
let _ = Self::ensure_header(header, &[2])?;
reader.read_data_into(&mut self.boolean)?;
Ok(())
}
}
#[test]
pub fn data_type_codec() {
let data_type = TestData::typing();
let mut encoded_data_type = vec![];
encoded_data_type.write_data(&data_type).unwrap();
let decoded_data_type = encoded_data_type.as_slice().read_data().unwrap();
assert_eq!(data_type, decoded_data_type);
}
#[test]
fn codes_unstructured_optionals() {
let option: Option<u32> = Some(1337u32);
let mut data = vec![];
data.write_data(&option).expect("encoded");
println!("encoded");
let decoded_option = data.as_slice().read_data().expect("decoded");
assert_eq!(option, decoded_option);
let option: Option<u32> = None;
let mut data = vec![];
data.write_data(&option).expect("encoded");
let decoded_option = data.as_slice().read_data().expect("decoded");
assert_eq!(option, decoded_option);
let option: Option<u32> = Some(0);
let mut data = vec![];
data.write_data(&option).expect("encoded");
let decoded_option: Option<u32> = data.as_slice().read_data().expect("decoded");
assert_eq!(Some(0), decoded_option);
}
#[test]
fn codes_structured_optionals() {
let option: Option<Text> = Some("Hello, World!".into());
let mut data = vec![];
data.write_data(&option).expect("encoded");
println!("encoded");
let decoded_option = data.as_slice().read_data().expect("decoded");
assert_eq!(option, decoded_option);
let option: Option<Text> = None;
let mut data = vec![];
data.write_data(&option).expect("encoded");
let decoded_option = data.as_slice().read_data().expect("decoded");
assert_eq!(option, decoded_option);
let option: Option<Text> = Some("".into());
let mut data = vec![];
data.write_data(&option).expect("encoded");
let decoded_option: Option<Text> = data.as_slice().read_data().expect("decoded");
assert_eq!(Some("".into()), decoded_option);
}
#[test]
fn codes_nested_optionals() {
let option: Option<Option<u32>> = None;
let mut data = vec![];
data.write_data(&option).expect("encoded");
let decoded: Option<Option<u32>> = data.as_slice().read_data().expect("decoded");
assert_eq!(option, decoded);
let option: Option<Option<u32>> = Some(None);
let mut data = vec![];
data.write_data(&option).expect("encoded");
let decoded: Option<Option<u32>> = data.as_slice().read_data().expect("decoded");
assert_eq!(option, decoded);
let option: Option<Option<u32>> = Some(Some(0));
let mut data = vec![];
data.write_data(&option).expect("encoded");
let decoded: Option<Option<u32>> = data.as_slice().read_data().expect("decoded");
assert_eq!(option, decoded);
let option: Option<Option<u32>> = Some(Some(42));
let mut data = vec![];
data.write_data(&option).expect("encoded");
let decoded: Option<Option<u32>> = data.as_slice().read_data().expect("decoded");
assert_eq!(option, decoded);
}
#[test]
fn codes_optional_vec() {
let option: Option<Vec<u16>> = None;
let mut data = vec![];
data.write_data(&option).expect("encoded");
let decoded: Option<Vec<u16>> = data.as_slice().read_data().expect("decoded");
assert_eq!(option, decoded);
let option: Option<Vec<u16>> = Some(vec![]);
let mut data = vec![];
data.write_data(&option).expect("encoded");
let decoded: Option<Vec<u16>> = data.as_slice().read_data().expect("decoded");
assert_eq!(option, decoded);
let option: Option<Vec<u16>> = Some(vec![42]);
let mut data = vec![];
data.write_data(&option).expect("encoded");
let decoded: Option<Vec<u16>> = data.as_slice().read_data().expect("decoded");
assert_eq!(option, decoded);
}
#[test]
fn ordinal_round_trip() {
for ordinal in 0..=255u8 {
if let Some(typ) = Type::from_ordinal(ordinal) {
assert_eq!(
ordinal,
typ.ordinal(),
"from_ordinal({ordinal}) returned {typ:?} with ordinal {}",
typ.ordinal()
);
}
}
}
}