1use crate::map_decoder;
2use core::num::NonZeroU32;
3use minicbor::decode::{Decode, Decoder, Error};
4
5#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
10pub struct Fluid<'buffer> {
11 pub name: &'buffer str,
15
16 pub label: &'buffer str,
20
21 pub amount: NonZeroU32,
23
24 pub has_tag: bool,
26}
27
28impl<'buffer, Context> Decode<'buffer, Context> for Fluid<'buffer> {
29 fn decode(d: &mut Decoder<'buffer>, context: &mut Context) -> Result<Self, Error> {
30 match OptionFluid::decode(d, context)?.into() {
31 Some(f) => Ok(f),
32 None => Err(Error::message("missing fluid")),
33 }
34 }
35}
36
37#[allow(clippy::module_name_repetitions)]
46#[derive(Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
47#[repr(transparent)]
48pub struct OptionFluid<'buffer>(pub Option<Fluid<'buffer>>);
49
50impl<'buffer, Context> Decode<'buffer, Context> for OptionFluid<'buffer> {
51 fn decode(d: &mut Decoder<'buffer>, context: &mut Context) -> Result<Self, Error> {
52 map_decoder::decode_nullable::<OptionFluidBuilder<'buffer>, Context>(d, context)
53 }
54}
55
56impl<'buffer> From<OptionFluid<'buffer>> for Option<Fluid<'buffer>> {
57 fn from(x: OptionFluid<'buffer>) -> Option<Fluid<'buffer>> {
58 x.0
59 }
60}
61
62#[derive(Clone, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
64pub struct OptionFluidBuilder<'buffer> {
65 name: Option<&'buffer str>,
69
70 label: Option<&'buffer str>,
74
75 amount: Option<u32>,
77
78 has_tag: Option<bool>,
80}
81
82impl<'buffer> map_decoder::Builder<'buffer> for OptionFluidBuilder<'buffer> {
83 type Output = OptionFluid<'buffer>;
84
85 fn entry<Context>(
86 &mut self,
87 key: &str,
88 d: &mut Decoder<'buffer>,
89 _: &mut Context,
90 ) -> Result<bool, Error> {
91 match key {
92 "name" => {
93 self.name = Some(d.str()?);
94 Ok(true)
95 }
96 "label" => {
97 self.label = Some(d.str()?);
98 Ok(true)
99 }
100 "amount" => {
101 self.amount = Some(d.u32()?);
102 Ok(true)
103 }
104 "hasTag" => {
105 self.has_tag = Some(d.bool()?);
106 Ok(true)
107 }
108 _ => Ok(false),
109 }
110 }
111
112 fn build(self) -> Result<Self::Output, Error> {
113 if let Some(name) = self.name {
115 if let Some(label) = self.label {
116 if let Some(amount) = self.amount {
117 if let Some(amount) = NonZeroU32::new(amount) {
118 if let Some(has_tag) = self.has_tag {
119 return Ok(OptionFluid(Some(Fluid {
120 name,
121 label,
122 amount,
123 has_tag,
124 })));
125 }
126 }
127 }
128 }
129 }
130
131 if (self.name, self.label, self.amount, self.has_tag) == (None, None, None, None) {
133 return Ok(OptionFluid(None));
134 }
135
136 if self.amount == Some(0) {
138 return Ok(OptionFluid(None));
139 }
140
141 Err(minicbor::decode::Error::message("missing key in fluid"))
143 }
144}
145
146impl<'buffer> map_decoder::NullableBuilder<'buffer> for OptionFluidBuilder<'buffer> {
147 fn build_null() -> OptionFluid<'buffer> {
148 OptionFluid(None)
149 }
150}
151
152#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
157pub struct Tank<'buffer> {
158 pub fluid: Option<Fluid<'buffer>>,
160
161 pub capacity: u32,
163}
164
165impl<'buffer, Context> Decode<'buffer, Context> for Tank<'buffer> {
166 fn decode(d: &mut Decoder<'buffer>, context: &mut Context) -> Result<Self, Error> {
167 map_decoder::decode::<TankBuilder<'buffer>, Context>(d, context)
168 }
169}
170
171#[derive(Clone, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
173pub struct TankBuilder<'buffer> {
174 fluid: OptionFluidBuilder<'buffer>,
176
177 capacity: Option<u32>,
179}
180
181impl<'buffer> map_decoder::Builder<'buffer> for TankBuilder<'buffer> {
182 type Output = Tank<'buffer>;
183
184 fn entry<Context>(
185 &mut self,
186 key: &'buffer str,
187 d: &mut Decoder<'buffer>,
188 context: &mut Context,
189 ) -> Result<bool, Error> {
190 match key {
191 "capacity" => {
192 self.capacity = Some(d.u32()?);
193 Ok(true)
194 }
195 _ => self.fluid.entry(key, d, context),
196 }
197 }
198
199 fn build(self) -> Result<Self::Output, Error> {
200 if let Some(capacity) = self.capacity {
201 Ok(Tank {
204 fluid: self.fluid.build()?.into(),
205 capacity,
206 })
207 } else {
208 Err(Error::message("missing key in tank"))
210 }
211 }
212}