1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
use std::fmt;

use crate::xfs::method_response::XfsMethodResponse;
use crate::{impl_xfs_struct, Error, Result};

mod count;
mod counters;
mod lock;
mod logical_cash_unit;
mod number;
mod pcu_name;
mod physical_cash_unit;
mod status;
mod threshold;
mod unit_id;

pub use count::*;
pub use counters::*;
pub use lock::*;
pub use logical_cash_unit::*;
pub use number::*;
pub use pcu_name::*;
pub use physical_cash_unit::*;
pub use status::*;
pub use threshold::*;
pub use unit_id::*;

/// Represents a cash unit in a BNR device.
///
/// Describes the entire set of [LogicalCashUnit]s and [PhysicalCashUnit]s present on a device.
#[repr(C)]
#[derive(Clone, Debug, Default, PartialEq, serde::Deserialize, serde::Serialize)]
pub struct CashUnit {
    transport_count: TransportCount,
    logical_cash_unit_list: LogicalCashUnitList,
    physical_cash_unit_list: PhysicalCashUnitList,
}

impl CashUnit {
    /// Creates a new [CashUnit].
    pub fn new() -> Self {
        Self {
            transport_count: TransportCount::new(),
            logical_cash_unit_list: LogicalCashUnitList::new(),
            physical_cash_unit_list: PhysicalCashUnitList::new(),
        }
    }

    /// Gets the [TransportCount].
    pub const fn transport_count(&self) -> u32 {
        self.transport_count.inner()
    }

    /// Sets the [TransportCount].
    pub fn set_transport_count(&mut self, count: u32) {
        self.transport_count.set_inner(count);
    }

    /// Builder function that sets the [TransportCount].
    pub fn with_transport_count(mut self, count: u32) -> Self {
        self.set_transport_count(count);
        self
    }

    /// Gets a reference to the [LogicalCashUnitList].
    pub const fn logical_cash_unit_list(&self) -> &LogicalCashUnitList {
        &self.logical_cash_unit_list
    }

    /// Gets a mutable reference to the [LogicalCashUnitList].
    pub fn logical_cash_unit_list_mut(&mut self) -> &mut LogicalCashUnitList {
        &mut self.logical_cash_unit_list
    }

    /// Sets the [LogicalCashUnitList].
    pub fn set_logical_cash_unit_list(&mut self, lcu: LogicalCashUnitList) {
        self.logical_cash_unit_list = lcu;
    }

    /// Builder function that sets the [LogicalCashUnitList].
    pub fn with_logical_cash_unit_list(mut self, lcu: LogicalCashUnitList) -> Self {
        self.set_logical_cash_unit_list(lcu);
        self
    }

    /// Gets a reference to the [PhysicalCashUnitList].
    pub const fn physical_cash_unit_list(&self) -> &PhysicalCashUnitList {
        &self.physical_cash_unit_list
    }

    /// Sets the [PhysicalCashUnitList].
    pub fn set_physical_cash_unit_list(&mut self, pcu: PhysicalCashUnitList) {
        self.physical_cash_unit_list = pcu;
    }

    /// Builder function that sets the [PhysicalCashUnitList].
    pub fn with_physical_cash_unit_list(mut self, pcu: PhysicalCashUnitList) -> Self {
        self.set_physical_cash_unit_list(pcu);
        self
    }

    /// Deconstructs the [CashUnit] into a [LogicalCashUnitList] and [PhysicalCashUnitList].
    pub fn into_lists(self) -> (LogicalCashUnitList, PhysicalCashUnitList) {
        (self.logical_cash_unit_list, self.physical_cash_unit_list)
    }
}

impl fmt::Display for CashUnit {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{{")?;
        write!(f, r#""transport_count":{},"#, self.transport_count)?;
        write!(
            f,
            r#""logical_cash_unit_list":{},"#,
            self.logical_cash_unit_list
        )?;
        write!(
            f,
            r#""physical_cash_unit_list":{}"#,
            self.physical_cash_unit_list
        )?;
        write!(f, "}}")
    }
}

impl_xfs_struct!(
    CashUnit,
    "cashUnit",
    [
        transport_count: TransportCount,
        logical_cash_unit_list: LogicalCashUnitList,
        physical_cash_unit_list: PhysicalCashUnitList
    ]
);

impl TryFrom<&XfsMethodResponse> for CashUnit {
    type Error = Error;

    fn try_from(val: &XfsMethodResponse) -> Result<Self> {
        val.as_params()?
            .params()
            .iter()
            .map(|m| m.inner())
            .find(|m| m.value().xfs_struct().is_some())
            .ok_or(Error::Xfs(format!(
                "Expected CashUnit XfsMethodResponse, have: {val}"
            )))?
            .value()
            .try_into()
    }
}

impl TryFrom<XfsMethodResponse> for CashUnit {
    type Error = Error;

    fn try_from(val: XfsMethodResponse) -> Result<Self> {
        (&val).try_into()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::xfs;

    #[test]
    fn test_parse_cash_unit() -> Result<()> {
        let unit_xml = include_bytes!("../tests/xml/query-cash-unit.xml");
        let unit_xml_str = std::str::from_utf8(unit_xml.as_ref())?;

        let res = xfs::from_str::<xfs::method_response::XfsMethodResponseStruct>(unit_xml_str)?;
        let _cash_unit = CashUnit::try_from(res.inner())?;

        Ok(())
    }
}