epics_ca/types/
value.rs

1use super::{EpicsEnum, EpicsString, FieldId};
2use std::{fmt::Debug, mem::MaybeUninit, ptr};
3
4/// Field of the channel.
5///
6/// # Safety
7///
8/// Should be implemented only for types supported by channel access.
9pub unsafe trait Field: Copy + Send + Sized + 'static + Debug {
10    /// Raw field structure.
11    type Raw: Copy + Send + Sized + 'static;
12    /// Field type identifier.
13    const ID: FieldId;
14
15    type StsRaw: Copy + Send + Sized + 'static;
16    type TimeRaw: Copy + Send + Sized + 'static;
17    type GrRaw: Copy + Send + Sized + 'static;
18    type CtrlRaw: Copy + Send + Sized + 'static;
19
20    type __StsPad: Copy + Send + Sized + 'static + Debug;
21    type __TimePad: Copy + Send + Sized + 'static + Debug;
22    type __GrPad: Copy + Send + Sized + 'static + Debug;
23    type __CtrlPad: Copy + Send + Sized + 'static + Debug;
24}
25/// Integral field.
26pub trait Int: Field {}
27// Floating-point field.
28pub trait Float: Field {}
29
30unsafe impl Field for u8 {
31    type Raw = u8;
32    const ID: FieldId = FieldId::Char;
33
34    type StsRaw = sys::dbr_sts_char;
35    type TimeRaw = sys::dbr_time_char;
36    type GrRaw = sys::dbr_gr_char;
37    type CtrlRaw = sys::dbr_ctrl_char;
38
39    type __StsPad = [MaybeUninit<u8>; 1];
40    type __TimePad = [MaybeUninit<u8>; 3];
41    type __GrPad = [MaybeUninit<u8>; 1];
42    type __CtrlPad = [MaybeUninit<u8>; 1];
43}
44impl Int for u8 {}
45
46unsafe impl Field for i16 {
47    type Raw = i16;
48    const ID: FieldId = FieldId::Short;
49
50    type StsRaw = sys::dbr_sts_short;
51    type TimeRaw = sys::dbr_time_short;
52    type GrRaw = sys::dbr_gr_short;
53    type CtrlRaw = sys::dbr_ctrl_short;
54
55    type __StsPad = ();
56    type __TimePad = [MaybeUninit<u8>; 2];
57    type __GrPad = ();
58    type __CtrlPad = ();
59}
60impl Int for i16 {}
61
62unsafe impl Field for EpicsEnum {
63    type Raw = u16;
64    const ID: FieldId = FieldId::Enum;
65
66    type StsRaw = sys::dbr_sts_enum;
67    type TimeRaw = sys::dbr_time_enum;
68    type GrRaw = sys::dbr_gr_enum;
69    type CtrlRaw = sys::dbr_ctrl_enum;
70
71    type __StsPad = ();
72    type __TimePad = [MaybeUninit<u8>; 2];
73    type __GrPad = ();
74    type __CtrlPad = ();
75}
76
77unsafe impl Field for i32 {
78    type Raw = i32;
79    const ID: FieldId = FieldId::Long;
80
81    type StsRaw = sys::dbr_sts_long;
82    type TimeRaw = sys::dbr_time_long;
83    type GrRaw = sys::dbr_gr_long;
84    type CtrlRaw = sys::dbr_ctrl_long;
85
86    type __StsPad = ();
87    type __TimePad = ();
88    type __GrPad = ();
89    type __CtrlPad = ();
90}
91impl Int for i32 {}
92
93unsafe impl Field for f32 {
94    type Raw = f32;
95    const ID: FieldId = FieldId::Float;
96
97    type StsRaw = sys::dbr_sts_float;
98    type TimeRaw = sys::dbr_time_float;
99    type GrRaw = sys::dbr_gr_float;
100    type CtrlRaw = sys::dbr_ctrl_float;
101
102    type __StsPad = ();
103    type __TimePad = ();
104    type __GrPad = ();
105    type __CtrlPad = ();
106}
107impl Float for f32 {}
108
109unsafe impl Field for f64 {
110    type Raw = f64;
111    const ID: FieldId = FieldId::Double;
112
113    type StsRaw = sys::dbr_sts_double;
114    type TimeRaw = sys::dbr_time_double;
115    type GrRaw = sys::dbr_gr_double;
116    type CtrlRaw = sys::dbr_ctrl_double;
117
118    type __StsPad = [MaybeUninit<u8>; 4];
119    type __TimePad = [MaybeUninit<u8>; 4];
120    type __GrPad = ();
121    type __CtrlPad = ();
122}
123impl Float for f64 {}
124
125unsafe impl Field for EpicsString {
126    type Raw = sys::epicsOldString;
127    const ID: FieldId = FieldId::String;
128
129    type StsRaw = sys::dbr_sts_string;
130    type TimeRaw = sys::dbr_time_string;
131    type GrRaw = sys::dbr_sts_string;
132    type CtrlRaw = sys::dbr_sts_string;
133
134    type __StsPad = ();
135    type __TimePad = ();
136    type __GrPad = ();
137    type __CtrlPad = ();
138}
139
140/// Value of the channel.
141///
142/// Consists of single or many items.
143///
144/// # Safety
145///
146/// Should be implemented only for types that represented in memory as [Self::Item].
147#[allow(clippy::len_without_is_empty)]
148pub unsafe trait Value: Send + 'static {
149    /// Type of the item.
150    type Item: Field;
151
152    /// Length of the value.
153    fn len(&self) -> usize;
154    /// Check that provided length allowed for `Self`.
155    #[must_use]
156    fn check_len(count: usize) -> bool;
157    /// Create pointer (possibly wide) to value from raw pointer.
158    fn cast_ptr(ptr: *const u8, len: usize) -> *const Self;
159}
160
161unsafe impl<T: Field> Value for T {
162    type Item = T;
163
164    fn len(&self) -> usize {
165        1
166    }
167    fn check_len(count: usize) -> bool {
168        count == 1
169    }
170    fn cast_ptr(ptr: *const u8, _: usize) -> *const Self {
171        ptr as *const Self
172    }
173}
174
175unsafe impl<T: Field> Value for [T] {
176    type Item = T;
177
178    fn len(&self) -> usize {
179        self.len()
180    }
181    fn check_len(_: usize) -> bool {
182        true
183    }
184    fn cast_ptr(ptr: *const u8, len: usize) -> *const Self {
185        ptr::slice_from_raw_parts(ptr as *const T, len)
186    }
187}
188
189#[cfg(test)]
190mod tests {
191    use super::*;
192    use std::mem::{align_of, size_of};
193
194    fn assert_layout<T: Field>() {
195        assert_eq!(size_of::<T>(), size_of::<T::Raw>());
196        assert_eq!(align_of::<T>(), align_of::<T::Raw>());
197    }
198
199    #[test]
200    fn layout() {
201        assert_layout::<u8>();
202        assert_layout::<i16>();
203        assert_layout::<EpicsEnum>();
204        assert_layout::<i32>();
205        assert_layout::<f32>();
206        assert_layout::<f64>();
207        assert_layout::<EpicsString>();
208    }
209}