use crate::map_decoder;
use core::num::NonZeroU32;
use minicbor::decode::{Decode, Decoder, Error};
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Fluid<'buffer> {
pub name: &'buffer str,
pub label: &'buffer str,
pub amount: NonZeroU32,
pub has_tag: bool,
}
impl<'buffer, Context> Decode<'buffer, Context> for Fluid<'buffer> {
fn decode(d: &mut Decoder<'buffer>, context: &mut Context) -> Result<Self, Error> {
match OptionFluid::decode(d, context)?.into() {
Some(f) => Ok(f),
None => Err(Error::message("missing fluid")),
}
}
}
#[allow(clippy::module_name_repetitions)]
#[derive(Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[repr(transparent)]
pub struct OptionFluid<'buffer>(pub Option<Fluid<'buffer>>);
impl<'buffer, Context> Decode<'buffer, Context> for OptionFluid<'buffer> {
fn decode(d: &mut Decoder<'buffer>, context: &mut Context) -> Result<Self, Error> {
map_decoder::decode_nullable::<OptionFluidBuilder<'buffer>, Context>(d, context)
}
}
impl<'buffer> From<OptionFluid<'buffer>> for Option<Fluid<'buffer>> {
fn from(x: OptionFluid<'buffer>) -> Option<Fluid<'buffer>> {
x.0
}
}
#[derive(Clone, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct OptionFluidBuilder<'buffer> {
name: Option<&'buffer str>,
label: Option<&'buffer str>,
amount: Option<u32>,
has_tag: Option<bool>,
}
impl<'buffer> map_decoder::Builder<'buffer> for OptionFluidBuilder<'buffer> {
type Output = OptionFluid<'buffer>;
fn entry<Context>(
&mut self,
key: &str,
d: &mut Decoder<'buffer>,
_: &mut Context,
) -> Result<bool, Error> {
match key {
"name" => {
self.name = Some(d.str()?);
Ok(true)
}
"label" => {
self.label = Some(d.str()?);
Ok(true)
}
"amount" => {
self.amount = Some(d.u32()?);
Ok(true)
}
"hasTag" => {
self.has_tag = Some(d.bool()?);
Ok(true)
}
_ => Ok(false),
}
}
fn build(self) -> Result<Self::Output, Error> {
if let Some(name) = self.name {
if let Some(label) = self.label {
if let Some(amount) = self.amount {
if let Some(amount) = NonZeroU32::new(amount) {
if let Some(has_tag) = self.has_tag {
return Ok(OptionFluid(Some(Fluid {
name,
label,
amount,
has_tag,
})));
}
}
}
}
}
if (self.name, self.label, self.amount, self.has_tag) == (None, None, None, None) {
return Ok(OptionFluid(None));
}
if self.amount == Some(0) {
return Ok(OptionFluid(None));
}
Err(minicbor::decode::Error::message("missing key in fluid"))
}
}
impl<'buffer> map_decoder::NullableBuilder<'buffer> for OptionFluidBuilder<'buffer> {
fn build_null() -> OptionFluid<'buffer> {
OptionFluid(None)
}
}
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Tank<'buffer> {
pub fluid: Option<Fluid<'buffer>>,
pub capacity: u32,
}
impl<'buffer, Context> Decode<'buffer, Context> for Tank<'buffer> {
fn decode(d: &mut Decoder<'buffer>, context: &mut Context) -> Result<Self, Error> {
map_decoder::decode::<TankBuilder<'buffer>, Context>(d, context)
}
}
#[derive(Clone, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct TankBuilder<'buffer> {
fluid: OptionFluidBuilder<'buffer>,
capacity: Option<u32>,
}
impl<'buffer> map_decoder::Builder<'buffer> for TankBuilder<'buffer> {
type Output = Tank<'buffer>;
fn entry<Context>(
&mut self,
key: &'buffer str,
d: &mut Decoder<'buffer>,
context: &mut Context,
) -> Result<bool, Error> {
match key {
"capacity" => {
self.capacity = Some(d.u32()?);
Ok(true)
}
_ => self.fluid.entry(key, d, context),
}
}
fn build(self) -> Result<Self::Output, Error> {
if let Some(capacity) = self.capacity {
Ok(Tank {
fluid: self.fluid.build()?.into(),
capacity,
})
} else {
Err(Error::message("missing key in tank"))
}
}
}