1use 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#[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#[track_caller]
38fn merge_format(def: &str, current: Option<AttrDataFormat>, new: AttrDataFormat) -> AttrDataFormat {
39 let Some(current) = current else { return new };
40 match (¤t, &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#[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#[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#[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
105struct 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
116macro_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
135pub struct ClassDef<M: Model> {
137 pub(super) name: Cow<'static, str>,
139 pub(super) doc: Cow<'static, str>,
142 pub(super) doc_url: Option<Cow<'static, str>>,
146 pub(super) init: InitFn<M>,
148 pub(super) delete: Option<DeleteFn<M>>,
150 pub(super) state: Option<StateFn<M>>,
152 pub(super) status: Option<StatusFn<M>>,
154 pub(super) commands: Vec<Arc<CommandDef<M>>>,
161 pub(super) attrs: Vec<Arc<AttrDef<M>>>,
163 pub(super) state_attr: Arc<AttrDef<M>>,
166 pub(super) status_attr: Arc<AttrDef<M>>,
168}
169
170pub 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}
176pub 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
183pub 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
195pub 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
203pub trait HandlerAsync<'a, R, M: Model, O> {
210 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
225pub trait InitAsync<'a, M: Model> {
229 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
244pub trait DeleteAsync<'a, M: Model> {
249 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 #[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 #[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 #[track_caller]
567 pub fn state_config(mut self, config: AttrConfig) -> Self {
568 self.state_attr = state_attr(config);
569 self
570 }
571
572 #[track_caller]
580 pub fn status_config(mut self, config: AttrConfig) -> Self {
581 self.status_attr = status_attr(config);
582 self
583 }
584
585 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 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#[track_caller]
603fn state_attr<M: Model>(config: AttrConfig) -> Arc<AttrDef<M>> {
604 builtin_attr(STATE_NAME, AttrDataKind::State, config)
605}
606
607#[track_caller]
609fn status_attr<M: Model>(config: AttrConfig) -> Arc<AttrDef<M>> {
610 builtin_attr(STATUS_NAME, AttrDataKind::String, config)
611}
612
613fn 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#[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#[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
663pub struct CommandDef<M: Model> {
665 pub(super) name: Cow<'static, str>,
667 pub(super) exec: Option<ExecFn<M>>,
669 pub(super) in_kind: Option<CommandDataKind>,
672 pub(super) in_doc: Cow<'static, str>,
674 pub(super) out_kind: Option<CommandDataKind>,
677 pub(super) out_doc: Cow<'static, str>,
679 pub(super) display_level: DisplayLevel,
682 pub(super) poll_period: Option<Duration>,
685}
686
687pub 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
696pub trait ExecShared<'m, M: Model, I> {
699 const IN_KIND: CommandDataKind;
701 const OUT_KIND: CommandDataKind;
703 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
724pub trait ExecExclusive<'m, M: Model, I> {
726 const IN_KIND: CommandDataKind;
728 const OUT_KIND: CommandDataKind;
730 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
751pub trait ExecAsync<'a, R, M: Model, I> {
757 const IN_KIND: CommandDataKind;
759 const OUT_KIND: CommandDataKind;
761 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 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 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 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 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 pub fn display_level(mut self, level: DisplayLevel) -> Self {
830 self.display_level = level;
831 self
832 }
833
834 pub fn polled(mut self, period: Duration) -> Self {
841 self.poll_period = Some(period);
842 self
843 }
844
845 #[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 #[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 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 #[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 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 #[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 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 #[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 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 #[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
1019pub struct AttrDef<M: Model> {
1021 pub(super) name: Cow<'static, str>,
1023 pub(super) read: Option<ReadFn<M>>,
1025 pub(super) write: Option<WriteFn<M>>,
1027 pub(super) kind: Option<AttrDataKind>,
1029 pub(super) format: Option<AttrDataFormat>,
1031 pub(super) display_level: DisplayLevel,
1034 pub(super) memorized: Option<AttrMemorized>,
1037 pub(super) config: AttrConfig,
1042 pub(super) poll_period: Option<Duration>,
1045 pub(super) pushed: PushedEvents,
1048}
1049
1050#[derive(Debug, Clone, Copy, Default)]
1054pub(super) struct PushedEvents {
1055 pub change: Option<bool>,
1056 pub archive: Option<bool>,
1057}
1058
1059pub 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
1068pub 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
1077pub trait ReadOutput {
1080 const DATA_KIND: AttrDataKind;
1082 const DATA_FORMAT: AttrDataFormat;
1084 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 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
1132pub trait ReadShared<'m, M: Model> {
1136 const DATA_KIND: AttrDataKind;
1138 const DATA_FORMAT: AttrDataFormat;
1140 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
1158pub trait ReadExclusive<'m, M: Model> {
1160 const DATA_KIND: AttrDataKind;
1162 const DATA_FORMAT: AttrDataFormat;
1164 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
1182pub trait WriteShared<M: Model, I> {
1184 const DATA_KIND: AttrDataKind;
1186 const DATA_FORMAT: AttrDataFormat;
1188 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
1206pub trait WriteExclusive<M: Model, I> {
1208 const DATA_KIND: AttrDataKind;
1210 const DATA_FORMAT: AttrDataFormat;
1212 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
1230pub trait ReadAsync<'a, R, M: Model> {
1235 const DATA_KIND: AttrDataKind;
1237 const DATA_FORMAT: AttrDataFormat;
1239 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
1259pub trait WriteAsync<'a, R, M: Model, I> {
1263 const DATA_KIND: AttrDataKind;
1265 const DATA_FORMAT: AttrDataFormat;
1267 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 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 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 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 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 pub fn standard_unit(mut self, factor: f64) -> Self {
1344 self.config.standard_unit = Some(factor);
1345 self
1346 }
1347
1348 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 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 pub fn display_level(mut self, level: DisplayLevel) -> Self {
1371 self.display_level = level;
1372 self
1373 }
1374
1375 #[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 #[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 #[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 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 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 pub fn periodic_event(mut self, period: Duration) -> Self {
1473 self.config.periodic_event.period = Some(period);
1474 self
1475 }
1476
1477 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 pub fn push_change_event(mut self, detect: bool) -> Self {
1502 self.pushed.change = Some(detect);
1503 self
1504 }
1505
1506 pub fn push_archive_event(mut self, detect: bool) -> Self {
1509 self.pushed.archive = Some(detect);
1510 self
1511 }
1512
1513 pub fn memorized(mut self, mode: AttrMemorized) -> Self {
1523 self.memorized = Some(mode);
1524 self
1525 }
1526
1527 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 pub fn polled(mut self, period: Duration) -> Self {
1561 self.poll_period = Some(period);
1562 self
1563 }
1564
1565 #[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 #[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 #[track_caller]
1605 pub fn scalar(self) -> Self {
1606 self.format(AttrDataFormat::Scalar)
1607 }
1608
1609 #[track_caller]
1620 pub fn spectrum(self, max_size: usize) -> Self {
1621 self.format(AttrDataFormat::Spectrum(max_size))
1622 }
1623
1624 #[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 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 #[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 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 #[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 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 #[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 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 #[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 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 #[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 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 #[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 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 #[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 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 #[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 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 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 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 fn label_n(&self, _dev: &Dev<Self>, index: usize) -> Result<&str> {
1960 Ok(self.labels[index].as_str())
1961 }
1962
1963 fn tick(&mut self, _dev: &Dev<Self>) -> Result<i32> {
1965 self.count += 1;
1966 Ok(self.count)
1967 }
1968
1969 }
1970
1971 fn version(_model: &Model, _dev: &Dev<Model>, _arg: ()) -> Result<&'static str> {
1973 Ok("1.0.0")
1974 }
1975
1976 #[test]
1979 fn exec_signatures() {
1980
1981 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 let _ = CommandDef::<Model>::new("Incr").exec_exclusive(Model::incr);
1988
1989 let _ = CommandDef::<Model>::new("Status")
1992 .exec(|model: &Model, _dev: &Dev<Model>, (): ()| Ok(model.label.clone()));
1993
1994 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 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 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 let def = CommandDef::<Model>::new("Version").exec(version);
2019 assert_eq!(def.out_kind, Some(CommandDataKind::String));
2020
2021 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 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 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 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 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 #[test]
2067 fn attr_signatures() {
2068
2069 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 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 let def = AttrDef::<Model>::new("CountFull").read(Model::count_full);
2087 assert_eq!(def.kind, Some(AttrDataKind::Long));
2088
2089 let _ = AttrDef::<Model>::new("Ticks").read_exclusive(Model::tick);
2091
2092 let _ = AttrDef::<Model>::new("Double")
2094 .read(|model: &Model, _dev: &Dev<Model>| Ok(model.count * 2));
2095
2096 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 #[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 assert_eq!(def.config.delta, Some(AttrDeltaConfig {
2141 value: AttrNumber::Double(0.5),
2142 time: Some(Duration::from_millis(200)),
2143 }));
2144
2145 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 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 #[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 assert_eq!(def.config.warning, AttrRangeConfig {
2182 min: Some(AttrNumber::Double(-90.5)),
2183 max: None,
2184 });
2185
2186 assert_eq!(def.config.alarm, AttrRangeConfig {
2188 min: None,
2189 max: Some(AttrNumber::Double(95.0)),
2190 });
2191
2192 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 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 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 #[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 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 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 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 #[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 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 #[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 #[test]
2291 fn compatible_kinds() {
2292
2293 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 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 #[test]
2397 fn closures_borrowing() {
2398
2399 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 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 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 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 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 .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 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 #[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 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 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 #[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 #[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}