Skip to main content

tango/server/
def.rs

1//! Definition of a device model and of its interface: its commands and its attributes.
2
3use std::time::{Duration, SystemTime};
4use std::ops::{Bound, RangeBounds};
5use std::fmt::{self, Debug};
6use std::future::Future;
7use std::borrow::Cow;
8use std::sync::Arc;
9
10use futures::future::BoxFuture;
11
12use crate::dev::{AttrConfig, AttrDeltaConfig, AttrMemorized, AttrNumber, AttrQuality, AttrRangeConfig, AttrRead, DevState, DisplayLevel};
13use crate::value::{AttrData, AttrDataFormat, AttrDataKind, CommandData, CommandDataKind, FromValue, IntoValue, Value};
14use crate::error::Result;
15
16use super::{reserved_name, Model, RESERVED_ATTRS, RESERVED_COMMANDS, STATE_NAME, STATUS_NAME};
17use super::attr::{unsupported, unsupported_prop};
18use super::dev::Dev;
19
20
21/// Merge a data kind being defined with the one already defined, if any, and give the
22/// kind to keep. Both are compatible when they are equal, which is what allows a kind to
23/// be both derived from a handler and given explicitly, in any order. Anything else is a
24/// contradiction in the definition and therefore panics.
25#[track_caller]
26fn merge_kind<K: PartialEq + Debug>(def: &str, what: &str, current: Option<K>, new: K) -> K {
27    match current {
28        Some(current) if current != new => panic!(
29            "{def}: the {what} is already defined as {current:?}, incompatible with {new:?}"),
30        _ => new,
31    }
32}
33
34/// Merge a data format being defined with the one already defined, if any, and give the
35/// format to keep. Both are compatible when they have the same layout, their maximum
36/// dimensions being merged with [`merge_max`], anything else panics.
37#[track_caller]
38fn merge_format(def: &str, current: Option<AttrDataFormat>, new: AttrDataFormat) -> AttrDataFormat {
39    let Some(current) = current else { return new };
40    match (&current, &new) {
41        (AttrDataFormat::Scalar, AttrDataFormat::Scalar) => AttrDataFormat::Scalar,
42        (AttrDataFormat::Spectrum(cur), AttrDataFormat::Spectrum(new)) => {
43            AttrDataFormat::Spectrum(merge_max(def, "maximum size", *cur, *new))
44        }
45        (AttrDataFormat::Image(cur_x, cur_y), AttrDataFormat::Image(new_x, new_y)) => {
46            AttrDataFormat::Image(
47                merge_max(def, "maximum width", *cur_x, *new_x),
48                merge_max(def, "maximum height", *cur_y, *new_y),
49            )
50        }
51        _ => panic!(
52            "{def}: the data format is already defined as {current:?}, incompatible with {new:?}"),
53    }
54}
55
56/// Merge two maximum dimensions of a data format, zero standing for an undefined maximum
57/// and therefore being compatible with any other value. Two different defined maximums
58/// are a contradiction in the definition and therefore panic.
59#[track_caller]
60fn merge_max(def: &str, what: &str, current: usize, new: usize) -> usize {
61    match (current, new) {
62        (0, new) => new,
63        (current, 0) => current,
64        (current, new) if current != new => panic!(
65            "{def}: the {what} is already defined as {current}, incompatible with {new}"),
66        (current, _) => current,
67    }
68}
69
70/// The two bounds of a range being defined, either of which is absent for a bound that is
71/// left open, which is how an attribute says it has no minimum or no maximum rather than
72/// having one it never reaches.
73#[track_caller]
74fn range_config<T, R>(def: &str, what: &str, range: R) -> AttrRangeConfig
75where
76    T: Into<AttrNumber> + Copy,
77    R: RangeBounds<T>,
78{
79    AttrRangeConfig {
80        min: bound_value(def, what, range.start_bound()),
81        max: bound_value(def, what, range.end_bound()),
82    }
83}
84
85/// A single bound of such a range, as the number the attribute holds: a range written with
86/// integer bounds gives integer limits, one written with floating bounds gives floating
87/// ones, and it is up to the definition to bound an attribute with its own kind of number.
88///
89/// An exclusive bound has no representation in Tango, the bounds being values a client
90/// compares against, so it is refused rather than silently taken for the inclusive one it
91/// is not.
92#[track_caller]
93fn bound_value<T>(def: &str, what: &str, bound: Bound<&T>) -> Option<AttrNumber>
94where
95    T: Into<AttrNumber> + Copy,
96{
97    match bound {
98        Bound::Included(value) => Some((*value).into()),
99        Bound::Unbounded => None,
100        Bound::Excluded(_) => panic!(
101            "{def}: the {what} cannot have an exclusive bound, Tango only has inclusive ones"),
102    }
103}
104
105/// A placeholder shown by [`Debug`] in place of a handler, a closure having nothing to
106/// show about itself.
107struct HandlerDebug;
108
109impl Debug for HandlerDebug {
110    #[inline]
111    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112        f.write_str("..")
113    }
114}
115
116/// Implement [`Debug`] for the handler enums, showing which access to the model the
117/// handler takes and whether it is asynchronous, which is all there is to show about it.
118macro_rules! impl_handler_debug {
119    ($($handler:ident),* $(,)?) => { $(
120        impl<M: Model> Debug for $handler<M> {
121            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122                f.write_str(match self {
123                    Self::SharedSync(_) => "SharedSync(..)",
124                    Self::ExclusiveSync(_) => "ExclusiveSync(..)",
125                    Self::SharedAsync(_) => "SharedAsync(..)",
126                    Self::ExclusiveAsync(_) => "ExclusiveAsync(..)",
127                })
128            }
129        }
130    )* };
131}
132
133impl_handler_debug!(StateFn, StatusFn, ExecFn, ReadFn, WriteFn);
134
135/// A builder for defining a device model and interface.
136pub struct ClassDef<M: Model> {
137    /// The name of the device class.
138    pub(super) name: Cow<'static, str>,
139    /// The description every device of that class gives of itself, which is what the
140    /// description request of a device answers.
141    pub(super) doc: Cow<'static, str>,
142    /// Where the documentation of that class is, which is what a client browsing the
143    /// control system opens when it is asked to show what a device is. Absent for a class
144    /// that documents itself nowhere, which is what a client is then told.
145    pub(super) doc_url: Option<Cow<'static, str>>,
146    /// The function building the model when the device is initialized.
147    pub(super) init: InitFn<M>,
148    /// The function called when the device is deleted, given the model back.
149    pub(super) delete: Option<DeleteFn<M>>,
150    /// The function giving the state of the device, absent to always give [`DevState::On`].
151    pub(super) state: Option<StateFn<M>>,
152    /// The function giving the status of the device, absent to always give "Device is on".
153    pub(super) status: Option<StatusFn<M>>,
154    /// The commands every device of that class has, which is the usual way of defining
155    /// one: a device is given all of them when it is initialized, and only adds to that
156    /// what its own properties decide, see [`Dev::add_command`].
157    ///
158    /// Behind an [`Arc`] because a definition is fixed once the class is built and shared
159    /// by every device of it, only the state the server keeps around it being per-device.
160    pub(super) commands: Vec<Arc<CommandDef<M>>>,
161    /// The attributes every device of that class has, see [`Self::commands`].
162    pub(super) attrs: Vec<Arc<AttrDef<M>>>,
163    /// The definition of the State attribute every device has, which is read through the
164    /// state function but configured like any other, see [`Self::state_config`].
165    pub(super) state_attr: Arc<AttrDef<M>>,
166    /// The definition of the Status attribute every device has, see [`Self::state_attr`].
167    pub(super) status_attr: Arc<AttrDef<M>>,
168}
169
170/// The function building the model of a device, either synchronous or asynchronous, see
171/// [`ClassDef::new`] and [`ClassDef::new_async`].
172pub enum InitFn<M: Model> {
173    Sync(Box<dyn for<'ctx> Fn(&'ctx Dev<M>) -> Result<M> + Send + Sync>),
174    Async(Box<dyn for<'a> Fn(&'a Dev<M>) -> BoxFuture<'a, Result<M>> + Send + Sync>),
175}
176/// The function called when the model of a device is deleted, see [`ClassDef::delete`],
177/// either synchronous or asynchronous.
178pub enum DeleteFn<M: Model> {
179    Sync(Box<dyn for<'ctx> Fn(M, &'ctx Dev<M>) + Send + Sync>),
180    Async(Box<dyn for<'a> Fn(M, &'a Dev<M>) -> BoxFuture<'a, ()> + Send + Sync>),
181}
182
183/// The state function of a device, with a shared or an exclusive access to the model,
184/// either synchronous or asynchronous.
185///
186/// An asynchronous function borrows the model, the device and, for those that take one,
187/// the argument for as long as its future runs, hence the single lifetime they share.
188pub enum StateFn<M: Model> {
189    SharedSync(Box<dyn for<'m, 'ctx> Fn(&'m M, &'ctx Dev<M>) -> Result<DevState> + Send + Sync>),
190    ExclusiveSync(Box<dyn for<'m, 'ctx> Fn(&'m mut M, &'ctx Dev<M>) -> Result<DevState> + Send + Sync>),
191    SharedAsync(Box<dyn for<'a> Fn(&'a M, &'a Dev<M>) -> BoxFuture<'a, Result<DevState>> + Send + Sync>),
192    ExclusiveAsync(Box<dyn for<'a> Fn(&'a mut M, &'a Dev<M>) -> BoxFuture<'a, Result<DevState>> + Send + Sync>),
193}
194
195/// The status function of a device, see [`StateFn`].
196pub enum StatusFn<M: Model> {
197    SharedSync(Box<dyn for<'m, 'ctx> Fn(&'m M, &'ctx Dev<M>) -> Result<Cow<'m, str>> + Send + Sync>),
198    ExclusiveSync(Box<dyn for<'m, 'ctx> Fn(&'m mut M, &'ctx Dev<M>) -> Result<Cow<'m, str>> + Send + Sync>),
199    SharedAsync(Box<dyn for<'a> Fn(&'a M, &'a Dev<M>) -> BoxFuture<'a, Result<Cow<'a, str>>> + Send + Sync>),
200    ExclusiveAsync(Box<dyn for<'a> Fn(&'a mut M, &'a Dev<M>) -> BoxFuture<'a, Result<Cow<'a, str>>> + Send + Sync>),
201}
202
203/// An asynchronous function of the model and of the device alone, whose result is given
204/// as-is, which is what the state and the status functions are. See [`ClassDef::state_async`].
205///
206/// The model is taken as `R`, being either `&'a M` or `&'a mut M` depending on the access
207/// the function asks for, and the future may borrow from both the model and the device,
208/// which is what an `async fn` method of the model does.
209pub trait HandlerAsync<'a, R, M: Model, O> {
210    /// Call the function, giving the future of its result.
211    fn call(&self, model: R, dev: &'a Dev<M>) -> BoxFuture<'a, Result<O>>;
212}
213
214impl<'a, R, M: Model, O, F, Fut> HandlerAsync<'a, R, M, O> for F
215where
216    F: Fn(R, &'a Dev<M>) -> Fut,
217    Fut: Future<Output = Result<O>> + Send + 'a,
218{
219    #[inline]
220    fn call(&self, model: R, dev: &'a Dev<M>) -> BoxFuture<'a, Result<O>> {
221        Box::pin(self(model, dev))
222    }
223}
224
225/// An asynchronous function building the model of a device, see [`ClassDef::new_async`].
226///
227/// The future may borrow the device, which is what an `async fn` taking it does.
228pub trait InitAsync<'a, M: Model> {
229    /// Call the function, giving the future of the model.
230    fn call(&self, dev: &'a Dev<M>) -> BoxFuture<'a, Result<M>>;
231}
232
233impl<'a, M: Model, F, Fut> InitAsync<'a, M> for F
234where
235    F: Fn(&'a Dev<M>) -> Fut,
236    Fut: Future<Output = Result<M>> + Send + 'a,
237{
238    #[inline]
239    fn call(&self, dev: &'a Dev<M>) -> BoxFuture<'a, Result<M>> {
240        Box::pin(self(dev))
241    }
242}
243
244/// An asynchronous function deleting the model of a device, see [`ClassDef::delete_async`].
245///
246/// The future owns the model and may borrow the device, which is what an `async fn` taking
247/// them does.
248pub trait DeleteAsync<'a, M: Model> {
249    /// Call the function, giving the future of the deletion.
250    fn call(&self, model: M, dev: &'a Dev<M>) -> BoxFuture<'a, ()>;
251}
252
253impl<'a, M: Model, F, Fut> DeleteAsync<'a, M> for F
254where
255    F: Fn(M, &'a Dev<M>) -> Fut,
256    Fut: Future<Output = ()> + Send + 'a,
257{
258    #[inline]
259    fn call(&self, model: M, dev: &'a Dev<M>) -> BoxFuture<'a, ()> {
260        Box::pin(self(model, dev))
261    }
262}
263
264impl<M: Model> ClassDef<M> {
265
266    /// Create a new device definition, the given function building the model of each
267    /// device of that class when it is initialized.
268    pub fn new<N, I>(name: N, init: I) -> Self
269    where
270        N: Into<Cow<'static, str>>,
271        I: for<'ctx> Fn(&'ctx Dev<M>) -> Result<M> + Send + Sync + 'static,
272    {
273        Self::with_init(name.into(), InitFn::Sync(Box::new(init)))
274    }
275
276    /// Create a new device definition, the given function building the model of each
277    /// device of that class asynchronously when it is initialized. This is the raw form of
278    /// [`Self::new_async`], for a closure that boxes its future itself.
279    pub fn new_async_with<N, I>(name: N, init: I) -> Self
280    where
281        N: Into<Cow<'static, str>>,
282        I: for<'a> Fn(&'a Dev<M>) -> BoxFuture<'a, Result<M>> + Send + Sync + 'static,
283    {
284        Self::with_init(name.into(), InitFn::Async(Box::new(init)))
285    }
286
287    /// Create a new device definition, the given function building the model of each
288    /// device of that class asynchronously when it is initialized, typically an `async fn`
289    /// taking the device.
290    ///
291    /// The model of the device is locked exclusively until the future completes, as it is
292    /// for a synchronous one, see [`Dev::init`]. The future is polled by the server itself
293    /// when nothing else of the initialization may block, so it must never block, see
294    /// [`Self::state_async`].
295    pub fn new_async<N, I>(name: N, init: I) -> Self
296    where
297        N: Into<Cow<'static, str>>,
298        I: for<'a> InitAsync<'a, M> + Send + Sync + 'static,
299    {
300        Self::new_async_with(name, move |dev| init.call(dev))
301    }
302
303    fn with_init(name: Cow<'static, str>, init: InitFn<M>) -> Self {
304        Self {
305            name,
306            doc: Cow::Borrowed("A Tango device"),
307            doc_url: None,
308            init,
309            delete: None,
310            state: None,
311            status: None,
312            commands: Vec::new(),
313            attrs: Vec::new(),
314            state_attr: state_attr(AttrConfig {
315                doc: Some(Cow::Borrowed("The state of the device")),
316                label: Some(Cow::Borrowed(STATE_NAME)),
317                ..AttrConfig::default()
318            }),
319            status_attr: status_attr(AttrConfig {
320                doc: Some(Cow::Borrowed("The status of the device")),
321                label: Some(Cow::Borrowed(STATUS_NAME)),
322                ..AttrConfig::default()
323            }),
324        }
325    }
326
327    /// Create a new device definition whose model is built with its default value.
328    pub fn new_default<N>(name: N) -> Self
329    where
330        M: Default,
331        N: Into<Cow<'static, str>>,
332    {
333        Self::new(name, |_ctx| Ok(M::default()))
334    }
335
336    /// Set the description the devices of that class give of themselves, which is what a
337    /// client asking a device what it is gets back, and what a class defines once for all
338    /// of its devices.
339    pub fn doc<D>(mut self, doc: D) -> Self
340    where
341        D: Into<Cow<'static, str>>,
342    {
343        self.doc = doc.into();
344        self
345    }
346
347    /// Set where the documentation of that class is, which is what a client shows as the
348    /// documentation of every device of it: a page describing what the class does, not
349    /// what one device of it is doing, which is its status.
350    pub fn doc_url<U>(mut self, url: U) -> Self
351    where
352        U: Into<Cow<'static, str>>,
353    {
354        self.doc_url = Some(url.into());
355        self
356    }
357
358    /// Define the function called when the model of a device of that class is deleted,
359    /// which is given the model back so that it may release its resources: before every
360    /// initialization but the first, which is what the Init command of a device is, and
361    /// once the device is no longer served.
362    pub fn delete<F>(mut self, delete: F) -> Self
363    where
364        F: for<'ctx> Fn(M, &'ctx Dev<M>) + Send + Sync + 'static,
365    {
366        self.delete = Some(DeleteFn::Sync(Box::new(delete)));
367        self
368    }
369
370    /// Define the function called when the model of a device of that class is deleted,
371    /// asynchronously. This is the raw form of [`Self::delete_async`], for a closure that
372    /// boxes its future itself.
373    pub fn delete_async_with<F>(mut self, delete: F) -> Self
374    where
375        F: for<'a> Fn(M, &'a Dev<M>) -> BoxFuture<'a, ()> + Send + Sync + 'static,
376    {
377        self.delete = Some(DeleteFn::Async(Box::new(delete)));
378        self
379    }
380
381    /// Define the function called when the model of a device of that class is deleted,
382    /// asynchronously, typically an `async fn` taking the model and the device, see
383    /// [`Self::delete`].
384    ///
385    /// The model of the device is locked exclusively until the future completes, as it is
386    /// for a synchronous one. The future is polled by the server itself when nothing else
387    /// of the deletion may block, so it must never block, see [`Self::state_async`].
388    pub fn delete_async<F>(self, delete: F) -> Self
389    where
390        F: for<'a> DeleteAsync<'a, M> + Send + Sync + 'static,
391    {
392        self.delete_async_with(move |model, dev| delete.call(model, dev))
393    }
394
395    /// Define the function giving the state of the device, with a shared access to the
396    /// model, which allows parallel execution of such functions.
397    pub fn state<F>(mut self, state: F) -> Self
398    where
399        F: for<'m, 'ctx> Fn(&'m M, &'ctx Dev<M>) -> Result<DevState> + Send + Sync + 'static,
400    {
401        self.state = Some(StateFn::SharedSync(Box::new(state)));
402        self
403    }
404
405    /// Define the function giving the state of the device, with an exclusive access to
406    /// the model, therefore no other command or attribute can access it in parallel.
407    pub fn state_exclusive<F>(mut self, state: F) -> Self
408    where
409        F: for<'m, 'ctx> Fn(&'m mut M, &'ctx Dev<M>) -> Result<DevState> + Send + Sync + 'static,
410    {
411        self.state = Some(StateFn::ExclusiveSync(Box::new(state)));
412        self
413    }
414
415    /// Define the function giving the state of the device, asynchronously and with a
416    /// shared access to the model. This is the raw form of [`Self::state_async`], for a
417    /// closure that boxes its future itself.
418    pub fn state_async_with<F>(mut self, state: F) -> Self
419    where
420        F: for<'a> Fn(&'a M, &'a Dev<M>) -> BoxFuture<'a, Result<DevState>> + Send + Sync + 'static,
421    {
422        self.state = Some(StateFn::SharedAsync(Box::new(state)));
423        self
424    }
425
426    /// Define the function giving the state of the device, asynchronously and with a
427    /// shared access to the model, typically an `async fn` method of the model.
428    ///
429    /// The model stays borrowed until the future completes, and the future is polled by
430    /// the server itself, so it must never block: a function that has to wait on anything
431    /// else than another future offloads that wait to a thread of its own.
432    pub fn state_async<F>(self, state: F) -> Self
433    where
434        F: for<'a> HandlerAsync<'a, &'a M, M, DevState> + Send + Sync + 'static,
435    {
436        self.state_async_with(move |model, dev| state.call(model, dev))
437    }
438
439    /// Define the function giving the state of the device, asynchronously and with an
440    /// exclusive access to the model. This is the raw form of [`Self::state_exclusive_async`],
441    /// see [`Self::state_async_with`].
442    pub fn state_exclusive_async_with<F>(mut self, state: F) -> Self
443    where
444        F: for<'a> Fn(&'a mut M, &'a Dev<M>) -> BoxFuture<'a, Result<DevState>> + Send + Sync + 'static,
445    {
446        self.state = Some(StateFn::ExclusiveAsync(Box::new(state)));
447        self
448    }
449
450    /// Define the function giving the state of the device, asynchronously and with an
451    /// exclusive access to the model, which no other command or attribute can then access
452    /// until the future completes. See [`Self::state_async`].
453    pub fn state_exclusive_async<F>(self, state: F) -> Self
454    where
455        F: for<'a> HandlerAsync<'a, &'a mut M, M, DevState> + Send + Sync + 'static,
456    {
457        self.state_exclusive_async_with(move |model, dev| state.call(model, dev))
458    }
459
460    /// Define the function giving the status of the device, with a shared access to the
461    /// model, the status being allowed to borrow from it.
462    pub fn status<F>(mut self, status: F) -> Self
463    where
464        F: for<'m, 'ctx> Fn(&'m M, &'ctx Dev<M>) -> Result<Cow<'m, str>> + Send + Sync + 'static,
465    {
466        self.status = Some(StatusFn::SharedSync(Box::new(status)));
467        self
468    }
469
470    /// Define the function giving the status of the device, with an exclusive access to
471    /// the model, the status being allowed to borrow from it.
472    pub fn status_exclusive<F>(mut self, status: F) -> Self
473    where
474        F: for<'m, 'ctx> Fn(&'m mut M, &'ctx Dev<M>) -> Result<Cow<'m, str>> + Send + Sync + 'static,
475    {
476        self.status = Some(StatusFn::ExclusiveSync(Box::new(status)));
477        self
478    }
479
480    /// Define the function giving the status of the device, asynchronously and with a
481    /// shared access to the model. This is the raw form of [`Self::status_async`], see
482    /// [`Self::state_async_with`].
483    pub fn status_async_with<F>(mut self, status: F) -> Self
484    where
485        F: for<'a> Fn(&'a M, &'a Dev<M>) -> BoxFuture<'a, Result<Cow<'a, str>>> + Send + Sync + 'static,
486    {
487        self.status = Some(StatusFn::SharedAsync(Box::new(status)));
488        self
489    }
490
491    /// Define the function giving the status of the device, asynchronously and with a
492    /// shared access to the model, the status being allowed to borrow from it. See
493    /// [`Self::state_async`].
494    pub fn status_async<F>(self, status: F) -> Self
495    where
496        F: for<'a> HandlerAsync<'a, &'a M, M, Cow<'a, str>> + Send + Sync + 'static,
497    {
498        self.status_async_with(move |model, dev| status.call(model, dev))
499    }
500
501    /// Define the function giving the status of the device, asynchronously and with an
502    /// exclusive access to the model. This is the raw form of
503    /// [`Self::status_exclusive_async`], see [`Self::state_async_with`].
504    pub fn status_exclusive_async_with<F>(mut self, status: F) -> Self
505    where
506        F: for<'a> Fn(&'a mut M, &'a Dev<M>) -> BoxFuture<'a, Result<Cow<'a, str>>> + Send + Sync + 'static,
507    {
508        self.status = Some(StatusFn::ExclusiveAsync(Box::new(status)));
509        self
510    }
511
512    /// Define the function giving the status of the device, asynchronously and with an
513    /// exclusive access to the model, see [`Self::state_exclusive_async`].
514    pub fn status_exclusive_async<F>(self, status: F) -> Self
515    where
516        F: for<'a> HandlerAsync<'a, &'a mut M, M, Cow<'a, str>> + Send + Sync + 'static,
517    {
518        self.status_exclusive_async_with(move |model, dev| status.call(model, dev))
519    }
520
521    /// Define a command every device of that class has, which is what defining a command
522    /// usually means: the devices of a class have the same interface, and a device only
523    /// adds to its own the part of it that its properties decide, see [`Dev::add_command`].
524    ///
525    /// # Panics
526    ///
527    /// If the class already defines a command of that name, or if the name is one of the
528    /// commands the server answers itself, being `State`, `Status` and `Init`.
529    #[track_caller]
530    pub fn command(mut self, def: CommandDef<M>) -> Self {
531        check_own_name(&self.name, "command", &def.name, RESERVED_COMMANDS);
532        if self.commands.iter().any(|other| other.name.eq_ignore_ascii_case(&def.name)) {
533            panic!("{}: the command {} is already defined", self.name, def.name);
534        }
535        self.commands.push(Arc::new(def));
536        self
537    }
538
539    /// Define an attribute every device of that class has, see [`Self::command`].
540    ///
541    /// # Panics
542    ///
543    /// If the class already defines an attribute of that name, or if the name is one of
544    /// the attributes the server answers itself, being `State` and `Status`.
545    #[track_caller]
546    pub fn attr(mut self, def: AttrDef<M>) -> Self {
547        check_own_name(&self.name, "attribute", &def.name, RESERVED_ATTRS);
548        if let Err(err) = def.check() {
549            panic!("{}: {err}", self.name);
550        }
551        if self.attrs.iter().any(|other| other.name.eq_ignore_ascii_case(&def.name)) {
552            panic!("{}: the attribute {} is already defined", self.name, def.name);
553        }
554        self.attrs.push(Arc::new(def));
555        self
556    }
557
558    /// Set the configuration the State attribute of every device of that class starts
559    /// from, which the database and clients then override like the one of any attribute.
560    /// The default one only gives it a label and a description.
561    ///
562    /// # Panics
563    ///
564    /// If the configuration gives a value to a property a state does not support, such as
565    /// a bound or an event criterion, see [`AttrConfig`].
566    #[track_caller]
567    pub fn state_config(mut self, config: AttrConfig) -> Self {
568        self.state_attr = state_attr(config);
569        self
570    }
571
572    /// Set the configuration the Status attribute of every device of that class starts
573    /// from, see [`Self::state_config`].
574    ///
575    /// # Panics
576    ///
577    /// If the configuration gives a value to a property a string does not support, see
578    /// [`Self::state_config`].
579    #[track_caller]
580    pub fn status_config(mut self, config: AttrConfig) -> Self {
581        self.status_attr = status_attr(config);
582        self
583    }
584
585    /// Declare that the devices of that class push the events of their State themselves,
586    /// change and archive, see [`AttrDef::push_change_event`].
587    pub fn push_state_events(mut self, change: Option<bool>, archive: Option<bool>) -> Self {
588        builtin_pushed(&mut self.state_attr, change, archive);
589        self
590    }
591
592    /// Declare that the devices of that class push the events of their Status themselves,
593    /// see [`Self::push_state_events`].
594    pub fn push_status_events(mut self, change: Option<bool>, archive: Option<bool>) -> Self {
595        builtin_pushed(&mut self.status_attr, change, archive);
596        self
597    }
598
599}
600
601/// The definition of the State attribute, with that configuration.
602#[track_caller]
603fn state_attr<M: Model>(config: AttrConfig) -> Arc<AttrDef<M>> {
604    builtin_attr(STATE_NAME, AttrDataKind::State, config)
605}
606
607/// The definition of the Status attribute, with that configuration.
608#[track_caller]
609fn status_attr<M: Model>(config: AttrConfig) -> Arc<AttrDef<M>> {
610    builtin_attr(STATUS_NAME, AttrDataKind::String, config)
611}
612
613/// Declare the events pushed for one of the attributes the server answers itself, whose
614/// definition only its class holds while it is built.
615fn builtin_pushed<M: Model>(def: &mut Arc<AttrDef<M>>, change: Option<bool>, archive: Option<bool>) {
616    let def = Arc::get_mut(def).expect("a class being built is the only owner of its definitions");
617    def.pushed = PushedEvents { change, archive };
618}
619
620/// The definition of one of the attributes the server answers itself, a read-only scalar
621/// of that kind with that configuration.
622#[track_caller]
623fn builtin_attr<M: Model>(name: &'static str, kind: AttrDataKind, config: AttrConfig) -> Arc<AttrDef<M>> {
624    let mut def = AttrDef::new(name).kind(kind).scalar();
625    def.display_level = DisplayLevel::Operator;
626    def.config = config;
627    if let Err(err) = def.check() {
628        panic!("{err}");
629    }
630    Arc::new(def)
631}
632
633/// Refuse a name that belongs to the server rather than to the class: the state, the
634/// status and the initialization of a device are answered by the server itself, whatever
635/// its class, so a definition of that name would never be reached and is a mistake worth
636/// pointing out where it is written rather than leaving to be found at runtime.
637#[track_caller]
638fn check_own_name(class: &str, what: &str, name: &str, reserved: &[&str]) {
639    if let Some(reserved) = reserved_name(name, reserved) {
640        panic!("{class}: the {what} {name} cannot be defined by a class, \
641            {reserved} is answered by the server itself");
642    }
643}
644
645impl<M: Model> Debug for ClassDef<M> {
646    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
647        f.debug_struct("ClassDef")
648            .field("name", &self.name)
649            .field("doc", &self.doc)
650            .field("doc_url", &self.doc_url)
651            .field("init", &HandlerDebug)
652            .field("delete", &self.delete.as_ref().map(|_| HandlerDebug))
653            .field("state", &self.state)
654            .field("status", &self.status)
655            .field("commands", &self.commands)
656            .field("attrs", &self.attrs)
657            .field("state_attr", &self.state_attr)
658            .field("status_attr", &self.status_attr)
659            .finish()
660    }
661}
662
663/// A builder for defining a command of a device.
664pub struct CommandDef<M: Model> {
665    /// The name of the command.
666    pub(super) name: Cow<'static, str>,
667    /// The function executing the command.
668    pub(super) exec: Option<ExecFn<M>>,
669    /// The advertised kind of the argument, derived from the execution function, absent
670    /// until it is defined and then defaulting to [`CommandDataKind::Void`].
671    pub(super) in_kind: Option<CommandDataKind>,
672    /// The documentation of the argument.
673    pub(super) in_doc: Cow<'static, str>,
674    /// The advertised kind of the result, derived from the execution function, absent
675    /// until it is defined and then defaulting to [`CommandDataKind::Void`].
676    pub(super) out_kind: Option<CommandDataKind>,
677    /// The documentation of the result.
678    pub(super) out_doc: Cow<'static, str>,
679    /// The display level of the command, which is all a command has of a configuration:
680    /// unlike an attribute, nothing about it can be changed once the class is defined.
681    pub(super) display_level: DisplayLevel,
682    /// The polling period this command asks for, absent for one that is not polled unless
683    /// the database says otherwise.
684    pub(super) poll_period: Option<Duration>,
685}
686
687/// The execution function of a command, with a shared or an exclusive access to the model,
688/// either synchronous or asynchronous, see [`StateFn`].
689pub enum ExecFn<M: Model> {
690    SharedSync(Box<dyn Fn(&M, &Dev<M>, Value) -> Result<Value> + Send + Sync>),
691    ExclusiveSync(Box<dyn Fn(&mut M, &Dev<M>, Value) -> Result<Value> + Send + Sync>),
692    SharedAsync(Box<dyn for<'a> Fn(&'a M, &'a Dev<M>, Value) -> BoxFuture<'a, Result<Value>> + Send + Sync>),
693    ExclusiveAsync(Box<dyn for<'a> Fn(&'a mut M, &'a Dev<M>, Value) -> BoxFuture<'a, Result<Value>> + Send + Sync>),
694}
695
696/// An execution function of a command with a shared access to the model, whose result may
697/// borrow from it until it is converted into a value. See [`CommandDef::exec`].
698pub trait ExecShared<'m, M: Model, I> {
699    /// The advertised kind of the argument, derived from its type.
700    const IN_KIND: CommandDataKind;
701    /// The advertised kind of the result, derived from its type.
702    const OUT_KIND: CommandDataKind;
703    /// Convert the given argument, execute the command and convert its result.
704    fn exec(&self, model: &'m M, dev: &Dev<M>, input: Value) -> Result<Value>;
705}
706
707impl<'m, M: Model, I, O, F> ExecShared<'m, M, I> for F
708where
709    I: FromValue + CommandData,
710    O: IntoValue + CommandData,
711    F: Fn(&'m M, &Dev<M>, I) -> Result<O>,
712{
713
714    const IN_KIND: CommandDataKind = I::DATA_KIND;
715    const OUT_KIND: CommandDataKind = O::DATA_KIND;
716
717    #[inline]
718    fn exec(&self, model: &'m M, dev: &Dev<M>, input: Value) -> Result<Value> {
719        Ok(self(model, dev, I::from_value(input)?)?.into_value())
720    }
721    
722}
723
724/// The exclusive counterpart of [`ExecShared`], see [`CommandDef::exec_exclusive`].
725pub trait ExecExclusive<'m, M: Model, I> {
726    /// The advertised kind of the argument, derived from its type.
727    const IN_KIND: CommandDataKind;
728    /// The advertised kind of the result, derived from its type.
729    const OUT_KIND: CommandDataKind;
730    /// Convert the given argument, execute the command and convert its result.
731    fn exec(&self, model: &'m mut M, dev: &Dev<M>, input: Value) -> Result<Value>;
732}
733
734impl<'m, M: Model, I, O, F> ExecExclusive<'m, M, I> for F
735where
736    I: FromValue + CommandData,
737    O: IntoValue + CommandData,
738    F: Fn(&'m mut M, &Dev<M>, I) -> Result<O>,
739{
740
741    const IN_KIND: CommandDataKind = I::DATA_KIND;
742    const OUT_KIND: CommandDataKind = O::DATA_KIND;
743
744    #[inline]
745    fn exec(&self, model: &'m mut M, dev: &Dev<M>, input: Value) -> Result<Value> {
746        Ok(self(model, dev, I::from_value(input)?)?.into_value())
747    }
748
749}
750
751/// An asynchronous execution function of a command, see [`CommandDef::exec_async`].
752///
753/// The model is taken as `R`, being either `&'a M` or `&'a mut M`, see [`HandlerAsync`],
754/// and the future may borrow from the model and the device, its result being allowed to
755/// borrow from both until it is converted into a value.
756pub trait ExecAsync<'a, R, M: Model, I> {
757    /// The advertised kind of the argument, derived from its type.
758    const IN_KIND: CommandDataKind;
759    /// The advertised kind of the result, derived from its type.
760    const OUT_KIND: CommandDataKind;
761    /// Convert the given argument and give the future executing the command and
762    /// converting its result.
763    fn exec(&self, model: R, dev: &'a Dev<M>, input: Value) -> BoxFuture<'a, Result<Value>>;
764}
765
766impl<'a, R, M: Model, I, O, F, Fut> ExecAsync<'a, R, M, I> for F
767where
768    I: FromValue + CommandData,
769    O: IntoValue + CommandData,
770    F: Fn(R, &'a Dev<M>, I) -> Fut,
771    Fut: Future<Output = Result<O>> + Send + 'a,
772{
773
774    const IN_KIND: CommandDataKind = I::DATA_KIND;
775    const OUT_KIND: CommandDataKind = O::DATA_KIND;
776
777    #[inline]
778    fn exec(&self, model: R, dev: &'a Dev<M>, input: Value) -> BoxFuture<'a, Result<Value>> {
779        // The function is called right away rather than on the first poll, so that
780        // whatever it starts before its first await is started with the request.
781        let fut = I::from_value(input).map(|input| self(model, dev, input));
782        Box::pin(async move { Ok(fut?.await?.into_value()) })
783    }
784
785}
786
787impl<M: Model> CommandDef<M> {
788
789    /// Create a new command definition, without any execution function.
790    pub fn new<N>(name: N) -> Self
791    where
792        N: Into<Cow<'static, str>>,
793    {
794        Self {
795            name: name.into(),
796            exec: None,
797            in_kind: None,
798            in_doc: Cow::Borrowed(""),
799            out_kind: None,
800            out_doc: Cow::Borrowed(""),
801            display_level: DisplayLevel::default(),
802            poll_period: None,
803        }
804    }
805
806    /// Set the documentation of the command argument (argin).
807    ///
808    /// A command has no description of its own, Tango only telling a client what each
809    /// side of it is, so what the command does has to be said in one of these two.
810    pub fn in_doc<D>(mut self, doc: D) -> Self
811    where
812        D: Into<Cow<'static, str>>,
813    {
814        self.in_doc = doc.into();
815        self
816    }
817
818    /// Set the documentation of the command result (argout).
819    pub fn out_doc<D>(mut self, doc: D) -> Self
820    where
821        D: Into<Cow<'static, str>>,
822    {
823        self.out_doc = doc.into();
824        self
825    }
826
827    /// Set the display level of the command, [`DisplayLevel::Expert`] keeping it out of
828    /// the panels an operator is shown without keeping it from anyone who asks for it.
829    pub fn display_level(mut self, level: DisplayLevel) -> Self {
830        self.display_level = level;
831        self
832    }
833
834    /// Ask for the command to be polled at that period, its result being kept in the
835    /// polling buffer of the device the way a polled attribute value is, which is what
836    /// `State` and `Status` are usually given.
837    ///
838    /// Only a command that takes no argument can be polled, there being no argument for
839    /// the server to invent, and the database has the last word on the period.
840    pub fn polled(mut self, period: Duration) -> Self {
841        self.poll_period = Some(period);
842        self
843    }
844
845    /// Set the advertised kind of the command argument (argin). This is only needed for
846    /// the execution functions that take a raw [`Value`] argument, the typed ones derive
847    /// it from their input type.
848    ///
849    /// # Panics
850    ///
851    /// If the argument kind has already been defined, explicitly or by an execution
852    /// function, as a different kind.
853    #[track_caller]
854    pub fn in_kind(mut self, kind: CommandDataKind) -> Self {
855        self.in_kind = Some(merge_kind(&self.name, "argument kind", self.in_kind.take(), kind));
856        self
857    }
858
859    /// Set the advertised kind of the command result (argout). This is only needed for
860    /// the execution functions that return a raw [`Value`], the typed ones derive it from
861    /// their output type.
862    ///
863    /// # Panics
864    ///
865    /// If the result kind has already been defined, explicitly or by an execution
866    /// function, as a different kind.
867    #[track_caller]
868    pub fn out_kind(mut self, kind: CommandDataKind) -> Self {
869        self.out_kind = Some(merge_kind(&self.name, "result kind", self.out_kind.take(), kind));
870        self
871    }
872
873    /// Define the execution function of this command, with a shared access to the model.
874    ///
875    /// This is the raw form of [`Self::exec`]: the closure is given the argument
876    /// [`Value`] as-is and returns one, converting what it borrows from the model itself,
877    /// which is what makes a closure usable for such a result. Because no input and output
878    /// types are involved, the advertised kinds have to be given with [`Self::in_kind`]
879    /// and [`Self::out_kind`].
880    pub fn exec_with<F>(mut self, func: F) -> Self
881    where
882        F: Fn(&M, &Dev<M>, Value) -> Result<Value> + Send + Sync + 'static,
883    {
884        self.exec = Some(ExecFn::SharedSync(Box::new(func)));
885        self
886    }
887
888    /// Define the execution function of this command, with a shared access to the model,
889    /// which allows parallel execution of such functions.
890    ///
891    /// The argument and result types are taken from the `ExecShared` implementation of
892    /// the function. The result may borrow from the model, being converted into a value
893    /// before the model is released, which requires a function item generic over the
894    /// model lifetime, typically an associated method of the model.
895    ///
896    /// # Panics
897    ///
898    /// If either advertised kind has already been defined as a different kind, see
899    /// [`Self::in_kind`] and [`Self::out_kind`].
900    #[track_caller]
901    pub fn exec<F, I>(self, func: F) -> Self
902    where
903        F: for<'m> ExecShared<'m, M, I> + Send + Sync + 'static,
904    {
905        self.in_kind(F::IN_KIND)
906            .out_kind(F::OUT_KIND)
907            .exec_with(move |model, dev, value| func.exec(model, dev, value))
908    }
909
910    /// Define the execution function of this command, with an exclusive access to the
911    /// model. This is the raw form of [`Self::exec_exclusive`], see [`Self::exec_with`].
912    pub fn exec_exclusive_with<F>(mut self, func: F) -> Self
913    where
914        F: Fn(&mut M, &Dev<M>, Value) -> Result<Value> + Send + Sync + 'static,
915    {
916        self.exec = Some(ExecFn::ExclusiveSync(Box::new(func)));
917        self
918    }
919
920    /// Define the execution function of this command, with an exclusive access to the
921    /// model, therefore no other command or attribute can access it in parallel.
922    ///
923    /// See [`Self::exec`] for the constraints on the argument and result types, this one
924    /// is only different in that its function item takes the model by exclusive reference.
925    ///
926    /// # Panics
927    ///
928    /// If either advertised kind has already been defined as a different kind, see
929    /// [`Self::in_kind`] and [`Self::out_kind`].
930    #[track_caller]
931    pub fn exec_exclusive<F, I>(self, func: F) -> Self
932    where
933        F: for<'m> ExecExclusive<'m, M, I> + Send + Sync + 'static,
934    {
935        self.in_kind(F::IN_KIND)
936            .out_kind(F::OUT_KIND)
937            .exec_exclusive_with(move |model, dev, value| func.exec(model, dev, value))
938    }
939
940    /// Define the execution function of this command, asynchronously and with a shared
941    /// access to the model. This is the raw form of [`Self::exec_async`], for a closure
942    /// that boxes its future itself, see [`Self::exec_with`].
943    pub fn exec_async_with<F>(mut self, func: F) -> Self
944    where
945        F: for<'a> Fn(&'a M, &'a Dev<M>, Value) -> BoxFuture<'a, Result<Value>> + Send + Sync + 'static,
946    {
947        self.exec = Some(ExecFn::SharedAsync(Box::new(func)));
948        self
949    }
950
951    /// Define the execution function of this command, asynchronously and with a shared
952    /// access to the model, typically an `async fn` method of the model.
953    ///
954    /// This is what a command forwarding its execution to other devices is written as:
955    /// it holds no thread while it waits on them, and may wait on many of them at once.
956    /// The future is polled by the server itself, so it must never block, see
957    /// [`ClassDef::state_async`].
958    ///
959    /// # Panics
960    ///
961    /// If either advertised kind has already been defined as a different kind, see
962    /// [`Self::in_kind`] and [`Self::out_kind`].
963    #[track_caller]
964    pub fn exec_async<F, I>(self, func: F) -> Self
965    where
966        F: for<'a> ExecAsync<'a, &'a M, M, I> + Send + Sync + 'static,
967    {
968        self.in_kind(F::IN_KIND)
969            .out_kind(F::OUT_KIND)
970            .exec_async_with(move |model, dev, value| func.exec(model, dev, value))
971    }
972
973    /// Define the execution function of this command, asynchronously and with an
974    /// exclusive access to the model. This is the raw form of [`Self::exec_exclusive_async`],
975    /// see [`Self::exec_async_with`].
976    pub fn exec_exclusive_async_with<F>(mut self, func: F) -> Self
977    where
978        F: for<'a> Fn(&'a mut M, &'a Dev<M>, Value) -> BoxFuture<'a, Result<Value>> + Send + Sync + 'static,
979    {
980        self.exec = Some(ExecFn::ExclusiveAsync(Box::new(func)));
981        self
982    }
983
984    /// Define the execution function of this command, asynchronously and with an
985    /// exclusive access to the model, which no other command or attribute can then access
986    /// until the future completes. See [`Self::exec_async`].
987    ///
988    /// # Panics
989    ///
990    /// If either advertised kind has already been defined as a different kind, see
991    /// [`Self::in_kind`] and [`Self::out_kind`].
992    #[track_caller]
993    pub fn exec_exclusive_async<F, I>(self, func: F) -> Self
994    where
995        F: for<'a> ExecAsync<'a, &'a mut M, M, I> + Send + Sync + 'static,
996    {
997        self.in_kind(F::IN_KIND)
998            .out_kind(F::OUT_KIND)
999            .exec_exclusive_async_with(move |model, dev, value| func.exec(model, dev, value))
1000    }
1001
1002}
1003
1004impl<M: Model> Debug for CommandDef<M> {
1005    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1006        f.debug_struct("CommandDef")
1007            .field("name", &self.name)
1008            .field("exec", &self.exec)
1009            .field("in_kind", &self.in_kind)
1010            .field("in_doc", &self.in_doc)
1011            .field("out_kind", &self.out_kind)
1012            .field("out_doc", &self.out_doc)
1013            .field("display_level", &self.display_level)
1014            .field("poll_period", &self.poll_period)
1015            .finish()
1016    }
1017}
1018
1019/// A builder for defining an attribute of a device.
1020pub struct AttrDef<M: Model> {
1021    /// The name of the attribute.
1022    pub(super) name: Cow<'static, str>,
1023    /// The function reading the attribute value, absent for a write-only attribute.
1024    pub(super) read: Option<ReadFn<M>>,
1025    /// The function writing the attribute value, absent for a read-only attribute.
1026    pub(super) write: Option<WriteFn<M>>,
1027    /// The advertised data kind, derived from the read and write functions.
1028    pub(super) kind: Option<AttrDataKind>,
1029    /// The advertised data format, derived from the read and write functions.
1030    pub(super) format: Option<AttrDataFormat>,
1031    /// The display level the attribute is shown at, which the class declares and a client
1032    /// cannot change, unlike the configuration below.
1033    pub(super) display_level: DisplayLevel,
1034    /// What the attribute does with the value of a write when the device is initialized
1035    /// again, absent for one that remembers nothing, which the class declares as well.
1036    pub(super) memorized: Option<AttrMemorized>,
1037    /// Everything a client may read about the attribute and, for most of it, change: its
1038    /// documentation, its units, its bounds and its event criteria. Every device of the
1039    /// class starts from this one and owns its copy from then on, because the database
1040    /// overrides it per device and a client changes it per device.
1041    pub(super) config: AttrConfig,
1042    /// The polling period this attribute asks for, absent for one that is not polled
1043    /// unless the database says otherwise.
1044    pub(super) poll_period: Option<Duration>,
1045    /// The events the device pushes itself for this attribute, see
1046    /// [`Self::push_change_event`].
1047    pub(super) pushed: PushedEvents,
1048}
1049
1050/// The events a device declares it pushes itself for an attribute, each with whether the
1051/// criteria of its configuration are checked against what is pushed, see
1052/// [`AttrDef::push_change_event`].
1053#[derive(Debug, Clone, Copy, Default)]
1054pub(super) struct PushedEvents {
1055    pub change: Option<bool>,
1056    pub archive: Option<bool>,
1057}
1058
1059/// The read function of an attribute, with a shared or an exclusive access to the model,
1060/// either synchronous or asynchronous, see [`StateFn`].
1061pub enum ReadFn<M: Model> {
1062    SharedSync(Box<dyn Fn(&M, &Dev<M>) -> Result<AttrRead<Value>> + Send + Sync>),
1063    ExclusiveSync(Box<dyn Fn(&mut M, &Dev<M>) -> Result<AttrRead<Value>> + Send + Sync>),
1064    SharedAsync(Box<dyn for<'a> Fn(&'a M, &'a Dev<M>) -> BoxFuture<'a, Result<AttrRead<Value>>> + Send + Sync>),
1065    ExclusiveAsync(Box<dyn for<'a> Fn(&'a mut M, &'a Dev<M>) -> BoxFuture<'a, Result<AttrRead<Value>>> + Send + Sync>),
1066}
1067
1068/// The write function of an attribute, with a shared or an exclusive access to the model,
1069/// either synchronous or asynchronous, see [`StateFn`].
1070pub enum WriteFn<M: Model> {
1071    SharedSync(Box<dyn Fn(&M, &Dev<M>, Value) -> Result<()> + Send + Sync>),
1072    ExclusiveSync(Box<dyn Fn(&mut M, &Dev<M>, Value) -> Result<()> + Send + Sync>),
1073    SharedAsync(Box<dyn for<'a> Fn(&'a M, &'a Dev<M>, Value) -> BoxFuture<'a, Result<()>> + Send + Sync>),
1074    ExclusiveAsync(Box<dyn for<'a> Fn(&'a mut M, &'a Dev<M>, Value) -> BoxFuture<'a, Result<()>> + Send + Sync>),
1075}
1076
1077/// A trait for abstracting what output types are accepted by read attribute methods: a
1078/// value alone, its quality and timestamp then being implicit, or a whole [`AttrRead`].
1079pub trait ReadOutput {
1080    /// The advertised kind of the value, derived from its type.
1081    const DATA_KIND: AttrDataKind;
1082    /// The advertised format of the value, without any maximum dimension.
1083    const DATA_FORMAT: AttrDataFormat;
1084    /// Convert this output into a read result, an absent write value asking the server
1085    /// to fill it with the latest one it has written.
1086    fn into_read(self) -> AttrRead<Value>;
1087}
1088
1089impl<O> ReadOutput for O
1090where
1091    O: IntoValue + AttrData,
1092{
1093    
1094    const DATA_KIND: AttrDataKind = O::DATA_KIND;
1095    const DATA_FORMAT: AttrDataFormat = O::DATA_FORMAT;
1096
1097    fn into_read(self) -> AttrRead<Value> {
1098        AttrRead {
1099            value: Some(self.into_value()),
1100            // An absent write value asks the server to fill it with the latest one it
1101            // has written, which is the usual behaviour of a read function.
1102            // If this is filled by the read function, the server will overwrite its own 
1103            // write value so that if a next read does not specify the write value, it 
1104            // will be returning the same one.
1105            w_value: None,
1106            quality: AttrQuality::Valid,
1107            time: SystemTime::now(),
1108        }
1109    }
1110    
1111}
1112
1113impl<O> ReadOutput for AttrRead<O>
1114where
1115    O: IntoValue + AttrData,
1116{
1117
1118    const DATA_KIND: AttrDataKind = O::DATA_KIND;
1119    const DATA_FORMAT: AttrDataFormat = O::DATA_FORMAT;
1120
1121    fn into_read(self) -> AttrRead<Value> {
1122        AttrRead {
1123            value: self.value.map(IntoValue::into_value),
1124            w_value: self.w_value.map(IntoValue::into_value),
1125            quality: self.quality,
1126            time: self.time,
1127        }
1128    }
1129
1130}
1131
1132/// A read function with a shared access to the model, whose result may borrow from it
1133/// until it is converted into a value. See [`AttrDef::read`], the same constraints as
1134/// [`ExecShared`] apply to the result type.
1135pub trait ReadShared<'m, M: Model> {
1136    /// The advertised kind of the value, derived from its type.
1137    const DATA_KIND: AttrDataKind;
1138    /// The advertised format of the value, without any maximum dimension.
1139    const DATA_FORMAT: AttrDataFormat;
1140    /// Read the value of the attribute and convert it.
1141    fn read(&self, model: &'m M, dev: &Dev<M>) -> Result<AttrRead<Value>>;
1142}
1143
1144impl<'m, M: Model, O, F> ReadShared<'m, M> for F
1145where
1146    F: Fn(&'m M, &Dev<M>) -> Result<O>,
1147    O: ReadOutput,
1148{
1149    const DATA_KIND: AttrDataKind = O::DATA_KIND;
1150    const DATA_FORMAT: AttrDataFormat = O::DATA_FORMAT;
1151
1152    #[inline]
1153    fn read(&self, model: &'m M, dev: &Dev<M>) -> Result<AttrRead<Value>> {
1154        Ok(self(model, dev)?.into_read())
1155    }
1156}
1157
1158/// The exclusive counterpart of [`ReadShared`], see [`AttrDef::read_exclusive`].
1159pub trait ReadExclusive<'m, M: Model> {
1160    /// The advertised kind of the value, derived from its type.
1161    const DATA_KIND: AttrDataKind;
1162    /// The advertised format of the value, without any maximum dimension.
1163    const DATA_FORMAT: AttrDataFormat;
1164    /// Read the value of the attribute and convert it.
1165    fn read(&self, model: &'m mut M, dev: &Dev<M>) -> Result<AttrRead<Value>>;
1166}
1167
1168impl<'m, M: Model, O, F> ReadExclusive<'m, M> for F
1169where
1170    F: Fn(&'m mut M, &Dev<M>) -> Result<O>,
1171    O: ReadOutput,
1172{
1173    const DATA_KIND: AttrDataKind = O::DATA_KIND;
1174    const DATA_FORMAT: AttrDataFormat = O::DATA_FORMAT;
1175
1176    #[inline]
1177    fn read(&self, model: &'m mut M, dev: &Dev<M>) -> Result<AttrRead<Value>> {
1178        Ok(self(model, dev)?.into_read())
1179    }
1180}
1181
1182/// A write function with a shared access to the model. See [`AttrDef::write`].
1183pub trait WriteShared<M: Model, I> {
1184    /// The advertised kind of the value, derived from its type.
1185    const DATA_KIND: AttrDataKind;
1186    /// The advertised format of the value, without any maximum dimension.
1187    const DATA_FORMAT: AttrDataFormat;
1188    /// Convert the given value and write it to the attribute.
1189    fn write(&self, model: &M, dev: &Dev<M>, value: Value) -> Result<()>;
1190}
1191
1192impl<M: Model, I, F> WriteShared<M, I> for F
1193where
1194    F: Fn(&M, &Dev<M>, I) -> Result<()>,
1195    I: FromValue + AttrData,
1196{
1197    const DATA_KIND: AttrDataKind = I::DATA_KIND;
1198    const DATA_FORMAT: AttrDataFormat = I::DATA_FORMAT;
1199
1200    #[inline]
1201    fn write(&self, model: &M, dev: &Dev<M>, value: Value) -> Result<()> {
1202        self(model, dev, I::from_value(value)?)
1203    }
1204}
1205
1206/// The exclusive counterpart of [`WriteShared`], see [`AttrDef::write_exclusive`].
1207pub trait WriteExclusive<M: Model, I> {
1208    /// The advertised kind of the value, derived from its type.
1209    const DATA_KIND: AttrDataKind;
1210    /// The advertised format of the value, without any maximum dimension.
1211    const DATA_FORMAT: AttrDataFormat;
1212    /// Convert the given value and write it to the attribute.
1213    fn write(&self, model: &mut M, dev: &Dev<M>, value: Value) -> Result<()>;
1214}
1215
1216impl<M: Model, I, F> WriteExclusive<M, I> for F
1217where
1218    F: Fn(&mut M, &Dev<M>, I) -> Result<()>,
1219    I: FromValue + AttrData,
1220{
1221    const DATA_KIND: AttrDataKind = I::DATA_KIND;
1222    const DATA_FORMAT: AttrDataFormat = I::DATA_FORMAT;
1223
1224    #[inline]
1225    fn write(&self, model: &mut M, dev: &Dev<M>, value: Value) -> Result<()> {
1226        self(model, dev, I::from_value(value)?)
1227    }
1228}
1229
1230/// An asynchronous read function of an attribute, see [`AttrDef::read_async`].
1231///
1232/// The model is taken as `R`, being either `&'a M` or `&'a mut M`, see [`HandlerAsync`],
1233/// and the value may borrow from the model, with the same result types as [`ReadShared`].
1234pub trait ReadAsync<'a, R, M: Model> {
1235    /// The advertised kind of the value, derived from its type.
1236    const DATA_KIND: AttrDataKind;
1237    /// The advertised format of the value, without any maximum dimension.
1238    const DATA_FORMAT: AttrDataFormat;
1239    /// Give the future reading the value of the attribute and converting it.
1240    fn read(&self, model: R, dev: &'a Dev<M>) -> BoxFuture<'a, Result<AttrRead<Value>>>;
1241}
1242
1243impl<'a, R, M: Model, O, F, Fut> ReadAsync<'a, R, M> for F
1244where
1245    F: Fn(R, &'a Dev<M>) -> Fut,
1246    Fut: Future<Output = Result<O>> + Send + 'a,
1247    O: ReadOutput,
1248{
1249    const DATA_KIND: AttrDataKind = O::DATA_KIND;
1250    const DATA_FORMAT: AttrDataFormat = O::DATA_FORMAT;
1251
1252    #[inline]
1253    fn read(&self, model: R, dev: &'a Dev<M>) -> BoxFuture<'a, Result<AttrRead<Value>>> {
1254        let fut = self(model, dev);
1255        Box::pin(async move { Ok(fut.await?.into_read()) })
1256    }
1257}
1258
1259/// An asynchronous write function of an attribute, see [`AttrDef::write_async`].
1260///
1261/// The model is taken as `R`, being either `&'a M` or `&'a mut M`, see [`HandlerAsync`].
1262pub trait WriteAsync<'a, R, M: Model, I> {
1263    /// The advertised kind of the value, derived from its type.
1264    const DATA_KIND: AttrDataKind;
1265    /// The advertised format of the value, without any maximum dimension.
1266    const DATA_FORMAT: AttrDataFormat;
1267    /// Convert the given value and give the future writing it to the attribute.
1268    fn write(&self, model: R, dev: &'a Dev<M>, value: Value) -> BoxFuture<'a, Result<()>>;
1269}
1270
1271impl<'a, R, M: Model, I, F, Fut> WriteAsync<'a, R, M, I> for F
1272where
1273    F: Fn(R, &'a Dev<M>, I) -> Fut,
1274    Fut: Future<Output = Result<()>> + Send + 'a,
1275    I: FromValue + AttrData,
1276{
1277    const DATA_KIND: AttrDataKind = I::DATA_KIND;
1278    const DATA_FORMAT: AttrDataFormat = I::DATA_FORMAT;
1279
1280    #[inline]
1281    fn write(&self, model: R, dev: &'a Dev<M>, value: Value) -> BoxFuture<'a, Result<()>> {
1282        let fut = I::from_value(value).map(|input| self(model, dev, input));
1283        Box::pin(async move { fut?.await })
1284    }
1285}
1286
1287impl<M: Model> AttrDef<M> {
1288
1289    /// Create a new attribute definition, without any read or write function.
1290    pub fn new<N>(name: N) -> Self
1291    where
1292        N: Into<Cow<'static, str>>,
1293    {
1294        Self {
1295            name: name.into(),
1296            read: None,
1297            write: None,
1298            kind: None,
1299            format: None,
1300            display_level: DisplayLevel::default(),
1301            memorized: None,
1302            config: AttrConfig::default(),
1303            poll_period: None,
1304            pushed: PushedEvents::default(),
1305        }
1306    }
1307
1308    // --- Documentation --- //
1309
1310    /// Set the description of the attribute, which is the only part of its configuration
1311    /// a client cannot change afterwards: it describes what the attribute *is*, and that
1312    /// is the business of the device, not of whoever reads it.
1313    pub fn doc<D>(mut self, doc: D) -> Self
1314    where
1315        D: Into<Cow<'static, str>>,
1316    {
1317        self.config.doc = Some(doc.into());
1318        self
1319    }
1320
1321    /// Set the label of the attribute, the short name a client shows in place of its own,
1322    /// where "Position" reads better than "position" and "Δθ" than "delta_theta".
1323    pub fn label<L>(mut self, label: L) -> Self
1324    where
1325        L: Into<Cow<'static, str>>,
1326    {
1327        self.config.label = Some(label.into());
1328        self
1329    }
1330
1331    /// Set the unit the value is expressed in, as it is shown next to it.
1332    pub fn unit<U>(mut self, unit: U) -> Self
1333    where
1334        U: Into<Cow<'static, str>>,
1335    {
1336        self.config.unit = Some(unit.into());
1337        self
1338    }
1339
1340    /// Set the factor going from the value of the attribute to the same quantity in the
1341    /// international system, so that a client can convert without knowing the unit: 1e-3
1342    /// for a value in millimetres, the metre being the standard unit of a length.
1343    pub fn standard_unit(mut self, factor: f64) -> Self {
1344        self.config.standard_unit = Some(factor);
1345        self
1346    }
1347
1348    /// Set the unit the value is *displayed* in, when it is not the one it is expressed
1349    /// in: a value in metres a client should show in millimetres.
1350    pub fn display_unit<U>(mut self, unit: U) -> Self
1351    where
1352        U: Into<Cow<'static, str>>,
1353    {
1354        self.config.display_unit = Some(unit.into());
1355        self
1356    }
1357
1358    /// Set how the value is formatted for display, as a printf format such as `%8.3f`,
1359    /// which is what tells a client how many decimals of it are meaningful.
1360    pub fn display_format<F>(mut self, format: F) -> Self
1361    where
1362        F: Into<Cow<'static, str>>,
1363    {
1364        self.config.display_format = Some(format.into());
1365        self
1366    }
1367
1368    /// Set the display level of the attribute, [`DisplayLevel::Expert`] hiding it from the
1369    /// panels an operator is shown without hiding it from anyone who asks for it.
1370    pub fn display_level(mut self, level: DisplayLevel) -> Self {
1371        self.display_level = level;
1372        self
1373    }
1374
1375    // --- Bounds --- //
1376
1377    /// Set the range of the values the attribute accepts being written, outside of which a
1378    /// write is refused by the server rather than by the device.
1379    ///
1380    /// The range is given as a Rust range, either bound of which may be left open for an
1381    /// attribute that is only bounded on one side:
1382    ///
1383    /// ```ignore
1384    /// AttrDef::new("position").range(-100.0..=100.0)
1385    /// AttrDef::new("pressure").range(0.0..)
1386    /// ```
1387    ///
1388    /// # Panics
1389    ///
1390    /// If a bound is exclusive, which Tango has no way to express.
1391    #[track_caller]
1392    pub fn range<T, R>(mut self, range: R) -> Self
1393    where
1394        T: Into<AttrNumber> + Copy,
1395        R: RangeBounds<T>,
1396    {
1397        self.config.range = range_config(&self.name, "value range", range);
1398        self
1399    }
1400
1401    /// Set the range outside of which the attribute is in [`AttrQuality::Alarm`], and the
1402    /// device with it: an alarm is the reading being wrong, not the write being refused.
1403    ///
1404    /// # Panics
1405    ///
1406    /// If a bound is exclusive, see [`Self::range`].
1407    #[track_caller]
1408    pub fn alarm<T, R>(mut self, range: R) -> Self
1409    where
1410        T: Into<AttrNumber> + Copy,
1411        R: RangeBounds<T>,
1412    {
1413        self.config.alarm = range_config(&self.name, "alarm range", range);
1414        self
1415    }
1416
1417    /// Set the range outside of which the attribute is in [`AttrQuality::Warning`], which
1418    /// is the same as an alarm without the device going into [`DevState::Alarm`] for it.
1419    ///
1420    /// # Panics
1421    ///
1422    /// If a bound is exclusive, see [`Self::range`].
1423    #[track_caller]
1424    pub fn warning<T, R>(mut self, range: R) -> Self
1425    where
1426        T: Into<AttrNumber> + Copy,
1427        R: RangeBounds<T>,
1428    {
1429        self.config.warning = range_config(&self.name, "warning range", range);
1430        self
1431    }
1432
1433    /// Set the alarm on the read value drifting from the written one: how far apart the
1434    /// two may be, and for how long before it counts, absent for immediately.
1435    ///
1436    /// This is what says that a motor asked to go somewhere is not going there, which no
1437    /// bound on the value alone can express.
1438    pub fn delta<V, T>(mut self, value: V, time: T) -> Self
1439    where
1440        V: Into<AttrNumber>,
1441        T: Into<Option<Duration>>,
1442    {
1443        self.config.delta = Some(AttrDeltaConfig {
1444            value: value.into(),
1445            time: time.into(),
1446        });
1447        self
1448    }
1449
1450    // --- Events --- //
1451
1452    /// Set the criteria of the change event: how much the value has to move, absolutely
1453    /// and relatively, for the server to send one. Either may be left out with [`None`],
1454    /// and an attribute that declares neither only has the change events its device pushes
1455    /// by itself.
1456    ///
1457    /// ```ignore
1458    /// AttrDef::new("position").change_event(0.001, None)
1459    /// ```
1460    pub fn change_event<A, R>(mut self, abs: A, rel: R) -> Self
1461    where
1462        A: Into<Option<f64>>,
1463        R: Into<Option<f64>>,
1464    {
1465        self.config.change_event.abs_change = abs.into();
1466        self.config.change_event.rel_change = rel.into();
1467        self
1468    }
1469
1470    /// Set the period of the periodic event, which is sent whether the value moved or not
1471    /// and is how a client tells a device that has nothing to say from one that is gone.
1472    pub fn periodic_event(mut self, period: Duration) -> Self {
1473        self.config.periodic_event.period = Some(period);
1474        self
1475    }
1476
1477    /// Set the criteria of the archive event: the same two changes as
1478    /// [`Self::change_event`], and the longest an archiver may go without an event when
1479    /// the value does not move.
1480    pub fn archive_event<A, R, P>(mut self, abs: A, rel: R, period: P) -> Self
1481    where
1482        A: Into<Option<f64>>,
1483        R: Into<Option<f64>>,
1484        P: Into<Option<Duration>>,
1485    {
1486        self.config.archive_event.abs_change = abs.into();
1487        self.config.archive_event.rel_change = rel.into();
1488        self.config.archive_event.period = period.into();
1489        self
1490    }
1491
1492    /// Declare that the device pushes the change events of this attribute itself, see
1493    /// [`Dev::push_change_event`], which is what a client may then subscribe to them for:
1494    /// with no polling, a subscription to the change events of an attribute that does not
1495    /// declare them is refused, the way cppTango refuses it.
1496    ///
1497    /// With `detect`, the criteria of the change event are to be checked against what is
1498    /// pushed, see [`Self::change_event`], as cppTango does.
1499    ///
1500    /// TODO: Check the criteria, every push being sent for now.
1501    pub fn push_change_event(mut self, detect: bool) -> Self {
1502        self.pushed.change = Some(detect);
1503        self
1504    }
1505
1506    /// Declare that the device pushes the archive events of this attribute itself, see
1507    /// [`Self::push_change_event`].
1508    pub fn push_archive_event(mut self, detect: bool) -> Self {
1509        self.pushed.archive = Some(detect);
1510        self
1511    }
1512
1513    // --- Server behaviour --- //
1514
1515    /// Make the attribute memorized: the server stores the value of every write in the
1516    /// database and restores it when the device is initialized, the mode saying whether it
1517    /// is only given back as the write value or written again for real.
1518    ///
1519    /// Only a writable scalar can be memorized, there being nothing to remember about a
1520    /// value the device computes, and a state or an encoded value cannot, which a class
1521    /// is told when the attribute is given to it, see [`ClassDef::attr`].
1522    pub fn memorized(mut self, mode: AttrMemorized) -> Self {
1523        self.memorized = Some(mode);
1524        self
1525    }
1526
1527    /// Check what is only known once the whole definition is built: that this attribute
1528    /// can be memorized if it asks to be, see [`Self::memorized`], and that its kind
1529    /// supports every property its configuration gives a value to.
1530    pub(super) fn check(&self) -> std::result::Result<(), String> {
1531
1532        if let Some(prop) = unsupported_prop(&self.config, self.kind) {
1533            return Err(format!("the attribute {} cannot have the property {:?}, {}",
1534                self.name, prop.name(), unsupported(self.kind)));
1535        }
1536
1537        if self.memorized.is_none() {
1538            return Ok(());
1539        }
1540
1541        let reason = if self.write.is_none() {
1542            "it is not writable"
1543        } else if !matches!(self.format, None | Some(AttrDataFormat::Scalar)) {
1544            "it is not a scalar"
1545        } else if matches!(self.kind, Some(AttrDataKind::State | AttrDataKind::Encoded)) {
1546            "a value of its kind cannot be memorized"
1547        } else {
1548            return Ok(());
1549        };
1550
1551        Err(format!("the attribute {} cannot be memorized, {reason}", self.name))
1552        
1553    }
1554
1555    /// Ask for the attribute to be polled at that period, the value each poll reads being
1556    /// what the server keeps in its polling buffer and answers a cached read with.
1557    ///
1558    /// This is the period the class asks for; the database has the last word, so a device
1559    /// may end up polled at another period, or not polled at all.
1560    pub fn polled(mut self, period: Duration) -> Self {
1561        self.poll_period = Some(period);
1562        self
1563    }
1564
1565    /// Set the advertised data kind of the attribute. This is only needed for the read
1566    /// and write functions that use a raw [`Value`], the typed ones derive it from their
1567    /// value type.
1568    ///
1569    /// # Panics
1570    ///
1571    /// If the data kind has already been defined, explicitly or by a read or a write
1572    /// function, as a different kind.
1573    #[track_caller]
1574    pub fn kind(mut self, kind: AttrDataKind) -> Self {
1575        self.kind = Some(merge_kind(&self.name, "data kind", self.kind.take(), kind));
1576        self
1577    }
1578
1579    /// Set the advertised data format of the attribute, which also gives the maximum
1580    /// dimensions of a spectrum or an image. This is only needed for the read and write
1581    /// functions that use a raw [`Value`], the typed ones derive a format without any
1582    /// maximum dimension from their value type.
1583    ///
1584    /// A maximum dimension of zero being undefined, it is compatible with any other one,
1585    /// so the maximum dimensions of a typed read or write function can be completed by
1586    /// this method, in any order.
1587    ///
1588    /// # Panics
1589    ///
1590    /// If the data format has already been defined, explicitly or by a read or a write
1591    /// function, with a different layout or a different maximum dimension.
1592    #[track_caller]
1593    pub fn format(mut self, format: AttrDataFormat) -> Self {
1594        self.format = Some(merge_format(&self.name, self.format.take(), format));
1595        self
1596    }
1597
1598    /// Declare the attribute to hold a single value, which is [`Self::format`] with the
1599    /// format written for you.
1600    ///
1601    /// # Panics
1602    ///
1603    /// If the format has already been defined as another layout, see [`Self::format`].
1604    #[track_caller]
1605    pub fn scalar(self) -> Self {
1606        self.format(AttrDataFormat::Scalar)
1607    }
1608
1609    /// Declare the attribute to hold a one dimensional array of at most that many values.
1610    ///
1611    /// A typed read or write function already gives the layout, so this is usually only
1612    /// there for the maximum size, which no value type carries; a maximum of zero leaves
1613    /// it undeclared, an array of any size then being accepted.
1614    ///
1615    /// # Panics
1616    ///
1617    /// If the format has already been defined as another layout, or as a spectrum of a
1618    /// different maximum size, see [`Self::format`].
1619    #[track_caller]
1620    pub fn spectrum(self, max_size: usize) -> Self {
1621        self.format(AttrDataFormat::Spectrum(max_size))
1622    }
1623
1624    /// Declare the attribute to hold a two dimensional array of at most that width and
1625    /// that height, see [`Self::spectrum`].
1626    ///
1627    /// # Panics
1628    ///
1629    /// If the format has already been defined as another layout, or as an image of
1630    /// different maximum dimensions, see [`Self::format`].
1631    #[track_caller]
1632    pub fn image(self, max_width: usize, max_height: usize) -> Self {
1633        self.format(AttrDataFormat::Image(max_width, max_height))
1634    }
1635
1636    /// Define the read function of this attribute, with a shared access to the model.
1637    ///
1638    /// This is the raw form of [`Self::read`]: the closure returns a [`Value`], converting
1639    /// what it borrows from the model itself, which is what makes a closure usable for
1640    /// such a result. The advertised kind and format then have to be given with
1641    /// [`Self::kind`] and [`Self::format`].
1642    pub fn read_with<F>(mut self, func: F) -> Self
1643    where
1644        F: Fn(&M, &Dev<M>) -> Result<AttrRead<Value>> + Send + Sync + 'static,
1645    {
1646        self.read = Some(ReadFn::SharedSync(Box::new(func)));
1647        self
1648    }
1649
1650    /// Define the read function of this attribute, with a shared access to the model,
1651    /// which allows parallel reading of such attributes.
1652    ///
1653    /// The value type is taken from the `ReadShared` implementation of the function,
1654    /// and may borrow from the model, with the same constraints as [`CommandDef::exec`]:
1655    /// it is then written as a function item generic over the model lifetime, typically
1656    /// an associated method of the model.
1657    ///
1658    /// # Panics
1659    ///
1660    /// If the advertised kind or format has already been defined incompatibly, see
1661    /// [`Self::kind`] and [`Self::format`].
1662    #[track_caller]
1663    pub fn read<F>(self, func: F) -> Self
1664    where
1665        F: for<'m> ReadShared<'m, M> + Send + Sync + 'static,
1666    {
1667        self.kind(F::DATA_KIND)
1668            .format(F::DATA_FORMAT)
1669            .read_with(move |model, dev| func.read(model, dev))
1670    }
1671
1672    /// Define the read function of this attribute, with an exclusive access to the model.
1673    /// This is the raw form of [`Self::read_exclusive`], see [`Self::read_with`].
1674    pub fn read_exclusive_with<F>(mut self, func: F) -> Self
1675    where
1676        F: Fn(&mut M, &Dev<M>) -> Result<AttrRead<Value>> + Send + Sync + 'static,
1677    {
1678        self.read = Some(ReadFn::ExclusiveSync(Box::new(func)));
1679        self
1680    }
1681
1682    /// Define the read function of this attribute, with an exclusive access to the model,
1683    /// therefore no other command or attribute can access it in parallel.
1684    ///
1685    /// # Panics
1686    ///
1687    /// If the advertised kind or format has already been defined incompatibly, see
1688    /// [`Self::kind`] and [`Self::format`].
1689    #[track_caller]
1690    pub fn read_exclusive<F>(self, func: F) -> Self
1691    where
1692        F: for<'m> ReadExclusive<'m, M> + Send + Sync + 'static,
1693    {
1694        self.kind(F::DATA_KIND)
1695            .format(F::DATA_FORMAT)
1696            .read_exclusive_with(move |model, dev| func.read(model, dev))
1697    }
1698
1699    /// Define the read function of this attribute, asynchronously and with a shared access
1700    /// to the model. This is the raw form of [`Self::read_async`], for a closure that
1701    /// boxes its future itself, see [`Self::read_with`].
1702    pub fn read_async_with<F>(mut self, func: F) -> Self
1703    where
1704        F: for<'a> Fn(&'a M, &'a Dev<M>) -> BoxFuture<'a, Result<AttrRead<Value>>> + Send + Sync + 'static,
1705    {
1706        self.read = Some(ReadFn::SharedAsync(Box::new(func)));
1707        self
1708    }
1709
1710    /// Define the read function of this attribute, asynchronously and with a shared access
1711    /// to the model, typically an `async fn` method of the model, see
1712    /// [`CommandDef::exec_async`] for what it is for and what it must not do.
1713    ///
1714    /// # Panics
1715    ///
1716    /// If the advertised kind or format has already been defined incompatibly, see
1717    /// [`Self::kind`] and [`Self::format`].
1718    #[track_caller]
1719    pub fn read_async<F>(self, func: F) -> Self
1720    where
1721        F: for<'a> ReadAsync<'a, &'a M, M> + Send + Sync + 'static,
1722    {
1723        self.kind(F::DATA_KIND)
1724            .format(F::DATA_FORMAT)
1725            .read_async_with(move |model, dev| func.read(model, dev))
1726    }
1727
1728    /// Define the read function of this attribute, asynchronously and with an exclusive
1729    /// access to the model. This is the raw form of [`Self::read_exclusive_async`], see
1730    /// [`Self::read_async_with`].
1731    pub fn read_exclusive_async_with<F>(mut self, func: F) -> Self
1732    where
1733        F: for<'a> Fn(&'a mut M, &'a Dev<M>) -> BoxFuture<'a, Result<AttrRead<Value>>> + Send + Sync + 'static,
1734    {
1735        self.read = Some(ReadFn::ExclusiveAsync(Box::new(func)));
1736        self
1737    }
1738
1739    /// Define the read function of this attribute, asynchronously and with an exclusive
1740    /// access to the model, which no other command or attribute can then access until the
1741    /// future completes. See [`Self::read_async`].
1742    ///
1743    /// # Panics
1744    ///
1745    /// If the advertised kind or format has already been defined incompatibly, see
1746    /// [`Self::kind`] and [`Self::format`].
1747    #[track_caller]
1748    pub fn read_exclusive_async<F>(self, func: F) -> Self
1749    where
1750        F: for<'a> ReadAsync<'a, &'a mut M, M> + Send + Sync + 'static,
1751    {
1752        self.kind(F::DATA_KIND)
1753            .format(F::DATA_FORMAT)
1754            .read_exclusive_async_with(move |model, dev| func.read(model, dev))
1755    }
1756
1757    /// Define the write function of this attribute, with a shared access to the model.
1758    /// This is the raw form of [`Self::write`], the written [`Value`] being given as-is
1759    /// and the advertised kind and format having to be given with [`Self::kind`] and
1760    /// [`Self::format`].
1761    pub fn write_with<F>(mut self, func: F) -> Self
1762    where
1763        F: Fn(&M, &Dev<M>, Value) -> Result<()> + Send + Sync + 'static,
1764    {
1765        self.write = Some(WriteFn::SharedSync(Box::new(func)));
1766        self
1767    }
1768
1769    /// Define the write function of this attribute, with a shared access to the model.
1770    ///
1771    /// The value type is taken from the `WriteShared` implementation of the function,
1772    /// any [`FromValue`] type, a [`Buf`](crate::buf::Buf) sharing the written value
1773    /// rather than copying it.
1774    ///
1775    /// # Panics
1776    ///
1777    /// If the advertised kind or format has already been defined incompatibly, which
1778    /// notably happens when the read function of the attribute does not use the same
1779    /// value type, see [`Self::kind`] and [`Self::format`].
1780    #[track_caller]
1781    pub fn write<F, I>(self, func: F) -> Self
1782    where
1783        F: WriteShared<M, I> + Send + Sync + 'static,
1784    {
1785        self.kind(F::DATA_KIND)
1786            .format(F::DATA_FORMAT)
1787            .write_with(move |model, dev, value| func.write(model, dev, value))
1788    }
1789
1790    /// Define the write function of this attribute, with an exclusive access to the
1791    /// model. This is the raw form of [`Self::write_exclusive`], see [`Self::write_with`].
1792    pub fn write_exclusive_with<F>(mut self, func: F) -> Self
1793    where
1794        F: Fn(&mut M, &Dev<M>, Value) -> Result<()> + Send + Sync + 'static,
1795    {
1796        self.write = Some(WriteFn::ExclusiveSync(Box::new(func)));
1797        self
1798    }
1799
1800    /// Define the write function of this attribute, with an exclusive access to the
1801    /// model, which is what a write usually needs in order to store the written value.
1802    ///
1803    /// # Panics
1804    ///
1805    /// If the advertised kind or format has already been defined incompatibly, which
1806    /// notably happens when the read function of the attribute does not use the same
1807    /// value type, see [`Self::kind`] and [`Self::format`].
1808    #[track_caller]
1809    pub fn write_exclusive<F, I>(self, func: F) -> Self
1810    where
1811        F: WriteExclusive<M, I> + Send + Sync + 'static,
1812    {
1813        self.kind(F::DATA_KIND)
1814            .format(F::DATA_FORMAT)
1815            .write_exclusive_with(move |model, dev, value| func.write(model, dev, value))
1816    }
1817
1818    /// Define the write function of this attribute, asynchronously and with a shared
1819    /// access to the model. This is the raw form of [`Self::write_async`], see
1820    /// [`Self::read_async_with`].
1821    pub fn write_async_with<F>(mut self, func: F) -> Self
1822    where
1823        F: for<'a> Fn(&'a M, &'a Dev<M>, Value) -> BoxFuture<'a, Result<()>> + Send + Sync + 'static,
1824    {
1825        self.write = Some(WriteFn::SharedAsync(Box::new(func)));
1826        self
1827    }
1828
1829    /// Define the write function of this attribute, asynchronously and with a shared
1830    /// access to the model, see [`Self::read_async`].
1831    ///
1832    /// # Panics
1833    ///
1834    /// If the advertised kind or format has already been defined incompatibly, see
1835    /// [`Self::write`].
1836    #[track_caller]
1837    pub fn write_async<F, I>(self, func: F) -> Self
1838    where
1839        F: for<'a> WriteAsync<'a, &'a M, M, I> + Send + Sync + 'static,
1840    {
1841        self.kind(F::DATA_KIND)
1842            .format(F::DATA_FORMAT)
1843            .write_async_with(move |model, dev, value| func.write(model, dev, value))
1844    }
1845
1846    /// Define the write function of this attribute, asynchronously and with an exclusive
1847    /// access to the model. This is the raw form of [`Self::write_exclusive_async`], see
1848    /// [`Self::read_async_with`].
1849    pub fn write_exclusive_async_with<F>(mut self, func: F) -> Self
1850    where
1851        F: for<'a> Fn(&'a mut M, &'a Dev<M>, Value) -> BoxFuture<'a, Result<()>> + Send + Sync + 'static,
1852    {
1853        self.write = Some(WriteFn::ExclusiveAsync(Box::new(func)));
1854        self
1855    }
1856
1857    /// Define the write function of this attribute, asynchronously and with an exclusive
1858    /// access to the model, which no other command or attribute can then access until the
1859    /// future completes. See [`Self::read_async`].
1860    ///
1861    /// # Panics
1862    ///
1863    /// If the advertised kind or format has already been defined incompatibly, see
1864    /// [`Self::write`].
1865    #[track_caller]
1866    pub fn write_exclusive_async<F, I>(self, func: F) -> Self
1867    where
1868        F: for<'a> WriteAsync<'a, &'a mut M, M, I> + Send + Sync + 'static,
1869    {
1870        self.kind(F::DATA_KIND)
1871            .format(F::DATA_FORMAT)
1872            .write_exclusive_async_with(move |model, dev, value| func.write(model, dev, value))
1873    }
1874
1875}
1876
1877impl<M: Model> Debug for AttrDef<M> {
1878    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1879        f.debug_struct("AttrDef")
1880            .field("name", &self.name)
1881            .field("read", &self.read)
1882            .field("write", &self.write)
1883            .field("kind", &self.kind)
1884            .field("format", &self.format)
1885            .field("config", &self.config)
1886            .field("poll_period", &self.poll_period)
1887            .field("pushed", &self.pushed)
1888            .finish()
1889    }
1890}
1891
1892
1893#[cfg(test)]
1894mod tests {
1895
1896    use super::*;
1897    use crate::value::Spectrum;
1898
1899    #[derive(Default)]
1900    struct Model { count: i32, label: String, values: Vec<f64>, labels: Vec<String> }
1901
1902    impl Model {
1903
1904        /// A result borrowed from the model, the lifetime elision binding it to the model
1905        /// borrow, see [`CommandDef::exec`].
1906        fn label(&self, _dev: &Dev<Self>, _arg: ()) -> Result<&str> {
1907            Ok(self.label.as_str())
1908        }
1909
1910        fn values(&self, _dev: &Dev<Self>, _arg: ()) -> Result<&[f64]> {
1911            Ok(&self.values)
1912        }
1913
1914        fn set_label(&mut self, _dev: &Dev<Self>, arg: String) -> Result<&str> {
1915            self.label = arg;
1916            Ok(self.label.as_str())
1917        }
1918
1919        fn add(&self, _dev: &Dev<Self>, arg: i32) -> Result<i32> {
1920            Ok(self.count + arg)
1921        }
1922
1923        fn incr(&mut self, _dev: &Dev<Self>, arg: i32) -> Result<i32> {
1924            self.count += arg;
1925            Ok(self.count)
1926        }
1927
1928        // --- Attribute handlers, which are only given the device --- //
1929
1930        fn count(&self, _dev: &Dev<Self>) -> Result<i32> {
1931            Ok(self.count)
1932        }
1933
1934        fn set_count(&mut self, _dev: &Dev<Self>, arg: i32) -> Result<()> {
1935            self.count = arg;
1936            Ok(())
1937        }
1938
1939        /// A read giving the quality and the timestamp of the value along with it.
1940        fn count_full(&self, _dev: &Dev<Self>) -> Result<AttrRead<i32>> {
1941            Ok(AttrRead {
1942                value: Some(self.count),
1943                w_value: None,
1944                quality: AttrQuality::Valid,
1945                time: SystemTime::now(),
1946            })
1947        }
1948
1949        fn read_label(&self, _dev: &Dev<Self>) -> Result<&str> {
1950            Ok(self.label.as_str())
1951        }
1952
1953        fn read_values(&self, _dev: &Dev<Self>) -> Result<&[f64]> {
1954            Ok(&self.values)
1955        }
1956
1957        /// The handler shared by the commands of a dynamic set, the index of the command
1958        /// being captured by the closure forwarding to it.
1959        fn label_n(&self, _dev: &Dev<Self>, index: usize) -> Result<&str> {
1960            Ok(self.labels[index].as_str())
1961        }
1962
1963        /// A read updating the model, therefore needing an exclusive access to it.
1964        fn tick(&mut self, _dev: &Dev<Self>) -> Result<i32> {
1965            self.count += 1;
1966            Ok(self.count)
1967        }
1968
1969    }
1970
1971    /// A result that does not borrow from the model at all.
1972    fn version(_model: &Model, _dev: &Dev<Model>, _arg: ()) -> Result<&'static str> {
1973        Ok("1.0.0")
1974    }
1975
1976    /// Check that all the intended signatures are accepted, and that both kinds are
1977    /// always derived from the argument and result types.
1978    #[test]
1979    fn exec_signatures() {
1980
1981        // Scalar in, scalar out, as an associated method of the model.
1982        let def = CommandDef::<Model>::new("Add").exec(Model::add);
1983        assert_eq!(def.in_kind, Some(CommandDataKind::Long));
1984        assert_eq!(def.out_kind, Some(CommandDataKind::Long));
1985
1986        // Exclusive access to the model.
1987        let _ = CommandDef::<Model>::new("Incr").exec_exclusive(Model::incr);
1988
1989        // A closure is still accepted as long as its result does not borrow from the
1990        // model, but it has to annotate the two reference parameters.
1991        let _ = CommandDef::<Model>::new("Status")
1992            .exec(|model: &Model, _dev: &Dev<Model>, (): ()| Ok(model.label.clone()));
1993
1994        // A closure whose result borrows from the model is only accepted by the raw
1995        // form, see `closures_borrowing`.
1996        let def = CommandDef::<Model>::new("Label")
1997            .out_kind(CommandDataKind::String)
1998            .exec_with(|model: &Model, dev, value| {
1999                Ok(model.label(dev, <()>::from_value(value)?)?.into())
2000            });
2001        assert_eq!(def.out_kind, Some(CommandDataKind::String));
2002
2003        // Spectrum in, scalar out.
2004        let def = CommandDef::<Model>::new("Sum")
2005            .exec(|_model: &Model, _dev: &Dev<Model>, arg: Vec<f64>| Ok(arg.iter().sum::<f64>()));
2006        assert_eq!(def.in_kind, Some(CommandDataKind::DoubleArray));
2007        assert_eq!(def.out_kind, Some(CommandDataKind::Double));
2008
2009        // Spectrum in and out, owned or borrowed from the argument.
2010        let _ = CommandDef::<Model>::new("Scale")
2011            .exec(|_model: &Model, _dev: &Dev<Model>, arg: Vec<f64>| Ok(arg.iter().map(|v| v * 2.0).collect::<Vec<f64>>()));
2012        let _ = CommandDef::<Model>::new("Reverse")
2013            .exec(|_model: &Model, _dev: &Dev<Model>, arg: Vec<String>| Ok(arg.into_iter().rev().collect::<Vec<String>>()));
2014        let _ = CommandDef::<Model>::new("Zeros")
2015            .exec(|_model: &Model, _dev: &Dev<Model>, (): ()| Ok(Spectrum::<f64>::from(vec![0.0; 4])));
2016
2017        // A `&'static str` result.
2018        let def = CommandDef::<Model>::new("Version").exec(version);
2019        assert_eq!(def.out_kind, Some(CommandDataKind::String));
2020
2021        // A result borrowed from the model, both kinds still being derived.
2022        let def = CommandDef::<Model>::new("Label")
2023            .out_doc("The label of the device")
2024            .exec(Model::label);
2025        assert_eq!(def.in_kind, Some(CommandDataKind::Void));
2026        assert_eq!(def.out_kind, Some(CommandDataKind::String));
2027
2028        let def = CommandDef::<Model>::new("Values").exec(Model::values);
2029        assert_eq!(def.out_kind, Some(CommandDataKind::DoubleArray));
2030
2031        // Exclusive access to the model, with a result borrowed from it.
2032        let def = CommandDef::<Model>::new("SetLabel").exec_exclusive(Model::set_label);
2033        assert_eq!(def.in_kind, Some(CommandDataKind::String));
2034        assert_eq!(def.out_kind, Some(CommandDataKind::String));
2035
2036        // Raw form, with a result borrowed from the model, the kinds being explicit
2037        // because they cannot be derived from a raw `Value`.
2038        let def = CommandDef::<Model>::new("Status")
2039            .out_kind(CommandDataKind::String)
2040            .exec_with(|model: &Model, _dev, _value| Ok(model.label.as_str().into()));
2041        assert_eq!(def.in_kind, None);
2042        assert_eq!(def.out_kind, Some(CommandDataKind::String));
2043
2044        // Raw form, borrowing the argument value itself.
2045        let _ = CommandDef::<Model>::new("Echo")
2046            .in_kind(CommandDataKind::String)
2047            .out_kind(CommandDataKind::String)
2048            .exec_with(|model: &Model, _dev, value| {
2049                let arg = <&str>::try_from(&value)?;
2050                Ok(format!("{}{arg}", model.label).into())
2051            });
2052
2053        // Raw form with an exclusive access to the model, returning a borrow of it.
2054        let _ = CommandDef::<Model>::new("SetLabel")
2055            .in_kind(CommandDataKind::String)
2056            .out_kind(CommandDataKind::String)
2057            .exec_exclusive_with(|model: &mut Model, _dev, value| {
2058                model.label = String::try_from(value)?;
2059                Ok(model.label.as_str().into())
2060            });
2061
2062    }
2063
2064    /// Check that all the intended read and write signatures are accepted, and that the
2065    /// kind and the format are always derived from the value type.
2066    #[test]
2067    fn attr_signatures() {
2068
2069        // Scalar read and write, as associated methods of the model.
2070        let def = AttrDef::<Model>::new("Count")
2071            .read(Model::count)
2072            .write_exclusive(Model::set_count);
2073        assert_eq!(def.kind, Some(AttrDataKind::Long));
2074        assert_eq!(def.format, Some(AttrDataFormat::Scalar));
2075
2076        // A value borrowed from the model, scalar or spectrum.
2077        let def = AttrDef::<Model>::new("Label").read(Model::read_label);
2078        assert_eq!(def.kind, Some(AttrDataKind::String));
2079        assert_eq!(def.format, Some(AttrDataFormat::Scalar));
2080
2081        let def = AttrDef::<Model>::new("Values").read(Model::read_values);
2082        assert_eq!(def.kind, Some(AttrDataKind::Double));
2083        assert_eq!(def.format, Some(AttrDataFormat::Spectrum(0)));
2084
2085        // A full read result, giving the quality and the timestamp.
2086        let def = AttrDef::<Model>::new("CountFull").read(Model::count_full);
2087        assert_eq!(def.kind, Some(AttrDataKind::Long));
2088
2089        // Exclusive access to the model, for a read updating it.
2090        let _ = AttrDef::<Model>::new("Ticks").read_exclusive(Model::tick);
2091
2092        // A closure is accepted as long as its result does not borrow from the model.
2093        let _ = AttrDef::<Model>::new("Double")
2094            .read(|model: &Model, _dev: &Dev<Model>| Ok(model.count * 2));
2095
2096        // Raw form, the kind and the format having to be explicit.
2097        let _ = AttrDef::<Model>::new("Raw")
2098            .kind(AttrDataKind::Double)
2099            .format(AttrDataFormat::Spectrum(4096))
2100            .read_with(|model: &Model, _dev| Ok(AttrRead {
2101                value: Some(model.values.as_slice().into()),
2102                w_value: None,
2103                quality: AttrQuality::Valid,
2104                time: SystemTime::now(),
2105            }));
2106
2107    }
2108
2109    /// Check that every configuration builder writes the field of [`AttrConfig`] it is
2110    /// named after, which is what a device of the class then starts from.
2111    #[test]
2112    fn attr_config() {
2113
2114        let def = AttrDef::<Model>::new("Position")
2115            .read(Model::count)
2116            .doc("The position of the axis")
2117            .label("Position")
2118            .unit("mm")
2119            .standard_unit(1e-3)
2120            .display_unit("mm")
2121            .display_format("%8.3f")
2122            .display_level(DisplayLevel::Expert)
2123            .delta(0.5, Duration::from_millis(200))
2124            .change_event(0.001, None)
2125            .periodic_event(Duration::from_secs(1))
2126            .archive_event(0.1, None, Duration::from_secs(10))
2127            .memorized(AttrMemorized::RestoreAndWrite)
2128            .polled(Duration::from_millis(100));
2129
2130        assert_eq!(def.config.doc.as_deref(), Some("The position of the axis"));
2131        assert_eq!(def.config.label.as_deref(), Some("Position"));
2132        assert_eq!(def.config.unit.as_deref(), Some("mm"));
2133        assert_eq!(def.config.standard_unit, Some(1e-3));
2134        assert_eq!(def.config.display_unit.as_deref(), Some("mm"));
2135        assert_eq!(def.config.display_format.as_deref(), Some("%8.3f"));
2136        assert_eq!(def.display_level, DisplayLevel::Expert);
2137
2138        // The delta is a limit like the bounds are, so it is the number of the attribute
2139        // and not a double the value would have to be converted to.
2140        assert_eq!(def.config.delta, Some(AttrDeltaConfig {
2141            value: AttrNumber::Double(0.5),
2142            time: Some(Duration::from_millis(200)),
2143        }));
2144
2145        // The criteria of the events are not limits: an absolute change is a magnitude and
2146        // a relative one a percentage, so both stay doubles, and either may be left out.
2147        assert_eq!(def.config.change_event.abs_change, Some(0.001));
2148        assert_eq!(def.config.change_event.rel_change, None);
2149        assert_eq!(def.config.periodic_event.period, Some(Duration::from_secs(1)));
2150        assert_eq!(def.config.archive_event.abs_change, Some(0.1));
2151        assert_eq!(def.config.archive_event.period, Some(Duration::from_secs(10)));
2152
2153        assert_eq!(def.memorized, Some(AttrMemorized::RestoreAndWrite));
2154        assert_eq!(def.poll_period, Some(Duration::from_millis(100)));
2155
2156        // What is not defined stays absent rather than being given a value nobody asked
2157        // for, an attribute with no bound being the usual case.
2158        let def = AttrDef::<Model>::new("Count").read(Model::count);
2159        assert_eq!(def.config, AttrConfig::default());
2160        assert_eq!(def.poll_period, None);
2161
2162    }
2163
2164    /// Check the three ways a range is bounded, that a bound left open stays open, and
2165    /// that a range is the kind of number it was written with.
2166    #[test]
2167    fn attr_ranges() {
2168
2169        let def = AttrDef::<Model>::new("Position")
2170            .read(Model::count)
2171            .range(-100.0..=100.0)
2172            .warning(-90.5..)
2173            .alarm(..=95.0);
2174
2175        assert_eq!(def.config.range, AttrRangeConfig {
2176            min: Some(AttrNumber::Double(-100.0)),
2177            max: Some(AttrNumber::Double(100.0)),
2178        });
2179
2180        // Only bounded below: an attribute that cannot go under that and has no ceiling.
2181        assert_eq!(def.config.warning, AttrRangeConfig {
2182            min: Some(AttrNumber::Double(-90.5)),
2183            max: None,
2184        });
2185
2186        // And only bounded above.
2187        assert_eq!(def.config.alarm, AttrRangeConfig {
2188            min: None,
2189            max: Some(AttrNumber::Double(95.0)),
2190        });
2191
2192        // An integer attribute is bounded with integers, which are held as such rather
2193        // than being rounded into a double: this is the whole point of the three kinds.
2194        let def = AttrDef::<Model>::new("Count")
2195            .read(Model::count)
2196            .range(-8..=8i32)
2197            .alarm(..=u64::MAX);
2198
2199        assert_eq!(def.config.range, AttrRangeConfig {
2200            min: Some(AttrNumber::Long(-8)),
2201            max: Some(AttrNumber::Long(8)),
2202        });
2203        assert_eq!(def.config.alarm.max, Some(AttrNumber::ULong(u64::MAX)));
2204
2205        // Two limits a double cannot tell apart, which is the whole reason they are not
2206        // doubles: kept as they are they differ, converted they are the same number.
2207        assert_ne!(AttrNumber::ULong(u64::MAX), AttrNumber::ULong(u64::MAX - 1));
2208        assert_eq!(AttrNumber::ULong(u64::MAX).as_f64(), AttrNumber::ULong(u64::MAX - 1).as_f64());
2209
2210        // Two limits of different kinds are equal when they stand for the same number.
2211        assert_eq!(AttrNumber::Long(2), AttrNumber::Double(2.0));
2212        assert!(AttrNumber::Long(-1) < AttrNumber::ULong(0));
2213        assert!(AttrNumber::ULong(u64::MAX) > AttrNumber::ULong(u64::MAX - 1));
2214        assert_ne!(AttrNumber::Double(f64::NAN), AttrNumber::Double(f64::NAN));
2215
2216    }
2217
2218    #[test]
2219    #[should_panic(expected = "the value range cannot have an exclusive bound")]
2220    fn exclusive_range_bound() {
2221        let _ = AttrDef::<Model>::new("Position").range(-100.0..100.0);
2222    }
2223
2224    /// Check that the three layout methods are the formats they stand for, and that they
2225    /// merge with what a handler derived the way [`AttrDef::format`] does.
2226    #[test]
2227    fn attr_layouts() {
2228
2229        let def = AttrDef::<Model>::new("Count").read(Model::count).scalar();
2230        assert_eq!(def.format, Some(AttrDataFormat::Scalar));
2231
2232        // The layout comes from the handler and only the maximum size from here, in
2233        // either order.
2234        let def = AttrDef::<Model>::new("Values").read(Model::read_values).spectrum(4096);
2235        assert_eq!(def.format, Some(AttrDataFormat::Spectrum(4096)));
2236
2237        let def = AttrDef::<Model>::new("Values").spectrum(4096).read(Model::read_values);
2238        assert_eq!(def.kind, Some(AttrDataKind::Double));
2239        assert_eq!(def.format, Some(AttrDataFormat::Spectrum(4096)));
2240
2241        // Nothing is derived from a raw handler, so both are stated outright.
2242        let def = AttrDef::<Model>::new("Frame")
2243            .kind(AttrDataKind::Double)
2244            .image(640, 480);
2245        assert_eq!(def.format, Some(AttrDataFormat::Image(640, 480)));
2246
2247        // A maximum of zero is the undefined one, which any size then matches.
2248        let def = AttrDef::<Model>::new("Values").read(Model::read_values).spectrum(0);
2249        assert_eq!(def.format, Some(AttrDataFormat::Spectrum(0)));
2250
2251    }
2252
2253    #[test]
2254    #[should_panic(expected = "the data format is already defined as Scalar")]
2255    fn incompatible_layout() {
2256        let _ = AttrDef::<Model>::new("Count").read(Model::count).spectrum(8);
2257    }
2258
2259    /// Check what a command has of a configuration, which is a good deal less than an
2260    /// attribute: Tango tells a client the display level and nothing else about it.
2261    #[test]
2262    fn command_config() {
2263
2264        let def = CommandDef::<Model>::new("Add")
2265            .exec(Model::add)
2266            .display_level(DisplayLevel::Expert)
2267            .polled(Duration::from_secs(1));
2268
2269        assert_eq!(def.display_level, DisplayLevel::Expert);
2270        assert_eq!(def.poll_period, Some(Duration::from_secs(1)));
2271
2272        // The level everything is at unless it says otherwise.
2273        let def = CommandDef::<Model>::new("Add").exec(Model::add);
2274        assert_eq!(def.display_level, DisplayLevel::Operator);
2275        assert_eq!(def.poll_period, None);
2276
2277    }
2278
2279    /// The description of a class is the one every device of it gives of itself.
2280    #[test]
2281    fn class_doc() {
2282        let def = ClassDef::<Model>::new_default("Motor").doc("A single axis");
2283        assert_eq!(def.doc, "A single axis");
2284        let def = ClassDef::<Model>::new_default("Motor");
2285        assert_eq!(def.doc, "A Tango device");
2286    }
2287
2288    /// Check that an explicit kind or format completes the one derived from a handler,
2289    /// in any order, as long as they do not contradict each other.
2290    #[test]
2291    fn compatible_kinds() {
2292
2293        // The same kind given twice, before or after the execution function.
2294        let def = CommandDef::<Model>::new("Add")
2295            .in_kind(CommandDataKind::Long)
2296            .exec(Model::add)
2297            .out_kind(CommandDataKind::Long);
2298        assert_eq!(def.in_kind, Some(CommandDataKind::Long));
2299        assert_eq!(def.out_kind, Some(CommandDataKind::Long));
2300
2301        // An undefined maximum size being completed by an explicit format, the derived
2302        // kind being kept in both orders.
2303        let def = AttrDef::<Model>::new("Values")
2304            .read(Model::read_values)
2305            .format(AttrDataFormat::Spectrum(4096));
2306        assert_eq!(def.kind, Some(AttrDataKind::Double));
2307        assert_eq!(def.format, Some(AttrDataFormat::Spectrum(4096)));
2308
2309        let def = AttrDef::<Model>::new("Values")
2310            .format(AttrDataFormat::Spectrum(4096))
2311            .read(Model::read_values);
2312        assert_eq!(def.format, Some(AttrDataFormat::Spectrum(4096)));
2313
2314    }
2315
2316    #[test]
2317    #[should_panic(expected = "the argument kind is already defined as String")]
2318    fn incompatible_in_kind() {
2319        let _ = CommandDef::<Model>::new("Add")
2320            .in_kind(CommandDataKind::String)
2321            .exec(Model::add);
2322    }
2323
2324    #[test]
2325    #[should_panic(expected = "the result kind is already defined as Long")]
2326    fn incompatible_out_kind() {
2327        let _ = CommandDef::<Model>::new("Add")
2328            .exec(Model::add)
2329            .out_kind(CommandDataKind::Long64);
2330    }
2331
2332    #[test]
2333    #[should_panic(expected = "the data kind is already defined as String")]
2334    fn incompatible_attr_kind() {
2335        let _ = AttrDef::<Model>::new("Label")
2336            .read(Model::read_label)
2337            .write_exclusive(Model::set_count);
2338    }
2339
2340    #[test]
2341    #[should_panic(expected = "the data format is already defined as Scalar")]
2342    fn incompatible_attr_format() {
2343        let _ = AttrDef::<Model>::new("Count")
2344            .read(Model::count)
2345            .format(AttrDataFormat::Spectrum(8));
2346    }
2347
2348    #[test]
2349    #[should_panic(expected = "the maximum size is already defined as 8")]
2350    fn incompatible_attr_max() {
2351        let _ = AttrDef::<Model>::new("Values")
2352            .format(AttrDataFormat::Spectrum(8))
2353            .format(AttrDataFormat::Spectrum(4096));
2354    }
2355
2356
2357    #[test]
2358    #[should_panic(expected = "Test: the attribute Label cannot have the property \"max_alarm\", not supported by an attribute of type String")]
2359    fn unsupported_attr_prop() {
2360        let _ = ClassDef::<Model>::new_default("Test")
2361            .attr(AttrDef::new("Label")
2362                .read(Model::read_label)
2363                .alarm(..=5));
2364    }
2365
2366    #[test]
2367    #[should_panic(expected = "the attribute State cannot have the property \"min_value\", not supported by an attribute of type State")]
2368    fn unsupported_state_prop() {
2369        let _ = ClassDef::<Model>::new_default("Test")
2370            .state_config(AttrConfig { range: AttrRangeConfig { min: Some(AttrNumber::Long(0)), max: None }, ..AttrConfig::default() });
2371    }
2372
2373    #[test]
2374    #[should_panic(expected = "the attribute Count cannot be memorized, it is not writable")]
2375    fn memorized_read_only() {
2376        let _ = ClassDef::<Model>::new_default("Test")
2377            .attr(AttrDef::new("Count")
2378                .read(Model::count)
2379                .memorized(AttrMemorized::RestoreSetPoint));
2380    }
2381
2382    #[test]
2383    #[should_panic(expected = "the attribute Values cannot be memorized, it is not a scalar")]
2384    fn memorized_spectrum() {
2385        let _ = ClassDef::<Model>::new_default("Test")
2386            .attr(AttrDef::new("Values")
2387                .memorized(AttrMemorized::RestoreAndWrite)
2388                .kind(AttrDataKind::Double)
2389                .format(AttrDataFormat::Spectrum(8))
2390                .write_with(|_model: &Model, _dev, _value| Ok(())));
2391    }
2392
2393    /// Check the way a closure borrowing from the model is defined: only the raw form
2394    /// accepts it, its result being converted into a [`Value`] before the borrow ends,
2395    /// and the advertised kinds then being explicit.
2396    #[test]
2397    fn closures_borrowing() {
2398
2399        // The dynamic command case: several commands sharing a single handler, each
2400        // closure capturing the index of its own command.
2401        for index in 0..3 {
2402            let def = CommandDef::<Model>::new(format!("Label{index}"))
2403                .out_kind(CommandDataKind::String)
2404                .exec_with(move |model: &Model, dev, _value| {
2405                    Ok(model.label_n(dev, index)?.into())
2406                });
2407            assert_eq!(def.out_kind, Some(CommandDataKind::String));
2408        }
2409
2410        // With an exclusive access to the model, the result borrowing what was written.
2411        let _ = CommandDef::<Model>::new("Push")
2412            .in_kind(CommandDataKind::String)
2413            .out_kind(CommandDataKind::String)
2414            .exec_exclusive_with(|model: &mut Model, _dev, value| {
2415                model.labels.push(String::try_from(value)?);
2416                Ok(model.labels.last().unwrap().as_str().into())
2417            });
2418
2419        // The same for the read function of a dynamic attribute.
2420        for index in 0..3 {
2421            let def = AttrDef::<Model>::new(format!("Label{index}"))
2422                .kind(AttrDataKind::String)
2423                .format(AttrDataFormat::Scalar)
2424                .read_with(move |model: &Model, dev| {
2425                    Ok(AttrRead {
2426                        value: Some(model.label_n(dev, index)?.into()),
2427                        w_value: None,
2428                        quality: AttrQuality::Valid,
2429                        time: SystemTime::now(),
2430                    })
2431                });
2432            assert_eq!(def.kind, Some(AttrDataKind::String));
2433        }
2434
2435    }
2436
2437    /// A model owning what it borrowed from outside of the device, which is what the
2438    /// `'static` bound asks of it: a class lives as long as the server serving it, so a
2439    /// model borrowing from a shorter lifetime has nothing to be borrowed from by then.
2440    struct Owning { values: Vec<f64> }
2441
2442    impl Owning {
2443        fn len(&self, _dev: &Dev<Self>, _arg: ()) -> Result<i32> { Ok(self.values.len() as i32) }
2444        fn first(&self, _dev: &Dev<Self>) -> Result<f64> { Ok(self.values[0]) }
2445    }
2446
2447    /// The definitions of such a model are `'static` themselves, so they can be given to a
2448    /// class without being tied to the scope they were written in.
2449    fn owning_defs(prefix: &str) -> (CommandDef<Owning>, AttrDef<Owning>) {
2450        let command = CommandDef::<Owning>::new("Len")
2451            .exec(Owning::len)
2452            .out_doc(prefix.to_owned());
2453        let attr = AttrDef::<Owning>::new("First")
2454            .read(Owning::first)
2455            // A handler capturing what it needs by value, the definition outliving the
2456            // scope it was built in.
2457            .write_with({
2458                let prefix = prefix.to_owned();
2459                move |_model: &Owning, _dev, _value| {
2460                    let _ = &prefix;
2461                    Ok(())
2462                }
2463            });
2464        (command, attr)
2465    }
2466
2467    #[test]
2468    fn model_owned() {
2469        let values = vec![1.0, 2.0, 3.0];
2470        let prefix = format!("{} values", values.len());
2471        let (command, attr) = owning_defs(&prefix);
2472        drop(prefix);
2473        assert_eq!(command.out_kind, Some(CommandDataKind::Long));
2474        assert_eq!(attr.kind, Some(AttrDataKind::Double));
2475    }
2476
2477    /// The asynchronous counterparts of the handlers of [`Model`], written as `async fn`
2478    /// methods, which is what the typed async definitions are meant to take.
2479    struct AsyncModel { count: i32, label: String }
2480
2481    impl AsyncModel {
2482
2483        async fn add(&self, _dev: &Dev<Self>, arg: i32) -> Result<i32> {
2484            Ok(self.count + arg)
2485        }
2486
2487        async fn label(&self, _dev: &Dev<Self>, _arg: ()) -> Result<&str> {
2488            Ok(self.label.as_str())
2489        }
2490
2491        async fn incr(&mut self, _dev: &Dev<Self>, arg: i32) -> Result<i32> {
2492            self.count += arg;
2493            Ok(self.count)
2494        }
2495
2496        async fn count(&self, _dev: &Dev<Self>) -> Result<i32> {
2497            Ok(self.count)
2498        }
2499
2500        async fn set_count(&mut self, _dev: &Dev<Self>, arg: i32) -> Result<()> {
2501            self.count = arg;
2502            Ok(())
2503        }
2504
2505        async fn read_label(&self, _dev: &Dev<Self>) -> Result<&str> {
2506            Ok(self.label.as_str())
2507        }
2508
2509        async fn check_label(&self, _dev: &Dev<Self>, arg: String) -> Result<()> {
2510            let _ = arg.len();
2511            Ok(())
2512        }
2513
2514        async fn tick(&mut self, _dev: &Dev<Self>) -> Result<i32> {
2515            self.count += 1;
2516            Ok(self.count)
2517        }
2518
2519        async fn state(&self, _dev: &Dev<Self>) -> Result<DevState> {
2520            Ok(DevState::On)
2521        }
2522
2523        async fn status(&mut self, _dev: &Dev<Self>) -> Result<Cow<'_, str>> {
2524            Ok(Cow::Borrowed(self.label.as_str()))
2525        }
2526
2527    }
2528
2529    /// Check that the async execution functions are accepted as `async fn` methods and as
2530    /// boxing closures, that both kinds are derived as for the sync ones, and that each
2531    /// definition is stored with the access it asked for.
2532    #[test]
2533    fn exec_async_signatures() {
2534
2535        let def = CommandDef::<AsyncModel>::new("Add").exec_async(AsyncModel::add);
2536        assert_eq!(def.in_kind, Some(CommandDataKind::Long));
2537        assert_eq!(def.out_kind, Some(CommandDataKind::Long));
2538        assert!(matches!(def.exec, Some(ExecFn::SharedAsync(_))));
2539
2540        // A result borrowed from the model across the future.
2541        let def = CommandDef::<AsyncModel>::new("Label").exec_async(AsyncModel::label);
2542        assert_eq!(def.in_kind, Some(CommandDataKind::Void));
2543        assert_eq!(def.out_kind, Some(CommandDataKind::String));
2544
2545        let def = CommandDef::<AsyncModel>::new("Incr").exec_exclusive_async(AsyncModel::incr);
2546        assert_eq!(def.in_kind, Some(CommandDataKind::Long));
2547        assert!(matches!(def.exec, Some(ExecFn::ExclusiveAsync(_))));
2548
2549        // Raw forms, whose closures box their future themselves and give no kind.
2550        let def = CommandDef::<AsyncModel>::new("Echo")
2551            .in_kind(CommandDataKind::String)
2552            .out_kind(CommandDataKind::String)
2553            .exec_async_with(|model: &AsyncModel, _dev, value| Box::pin(async move {
2554                let arg = <&str>::try_from(&value)?;
2555                Ok(format!("{}{arg}", model.label).into())
2556            }));
2557        assert_eq!(def.in_kind, Some(CommandDataKind::String));
2558        assert!(matches!(def.exec, Some(ExecFn::SharedAsync(_))));
2559
2560        let def = CommandDef::<AsyncModel>::new("SetLabel")
2561            .exec_exclusive_async_with(|model: &mut AsyncModel, _dev, value| Box::pin(async move {
2562                model.label = String::try_from(value)?;
2563                Ok(model.label.as_str().into())
2564            }));
2565        assert_eq!(def.in_kind, None);
2566        assert_eq!(def.out_kind, None);
2567        assert!(matches!(def.exec, Some(ExecFn::ExclusiveAsync(_))));
2568
2569    }
2570
2571    /// Check the same for the async read and write functions of an attribute.
2572    #[test]
2573    fn attr_async_signatures() {
2574
2575        let def = AttrDef::<AsyncModel>::new("Count")
2576            .read_async(AsyncModel::count)
2577            .write_exclusive_async(AsyncModel::set_count);
2578        assert_eq!(def.kind, Some(AttrDataKind::Long));
2579        assert_eq!(def.format, Some(AttrDataFormat::Scalar));
2580        assert!(matches!(def.read, Some(ReadFn::SharedAsync(_))));
2581        assert!(matches!(def.write, Some(WriteFn::ExclusiveAsync(_))));
2582
2583        let def = AttrDef::<AsyncModel>::new("Label")
2584            .read_async(AsyncModel::read_label)
2585            .write_async(AsyncModel::check_label);
2586        assert_eq!(def.kind, Some(AttrDataKind::String));
2587        assert!(matches!(def.write, Some(WriteFn::SharedAsync(_))));
2588
2589        let def = AttrDef::<AsyncModel>::new("Ticks").read_exclusive_async(AsyncModel::tick);
2590        assert!(matches!(def.read, Some(ReadFn::ExclusiveAsync(_))));
2591
2592        let def = AttrDef::<AsyncModel>::new("Raw")
2593            .kind(AttrDataKind::Long)
2594            .scalar()
2595            .read_async_with(|model: &AsyncModel, _dev| Box::pin(async move {
2596                Ok(AttrRead {
2597                    value: Some(model.count.into()),
2598                    w_value: None,
2599                    quality: AttrQuality::Valid,
2600                    time: SystemTime::now(),
2601                })
2602            }))
2603            .write_exclusive_async_with(|model: &mut AsyncModel, _dev, value| Box::pin(async move {
2604                model.count = i32::try_from(value)?;
2605                Ok(())
2606            }));
2607        assert!(matches!(def.read, Some(ReadFn::SharedAsync(_))));
2608        assert!(matches!(def.write, Some(WriteFn::ExclusiveAsync(_))));
2609
2610    }
2611
2612    #[test]
2613    #[should_panic(expected = "the data kind is already defined as String")]
2614    fn incompatible_attr_async_kind() {
2615        let _ = AttrDef::<AsyncModel>::new("Label")
2616            .read_async(AsyncModel::read_label)
2617            .write_exclusive_async(AsyncModel::set_count);
2618    }
2619
2620    /// Check that the async state and status functions are stored with the access they
2621    /// asked for, a later definition replacing an earlier one.
2622    #[test]
2623    fn class_async_handlers() {
2624
2625        let def = ClassDef::<AsyncModel>::new("Motor", |_dev| Ok(AsyncModel { count: 0, label: String::new() }))
2626            .state_async(AsyncModel::state)
2627            .status_exclusive_async(AsyncModel::status);
2628        assert!(matches!(def.state, Some(StateFn::SharedAsync(_))));
2629        assert!(matches!(def.status, Some(StatusFn::ExclusiveAsync(_))));
2630
2631        let def = def
2632            .state_exclusive_async_with(|_model: &mut AsyncModel, _dev| Box::pin(async { Ok(DevState::Moving) }))
2633            .status_async_with(|model: &AsyncModel, _dev| Box::pin(async move { Ok(Cow::Borrowed(model.label.as_str())) }));
2634        assert!(matches!(def.state, Some(StateFn::ExclusiveAsync(_))));
2635        assert!(matches!(def.status, Some(StatusFn::SharedAsync(_))));
2636
2637    }
2638
2639}