bnr_xfs/status/
position_capabilities.rs

1use std::{cmp, fmt};
2
3use crate::{create_xfs_bool, create_xfs_i4, impl_xfs_array, impl_xfs_struct, ShutterCmd, Size};
4
5use super::CdrPosition;
6
7pub const CDR_POS_CAP_LIST_LEN: usize = 2;
8
9create_xfs_bool!(
10    ShutterStatusSupported,
11    "shutterStatusSupported",
12    "Specifies whether shutter status reporting is supported."
13);
14create_xfs_bool!(
15    ContentStatusSupported,
16    "contentStatusSupported",
17    "Specifies whether there is a sensor to detect if the position is empty."
18);
19create_xfs_i4!(
20    MaxItems,
21    "maxItems",
22    "Maximum number of items which this position can hold."
23);
24create_xfs_bool!(
25    Input,
26    "input",
27    "Specifies whether this position can be used as source for an accept command."
28);
29create_xfs_bool!(
30    Output,
31    "output",
32    "Specifies whether this position can be used as target for a dispense command."
33);
34create_xfs_bool!(Rollback, "rollback", "Specifies whether this position can be used as target for[cash_in_rollback](crate::cash::cash_in_rollback) command.");
35create_xfs_bool!(Refusal, "refusal", "Specifies whether refused notes can be moved to this position during [cash_in](crate::cash::cash_in) command.");
36
37/// Characteristics of an input/output position.
38#[repr(C)]
39#[derive(Clone, Copy, Debug, Default, PartialEq, serde::Deserialize, serde::Serialize)]
40pub struct CdrPositionCapabilities {
41    /// Position fo the unit.
42    pub position: CdrPosition,
43    pub content_status_supported: ContentStatusSupported,
44    pub shutter_status_supported: ShutterStatusSupported,
45    /// Defines if the shutter has to be explicitly controlled by the application.
46    pub shutter_cmd: ShutterCmd,
47    pub max_items: MaxItems,
48    pub input: Input,
49    pub output: Output,
50    pub rollback: Rollback,
51    pub refusal: Refusal,
52}
53
54impl CdrPositionCapabilities {
55    /// Creates a new [CdrPositionCapabilities].
56    pub const fn new() -> Self {
57        Self {
58            position: CdrPosition::new(),
59            shutter_status_supported: ShutterStatusSupported::new(),
60            shutter_cmd: ShutterCmd::new(),
61            content_status_supported: ContentStatusSupported::new(),
62            max_items: MaxItems::new(),
63            input: Input::new(),
64            output: Output::new(),
65            rollback: Rollback::new(),
66            refusal: Refusal::new(),
67        }
68    }
69}
70
71impl fmt::Display for CdrPositionCapabilities {
72    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73        write!(f, "{{")?;
74        write!(f, r#""position":{},"#, self.position)?;
75        write!(
76            f,
77            r#""shutter_status_supported":{},"#,
78            self.shutter_status_supported
79        )?;
80        write!(f, r#""shutter_cmd":{},"#, self.shutter_cmd)?;
81        write!(
82            f,
83            r#""content_status_supported":{},"#,
84            self.content_status_supported
85        )?;
86        write!(f, r#""max_items":{},"#, self.max_items)?;
87        write!(f, r#""input":{},"#, self.input)?;
88        write!(f, r#""output":{},"#, self.output)?;
89        write!(f, r#""rollback":{},"#, self.rollback)?;
90        write!(f, r#""refusal":{}"#, self.refusal)?;
91        write!(f, "}}")
92    }
93}
94
95impl_xfs_struct!(
96    CdrPositionCapabilities,
97    "positionCapabilities",
98    [
99        position: CdrPosition,
100        shutter_status_supported: ShutterStatusSupported,
101        shutter_cmd: ShutterCmd,
102        content_status_supported: ContentStatusSupported,
103        max_items: MaxItems,
104        input: Input,
105        output: Output,
106        rollback: Rollback,
107        refusal: Refusal
108    ]
109);
110
111/// List of position capabilties.
112#[repr(C)]
113#[derive(Clone, Copy, Debug, Default, PartialEq, serde::Deserialize, serde::Serialize)]
114pub struct CdrPositionCapabilitiesList {
115    size: Size,
116    items: [CdrPositionCapabilities; CDR_POS_CAP_LIST_LEN],
117}
118
119impl CdrPositionCapabilitiesList {
120    /// Creates a new [CdrPositionCapabilitiesList].
121    pub const fn new() -> Self {
122        Self {
123            size: Size::new(),
124            items: [CdrPositionCapabilities::new(); CDR_POS_CAP_LIST_LEN],
125        }
126    }
127
128    /// Creates a new [CdrPositionCapabilitiesList] from the provided parameter.
129    pub const fn create(items: [CdrPositionCapabilities; CDR_POS_CAP_LIST_LEN]) -> Self {
130        Self {
131            size: Size::create(CDR_POS_CAP_LIST_LEN as u32),
132            items,
133        }
134    }
135
136    /// Gets the max size.
137    pub const fn max_size() -> usize {
138        CDR_POS_CAP_LIST_LEN
139    }
140
141    /// Gets the size.
142    pub const fn size(&self) -> u32 {
143        self.size.inner()
144    }
145
146    /// Sets the size.
147    pub fn set_size(&mut self, size: u32) {
148        if size as usize <= Self::max_size() {
149            self.size.set_inner(size);
150        }
151    }
152
153    /// Gets a reference to the [CdrPositionCapabilities] list.
154    pub fn items(&self) -> &[CdrPositionCapabilities] {
155        let len = self.size.inner() as usize;
156        if len <= Self::max_size() {
157            self.items[..len].as_ref()
158        } else {
159            self.items.as_ref()
160        }
161    }
162
163    /// Gets a reference to the [CdrPositionCapabilities] list.
164    pub fn items_mut(&mut self) -> &mut [CdrPositionCapabilities] {
165        let len = self.size.inner() as usize;
166        if len <= Self::max_size() {
167            self.items[..len].as_mut()
168        } else {
169            self.items.as_mut()
170        }
171    }
172
173    /// Sets the [CdrPositionCapabilities] list items.
174    pub fn set_items(&mut self, items: &[CdrPositionCapabilities]) {
175        let len = cmp::min(items.len(), Self::max_size());
176        self.items[..len].copy_from_slice(&items[..len]);
177        self.size.set_inner(len as u32);
178    }
179
180    /// Builder function that sets the [CdrPositionCapabilities] list items.
181    pub fn with_items(mut self, items: &[CdrPositionCapabilities]) -> Self {
182        self.set_items(items);
183        self
184    }
185}
186
187impl fmt::Display for CdrPositionCapabilitiesList {
188    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
189        write!(f, "[")?;
190
191        let items = self.items();
192        for (i, item) in items.iter().enumerate() {
193            if i != 0 {
194                write!(f, ",")?;
195            }
196            write!(f, "{item}")?;
197        }
198
199        write!(f, "]")
200    }
201}
202
203impl_xfs_array!(CdrPositionCapabilitiesList, "positionCapabilitiesList");
204
205#[cfg(test)]
206mod tests {
207    use super::*;
208    use crate::xfs::{
209        array::XfsArray,
210        value::XfsValue,
211        xfs_struct::{XfsMember, XfsStruct},
212    };
213    use crate::Result;
214
215    #[test]
216    fn test_cdr_position_capabitilities_xfs() -> Result<()> {
217        let exp_xfs = XfsMember::create(
218            CdrPositionCapabilitiesList::xfs_name(),
219            XfsValue::new().with_array(XfsArray::create([XfsValue::new().with_xfs_struct(
220                XfsStruct::create([
221                    XfsMember::create("position", XfsValue::new().with_i4(1)),
222                    XfsMember::create("contentStatusSupported", XfsValue::new().with_boolean(1)),
223                    XfsMember::create("shutterStatusSupported", XfsValue::new().with_boolean(0)),
224                    XfsMember::create("shutterCmd", XfsValue::new().with_boolean(0)),
225                    XfsMember::create("maxItems", XfsValue::new().with_i4(1)),
226                    XfsMember::create("input", XfsValue::new().with_boolean(1)),
227                    XfsMember::create("output", XfsValue::new().with_boolean(0)),
228                    XfsMember::create("rollback", XfsValue::new().with_boolean(0)),
229                    XfsMember::create("refusal", XfsValue::new().with_boolean(1)),
230                ]),
231            )])),
232        );
233        let exp_cap_list = CdrPositionCapabilitiesList {
234            size: Size::create(1),
235            items: [
236                CdrPositionCapabilities {
237                    position: CdrPosition::Top,
238                    shutter_status_supported: false.into(),
239                    shutter_cmd: false.into(),
240                    content_status_supported: true.into(),
241                    max_items: 1u32.into(),
242                    input: true.into(),
243                    output: false.into(),
244                    rollback: false.into(),
245                    refusal: true.into(),
246                },
247                CdrPositionCapabilities::new(),
248            ],
249        };
250
251        assert_eq!(
252            CdrPositionCapabilitiesList::try_from(&exp_xfs)?,
253            exp_cap_list
254        );
255
256        let xfs_list = XfsMember::from(exp_cap_list);
257        for (exp, item) in exp_xfs
258            .value()
259            .array()
260            .unwrap()
261            .data()
262            .iter()
263            .map(|m| m.inner().xfs_struct().unwrap())
264            .zip(
265                xfs_list
266                    .value()
267                    .array()
268                    .unwrap()
269                    .data()
270                    .iter()
271                    .map(|m| m.inner().xfs_struct().unwrap()),
272            )
273        {
274            assert_eq!(
275                exp.find_member(CdrPosition::xfs_name())?,
276                item.find_member(CdrPosition::xfs_name())?
277            );
278            assert_eq!(
279                exp.find_member(ShutterStatusSupported::xfs_name())?,
280                item.find_member(ShutterStatusSupported::xfs_name())?
281            );
282            assert_eq!(
283                exp.find_member(ShutterCmd::xfs_name())?,
284                item.find_member(ShutterCmd::xfs_name())?
285            );
286            assert_eq!(
287                exp.find_member(ContentStatusSupported::xfs_name())?,
288                item.find_member(ContentStatusSupported::xfs_name())?
289            );
290            assert_eq!(
291                exp.find_member(MaxItems::xfs_name())?,
292                item.find_member(MaxItems::xfs_name())?
293            );
294            assert_eq!(
295                exp.find_member(Input::xfs_name())?,
296                item.find_member(Input::xfs_name())?
297            );
298            assert_eq!(
299                exp.find_member(Output::xfs_name())?,
300                item.find_member(Output::xfs_name())?
301            );
302            assert_eq!(
303                exp.find_member(Rollback::xfs_name())?,
304                item.find_member(Rollback::xfs_name())?
305            );
306            assert_eq!(
307                exp.find_member(Refusal::xfs_name())?,
308                item.find_member(Refusal::xfs_name())?
309            );
310        }
311
312        Ok(())
313    }
314
315    #[test]
316    fn test_cdr_position_capabitilities_xfs_full() -> Result<()> {
317        let exp_xfs = XfsMember::create(
318            CdrPositionCapabilitiesList::xfs_name(),
319            XfsValue::new().with_array(XfsArray::create([
320                XfsValue::new().with_xfs_struct(XfsStruct::create([
321                    XfsMember::create("position", XfsValue::new().with_i4(1)),
322                    XfsMember::create("contentStatusSupported", XfsValue::new().with_boolean(1)),
323                    XfsMember::create("shutterStatusSupported", XfsValue::new().with_boolean(0)),
324                    XfsMember::create("shutterCmd", XfsValue::new().with_boolean(0)),
325                    XfsMember::create("maxItems", XfsValue::new().with_i4(1)),
326                    XfsMember::create("input", XfsValue::new().with_boolean(1)),
327                    XfsMember::create("output", XfsValue::new().with_boolean(0)),
328                    XfsMember::create("rollback", XfsValue::new().with_boolean(0)),
329                    XfsMember::create("refusal", XfsValue::new().with_boolean(1)),
330                ])),
331                XfsValue::new().with_xfs_struct(XfsStruct::create([
332                    XfsMember::create("position", XfsValue::new().with_i4(2)),
333                    XfsMember::create("contentStatusSupported", XfsValue::new().with_boolean(1)),
334                    XfsMember::create("shutterStatusSupported", XfsValue::new().with_boolean(1)),
335                    XfsMember::create("shutterCmd", XfsValue::new().with_boolean(1)),
336                    XfsMember::create("maxItems", XfsValue::new().with_i4(15)),
337                    XfsMember::create("input", XfsValue::new().with_boolean(0)),
338                    XfsMember::create("output", XfsValue::new().with_boolean(1)),
339                    XfsMember::create("rollback", XfsValue::new().with_boolean(1)),
340                    XfsMember::create("refusal", XfsValue::new().with_boolean(0)),
341                ])),
342            ])),
343        );
344
345        let exp_cap_list = CdrPositionCapabilitiesList {
346            size: Size::create(2),
347            items: [
348                CdrPositionCapabilities {
349                    position: CdrPosition::Top,
350                    content_status_supported: true.into(),
351                    shutter_status_supported: false.into(),
352                    shutter_cmd: false.into(),
353                    max_items: 1u32.into(),
354                    input: true.into(),
355                    output: false.into(),
356                    rollback: false.into(),
357                    refusal: true.into(),
358                },
359                CdrPositionCapabilities {
360                    position: CdrPosition::Bottom,
361                    content_status_supported: true.into(),
362                    shutter_status_supported: true.into(),
363                    shutter_cmd: true.into(),
364                    max_items: 15u32.into(),
365                    input: false.into(),
366                    output: true.into(),
367                    rollback: true.into(),
368                    refusal: false.into(),
369                },
370            ],
371        };
372
373        assert_eq!(
374            CdrPositionCapabilitiesList::try_from(&exp_xfs)?,
375            exp_cap_list
376        );
377
378        let xfs_list = XfsMember::from(exp_cap_list);
379        for (exp, item) in exp_xfs
380            .value()
381            .array()
382            .unwrap()
383            .data()
384            .iter()
385            .map(|m| m.inner().xfs_struct().unwrap())
386            .zip(
387                xfs_list
388                    .value()
389                    .array()
390                    .unwrap()
391                    .data()
392                    .iter()
393                    .map(|m| m.inner().xfs_struct().unwrap()),
394            )
395        {
396            assert_eq!(
397                exp.find_member(CdrPosition::xfs_name())?,
398                item.find_member(CdrPosition::xfs_name())?
399            );
400            assert_eq!(
401                exp.find_member(ShutterStatusSupported::xfs_name())?,
402                item.find_member(ShutterStatusSupported::xfs_name())?
403            );
404            assert_eq!(
405                exp.find_member(ShutterCmd::xfs_name())?,
406                item.find_member(ShutterCmd::xfs_name())?
407            );
408            assert_eq!(
409                exp.find_member(ContentStatusSupported::xfs_name())?,
410                item.find_member(ContentStatusSupported::xfs_name())?
411            );
412            assert_eq!(
413                exp.find_member(MaxItems::xfs_name())?,
414                item.find_member(MaxItems::xfs_name())?
415            );
416            assert_eq!(
417                exp.find_member(Input::xfs_name())?,
418                item.find_member(Input::xfs_name())?
419            );
420            assert_eq!(
421                exp.find_member(Output::xfs_name())?,
422                item.find_member(Output::xfs_name())?
423            );
424            assert_eq!(
425                exp.find_member(Rollback::xfs_name())?,
426                item.find_member(Rollback::xfs_name())?
427            );
428            assert_eq!(
429                exp.find_member(Refusal::xfs_name())?,
430                item.find_member(Refusal::xfs_name())?
431            );
432        }
433
434        Ok(())
435    }
436}