Skip to main content

rustbac_core/services/
list_element.rs

1use crate::apdu::ConfirmedRequestHeader;
2use crate::encoding::{
3    primitives::{encode_ctx_object_id, encode_ctx_unsigned},
4    tag::Tag,
5    writer::Writer,
6};
7use crate::services::value_codec::encode_application_data_value;
8use crate::types::{DataValue, ObjectId, PropertyId};
9use crate::EncodeError;
10
11pub const SERVICE_ADD_LIST_ELEMENT: u8 = 0x08;
12pub const SERVICE_REMOVE_LIST_ELEMENT: u8 = 0x09;
13
14#[derive(Debug, Clone, PartialEq)]
15pub struct AddListElementRequest<'a> {
16    pub object_id: ObjectId,
17    pub property_id: PropertyId,
18    pub array_index: Option<u32>,
19    pub elements: &'a [DataValue<'a>],
20    pub invoke_id: u8,
21}
22
23impl<'a> AddListElementRequest<'a> {
24    pub fn encode(&self, w: &mut Writer<'_>) -> Result<(), EncodeError> {
25        encode_list_element_request(w, self, SERVICE_ADD_LIST_ELEMENT)
26    }
27}
28
29#[derive(Debug, Clone, PartialEq)]
30pub struct RemoveListElementRequest<'a> {
31    pub object_id: ObjectId,
32    pub property_id: PropertyId,
33    pub array_index: Option<u32>,
34    pub elements: &'a [DataValue<'a>],
35    pub invoke_id: u8,
36}
37
38impl<'a> RemoveListElementRequest<'a> {
39    pub fn encode(&self, w: &mut Writer<'_>) -> Result<(), EncodeError> {
40        encode_list_element_request(
41            w,
42            &AddListElementRequest {
43                object_id: self.object_id,
44                property_id: self.property_id,
45                array_index: self.array_index,
46                elements: self.elements,
47                invoke_id: self.invoke_id,
48            },
49            SERVICE_REMOVE_LIST_ELEMENT,
50        )
51    }
52}
53
54fn encode_list_element_request(
55    w: &mut Writer<'_>,
56    req: &AddListElementRequest<'_>,
57    service_choice: u8,
58) -> Result<(), EncodeError> {
59    ConfirmedRequestHeader {
60        segmented: false,
61        more_follows: false,
62        segmented_response_accepted: false,
63        max_segments: 0,
64        max_apdu: 5,
65        invoke_id: req.invoke_id,
66        sequence_number: None,
67        proposed_window_size: None,
68        service_choice,
69    }
70    .encode(w)?;
71    encode_ctx_object_id(w, 0, req.object_id.raw())?;
72    encode_ctx_unsigned(w, 1, req.property_id.to_u32())?;
73    if let Some(array_index) = req.array_index {
74        encode_ctx_unsigned(w, 2, array_index)?;
75    }
76    Tag::Opening { tag_num: 3 }.encode(w)?;
77    for value in req.elements {
78        encode_application_data_value(w, value)?;
79    }
80    Tag::Closing { tag_num: 3 }.encode(w)?;
81    Ok(())
82}
83
84#[cfg(test)]
85mod tests {
86    use super::{
87        AddListElementRequest, RemoveListElementRequest, SERVICE_ADD_LIST_ELEMENT,
88        SERVICE_REMOVE_LIST_ELEMENT,
89    };
90    use crate::apdu::ConfirmedRequestHeader;
91    use crate::encoding::{reader::Reader, writer::Writer};
92    use crate::types::{DataValue, ObjectId, ObjectType, PropertyId};
93
94    #[test]
95    fn encode_add_list_element_request() {
96        let values = [DataValue::Unsigned(1), DataValue::Unsigned(2)];
97        let req = AddListElementRequest {
98            object_id: ObjectId::new(ObjectType::AnalogValue, 1),
99            property_id: PropertyId::Proprietary(512),
100            array_index: None,
101            elements: &values,
102            invoke_id: 7,
103        };
104        let mut buf = [0u8; 128];
105        let mut w = Writer::new(&mut buf);
106        req.encode(&mut w).unwrap();
107        let mut r = Reader::new(w.as_written());
108        let hdr = ConfirmedRequestHeader::decode(&mut r).unwrap();
109        assert_eq!(hdr.service_choice, SERVICE_ADD_LIST_ELEMENT);
110    }
111
112    #[test]
113    fn encode_remove_list_element_request() {
114        let values = [DataValue::Enumerated(3)];
115        let req = RemoveListElementRequest {
116            object_id: ObjectId::new(ObjectType::TrendLog, 1),
117            property_id: PropertyId::Proprietary(513),
118            array_index: None,
119            elements: &values,
120            invoke_id: 8,
121        };
122        let mut buf = [0u8; 128];
123        let mut w = Writer::new(&mut buf);
124        req.encode(&mut w).unwrap();
125        let mut r = Reader::new(w.as_written());
126        let hdr = ConfirmedRequestHeader::decode(&mut r).unwrap();
127        assert_eq!(hdr.service_choice, SERVICE_REMOVE_LIST_ELEMENT);
128    }
129}