1use 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}