cameleon_genapi/
string_reg.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use crate::GenApiError;
6
7use super::{
8    interface::{INode, IRegister, IString},
9    node_base::{NodeAttributeBase, NodeBase},
10    register_base::RegisterBase,
11    store::{CacheStore, NodeStore, ValueStore},
12    Device, GenApiResult, ValueCtxt,
13};
14
15#[derive(Debug, Clone)]
16pub struct StringRegNode {
17    pub(crate) attr_base: NodeAttributeBase,
18    pub(crate) register_base: RegisterBase,
19}
20
21impl StringRegNode {
22    #[must_use]
23    pub fn register_base(&self) -> &RegisterBase {
24        &self.register_base
25    }
26}
27
28impl INode for StringRegNode {
29    fn node_base(&self) -> NodeBase {
30        let elem_base = &self.register_base.elem_base;
31        NodeBase::new(&self.attr_base, elem_base)
32    }
33
34    fn streamable(&self) -> bool {
35        self.register_base().streamable()
36    }
37}
38
39impl IString for StringRegNode {
40    #[tracing::instrument(skip(self, device, store, cx),
41                          level = "trace",
42                          fields(node = store.name_by_id(self.node_base().id()).unwrap()))]
43    fn value<T: ValueStore, U: CacheStore>(
44        &self,
45        device: &mut impl Device,
46        store: &impl NodeStore,
47        cx: &mut ValueCtxt<T, U>,
48    ) -> GenApiResult<String> {
49        let nid = self.node_base().id();
50        let reg = self.register_base();
51        reg.with_cache_or_read(nid, device, store, cx, |data| {
52            let str_end = data.iter().position(|b| *b == 0).unwrap_or(data.len());
53            Ok(String::from_utf8_lossy(&data[..str_end]).to_string())
54        })
55    }
56
57    #[tracing::instrument(skip(self, device, store, cx),
58                          level = "trace",
59                          fields(node = store.name_by_id(self.node_base().id()).unwrap()))]
60    fn set_value<T: ValueStore, U: CacheStore>(
61        &self,
62        value: String,
63        device: &mut impl Device,
64        store: &impl NodeStore,
65        cx: &mut ValueCtxt<T, U>,
66    ) -> GenApiResult<()> {
67        let max_length = self.max_length(device, store, cx)? as usize;
68        if !value.is_ascii() {
69            return Err(GenApiError::invalid_data(
70                "the data must be an ascii string".into(),
71            ));
72        }
73        if value.len() > max_length {
74            return Err(GenApiError::invalid_data(
75                "the data length exceeds the maximum length allowed by the node.".into(),
76            ));
77        }
78
79        let nid = self.node_base().id();
80        cx.invalidate_cache_by(nid);
81
82        let reg = self.register_base();
83        let mut bytes = value.into_bytes();
84        bytes.resize(max_length, 0);
85        reg.write_and_cache(nid, &bytes, device, store, cx)
86    }
87
88    #[tracing::instrument(skip(self, device, store, cx),
89                          level = "trace",
90                          fields(node = store.name_by_id(self.node_base().id()).unwrap()))]
91    fn max_length<T: ValueStore, U: CacheStore>(
92        &self,
93        device: &mut impl Device,
94        store: &impl NodeStore,
95        cx: &mut ValueCtxt<T, U>,
96    ) -> GenApiResult<i64> {
97        self.length(device, store, cx)
98    }
99
100    #[tracing::instrument(skip(self, device, store, cx),
101                          level = "trace",
102                          fields(node = store.name_by_id(self.node_base().id()).unwrap()))]
103    fn is_readable<T: ValueStore, U: CacheStore>(
104        &self,
105        device: &mut impl Device,
106        store: &impl NodeStore,
107        cx: &mut ValueCtxt<T, U>,
108    ) -> GenApiResult<bool> {
109        self.register_base().is_readable(device, store, cx)
110    }
111
112    #[tracing::instrument(skip(self, device, store, cx),
113                          level = "trace",
114                          fields(node = store.name_by_id(self.node_base().id()).unwrap()))]
115    fn is_writable<T: ValueStore, U: CacheStore>(
116        &self,
117        device: &mut impl Device,
118        store: &impl NodeStore,
119        cx: &mut ValueCtxt<T, U>,
120    ) -> GenApiResult<bool> {
121        self.register_base().is_writable(device, store, cx)
122    }
123}
124
125impl IRegister for StringRegNode {
126    fn read<T: ValueStore, U: CacheStore>(
127        &self,
128        buf: &mut [u8],
129        device: &mut impl Device,
130        store: &impl NodeStore,
131        cx: &mut ValueCtxt<T, U>,
132    ) -> GenApiResult<()> {
133        let address = self.address(device, store, cx)?;
134        let length = self.length(device, store, cx)?;
135        self.register_base().read_and_cache(
136            self.node_base().id(),
137            address,
138            length,
139            buf,
140            device,
141            store,
142            cx,
143        )
144    }
145
146    fn write<T: ValueStore, U: CacheStore>(
147        &self,
148        buf: &[u8],
149        device: &mut impl Device,
150        store: &impl NodeStore,
151        cx: &mut ValueCtxt<T, U>,
152    ) -> GenApiResult<()> {
153        self.register_base()
154            .write_and_cache(self.node_base().id(), buf, device, store, cx)
155    }
156
157    fn address<T: ValueStore, U: CacheStore>(
158        &self,
159        device: &mut impl Device,
160        store: &impl NodeStore,
161        cx: &mut ValueCtxt<T, U>,
162    ) -> GenApiResult<i64> {
163        self.register_base().address(device, store, cx)
164    }
165
166    fn length<T: ValueStore, U: CacheStore>(
167        &self,
168        device: &mut impl Device,
169        store: &impl NodeStore,
170        cx: &mut ValueCtxt<T, U>,
171    ) -> GenApiResult<i64> {
172        self.register_base().length(device, store, cx)
173    }
174}