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, Scalar, Value};
14use crate::error::Result;
15use crate::name;
16
17use super::{reserved_name, Model, RESERVED_ATTRS, RESERVED_COMMANDS, STATE_NAME, STATUS_NAME};
18use super::attr::{unsupported, unsupported_prop};
19use super::dev::Dev;
20
21
22#[track_caller]
27fn merge_kind<K: PartialEq + Debug>(def: &str, what: &str, current: Option<K>, new: K) -> K {
28 match current {
29 Some(current) if current != new => panic!(
30 "{def}: the {what} is already defined as {current:?}, incompatible with {new:?}"),
31 _ => new,
32 }
33}
34
35#[track_caller]
39fn merge_format(def: &str, current: Option<AttrDataFormat>, new: AttrDataFormat) -> AttrDataFormat {
40 let Some(current) = current else { return new };
41 match (¤t, &new) {
42 (AttrDataFormat::Scalar, AttrDataFormat::Scalar) => AttrDataFormat::Scalar,
43 (AttrDataFormat::Spectrum(cur), AttrDataFormat::Spectrum(new)) => {
44 AttrDataFormat::Spectrum(merge_max(def, "maximum size", *cur, *new))
45 }
46 (AttrDataFormat::Image(cur_x, cur_y), AttrDataFormat::Image(new_x, new_y)) => {
47 AttrDataFormat::Image(
48 merge_max(def, "maximum width", *cur_x, *new_x),
49 merge_max(def, "maximum height", *cur_y, *new_y),
50 )
51 }
52 _ => panic!(
53 "{def}: the data format is already defined as {current:?}, incompatible with {new:?}"),
54 }
55}
56
57#[track_caller]
61fn merge_max(def: &str, what: &str, current: usize, new: usize) -> usize {
62 match (current, new) {
63 (0, new) => new,
64 (current, 0) => current,
65 (current, new) if current != new => panic!(
66 "{def}: the {what} is already defined as {current}, incompatible with {new}"),
67 (current, _) => current,
68 }
69}
70
71#[track_caller]
75fn range_config<T, R>(def: &str, what: &str, range: R) -> AttrRangeConfig
76where
77 T: Into<AttrNumber> + Copy,
78 R: RangeBounds<T>,
79{
80 AttrRangeConfig {
81 min: bound_value(def, what, range.start_bound()),
82 max: bound_value(def, what, range.end_bound()),
83 }
84}
85
86#[track_caller]
94fn bound_value<T>(def: &str, what: &str, bound: Bound<&T>) -> Option<AttrNumber>
95where
96 T: Into<AttrNumber> + Copy,
97{
98 match bound {
99 Bound::Included(value) => Some((*value).into()),
100 Bound::Unbounded => None,
101 Bound::Excluded(_) => panic!(
102 "{def}: the {what} cannot have an exclusive bound, Tango only has inclusive ones"),
103 }
104}
105
106struct HandlerDebug;
109
110impl Debug for HandlerDebug {
111 #[inline]
112 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113 f.write_str("..")
114 }
115}
116
117macro_rules! impl_handler_debug {
120 ($($handler:ident),* $(,)?) => { $(
121 impl<M: Model> Debug for $handler<M> {
122 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123 f.write_str(match self {
124 Self::SharedSync(_) => "SharedSync(..)",
125 Self::ExclusiveSync(_) => "ExclusiveSync(..)",
126 Self::SharedAsync(_) => "SharedAsync(..)",
127 Self::ExclusiveAsync(_) => "ExclusiveAsync(..)",
128 })
129 }
130 }
131 )* };
132}
133
134impl_handler_debug!(StateFn, StatusFn, ExecFn, ReadFn, WriteFn);
135
136pub struct ClassDef<M: Model> {
138 pub(super) name: Cow<'static, str>,
140 pub(super) doc: Cow<'static, str>,
143 pub(super) doc_url: Option<Cow<'static, str>>,
147 pub(super) init: InitFn<M>,
149 pub(super) delete: Option<DeleteFn<M>>,
151 pub(super) state: Option<StateFn<M>>,
153 pub(super) status: Option<StatusFn<M>>,
155 pub(super) commands: Vec<Arc<CommandDef<M>>>,
162 pub(super) attrs: Vec<Arc<AttrDef<M>>>,
164 pub(super) state_attr: Arc<AttrDef<M>>,
167 pub(super) status_attr: Arc<AttrDef<M>>,
169}
170
171pub enum InitFn<M: Model> {
174 Sync(Box<dyn for<'ctx> Fn(&'ctx Dev<M>) -> Result<M> + Send + Sync>),
175 Async(Box<dyn for<'a> Fn(&'a Dev<M>) -> BoxFuture<'a, Result<M>> + Send + Sync>),
176}
177pub enum DeleteFn<M: Model> {
180 Sync(Box<dyn for<'ctx> Fn(M, &'ctx Dev<M>) + Send + Sync>),
181 Async(Box<dyn for<'a> Fn(M, &'a Dev<M>) -> BoxFuture<'a, ()> + Send + Sync>),
182}
183
184pub enum StateFn<M: Model> {
190 SharedSync(Box<dyn for<'m, 'ctx> Fn(&'m M, &'ctx Dev<M>) -> Result<DevState> + Send + Sync>),
191 ExclusiveSync(Box<dyn for<'m, 'ctx> Fn(&'m mut M, &'ctx Dev<M>) -> Result<DevState> + Send + Sync>),
192 SharedAsync(Box<dyn for<'a> Fn(&'a M, &'a Dev<M>) -> BoxFuture<'a, Result<DevState>> + Send + Sync>),
193 ExclusiveAsync(Box<dyn for<'a> Fn(&'a mut M, &'a Dev<M>) -> BoxFuture<'a, Result<DevState>> + Send + Sync>),
194}
195
196pub enum StatusFn<M: Model> {
198 SharedSync(Box<dyn for<'m, 'ctx> Fn(&'m M, &'ctx Dev<M>) -> Result<Scalar<str>> + Send + Sync>),
199 ExclusiveSync(Box<dyn for<'m, 'ctx> Fn(&'m mut M, &'ctx Dev<M>) -> Result<Scalar<str>> + Send + Sync>),
200 SharedAsync(Box<dyn for<'a> Fn(&'a M, &'a Dev<M>) -> BoxFuture<'a, Result<Scalar<str>>> + Send + Sync>),
201 ExclusiveAsync(Box<dyn for<'a> Fn(&'a mut M, &'a Dev<M>) -> BoxFuture<'a, Result<Scalar<str>>> + Send + Sync>),
202}
203
204pub trait HandlerAsync<'a, R, M: Model, O> {
211 fn call(&self, model: R, dev: &'a Dev<M>) -> BoxFuture<'a, Result<O>>;
213}
214
215impl<'a, R, M: Model, O, F, Fut> HandlerAsync<'a, R, M, O> for F
216where
217 F: Fn(R, &'a Dev<M>) -> Fut,
218 Fut: Future<Output = Result<O>> + Send + 'a,
219{
220 #[inline]
221 fn call(&self, model: R, dev: &'a Dev<M>) -> BoxFuture<'a, Result<O>> {
222 Box::pin(self(model, dev))
223 }
224}
225
226pub trait StatusSync<R, M: Model> {
232 fn call(&self, model: R, dev: &Dev<M>) -> Result<Scalar<str>>;
234}
235
236impl<R, M: Model, O, F> StatusSync<R, M> for F
237where
238 F: Fn(R, &Dev<M>) -> Result<O>,
239 O: Into<Scalar<str>>,
240{
241 #[inline]
242 fn call(&self, model: R, dev: &Dev<M>) -> Result<Scalar<str>> {
243 self(model, dev).map(Into::into)
244 }
245}
246
247pub trait StatusAsync<'a, R, M: Model> {
252 fn call(&self, model: R, dev: &'a Dev<M>) -> BoxFuture<'a, Result<Scalar<str>>>;
254}
255
256impl<'a, R, M: Model, O, F, Fut> StatusAsync<'a, R, M> for F
257where
258 F: Fn(R, &'a Dev<M>) -> Fut,
259 Fut: Future<Output = Result<O>> + Send + 'a,
260 O: Into<Scalar<str>>,
261{
262 #[inline]
263 fn call(&self, model: R, dev: &'a Dev<M>) -> BoxFuture<'a, Result<Scalar<str>>> {
264 let fut = self(model, dev);
265 Box::pin(async move { fut.await.map(Into::into) })
266 }
267}
268
269pub trait InitAsync<'a, M: Model> {
273 fn call(&self, dev: &'a Dev<M>) -> BoxFuture<'a, Result<M>>;
275}
276
277impl<'a, M: Model, F, Fut> InitAsync<'a, M> for F
278where
279 F: Fn(&'a Dev<M>) -> Fut,
280 Fut: Future<Output = Result<M>> + Send + 'a,
281{
282 #[inline]
283 fn call(&self, dev: &'a Dev<M>) -> BoxFuture<'a, Result<M>> {
284 Box::pin(self(dev))
285 }
286}
287
288pub trait DeleteAsync<'a, M: Model> {
293 fn call(&self, model: M, dev: &'a Dev<M>) -> BoxFuture<'a, ()>;
295}
296
297impl<'a, M: Model, F, Fut> DeleteAsync<'a, M> for F
298where
299 F: Fn(M, &'a Dev<M>) -> Fut,
300 Fut: Future<Output = ()> + Send + 'a,
301{
302 #[inline]
303 fn call(&self, model: M, dev: &'a Dev<M>) -> BoxFuture<'a, ()> {
304 Box::pin(self(model, dev))
305 }
306}
307
308impl<M: Model> ClassDef<M> {
309
310 pub fn new<N, I>(name: N, init: I) -> Self
313 where
314 N: Into<Cow<'static, str>>,
315 I: for<'ctx> Fn(&'ctx Dev<M>) -> Result<M> + Send + Sync + 'static,
316 {
317 Self::with_init(name.into(), InitFn::Sync(Box::new(init)))
318 }
319
320 pub fn new_async_with<N, I>(name: N, init: I) -> Self
324 where
325 N: Into<Cow<'static, str>>,
326 I: for<'a> Fn(&'a Dev<M>) -> BoxFuture<'a, Result<M>> + Send + Sync + 'static,
327 {
328 Self::with_init(name.into(), InitFn::Async(Box::new(init)))
329 }
330
331 pub fn new_async<N, I>(name: N, init: I) -> Self
339 where
340 N: Into<Cow<'static, str>>,
341 I: for<'a> InitAsync<'a, M> + Send + Sync + 'static,
342 {
343 Self::new_async_with(name, move |dev| init.call(dev))
344 }
345
346 fn with_init(name: Cow<'static, str>, init: InitFn<M>) -> Self {
347 Self {
348 name,
349 doc: Cow::Borrowed("A Tango device"),
350 doc_url: None,
351 init,
352 delete: None,
353 state: None,
354 status: None,
355 commands: Vec::new(),
356 attrs: Vec::new(),
357 state_attr: state_attr(AttrConfig {
358 doc: Some(Cow::Borrowed("The state of the device")),
359 label: Some(Cow::Borrowed(STATE_NAME)),
360 ..AttrConfig::default()
361 }),
362 status_attr: status_attr(AttrConfig {
363 doc: Some(Cow::Borrowed("The status of the device")),
364 label: Some(Cow::Borrowed(STATUS_NAME)),
365 ..AttrConfig::default()
366 }),
367 }
368 }
369
370 pub fn new_default<N>(name: N) -> Self
372 where
373 M: Default,
374 N: Into<Cow<'static, str>>,
375 {
376 Self::new(name, |_ctx| Ok(M::default()))
377 }
378
379 pub fn doc<D>(mut self, doc: D) -> Self
383 where
384 D: Into<Cow<'static, str>>,
385 {
386 self.doc = doc.into();
387 self
388 }
389
390 pub fn doc_url<U>(mut self, url: U) -> Self
394 where
395 U: Into<Cow<'static, str>>,
396 {
397 self.doc_url = Some(url.into());
398 self
399 }
400
401 pub fn delete<F>(mut self, delete: F) -> Self
407 where
408 F: for<'ctx> Fn(M, &'ctx Dev<M>) + Send + Sync + 'static,
409 {
410 self.delete = Some(DeleteFn::Sync(Box::new(delete)));
411 self
412 }
413
414 pub fn delete_async_with<F>(mut self, delete: F) -> Self
418 where
419 F: for<'a> Fn(M, &'a Dev<M>) -> BoxFuture<'a, ()> + Send + Sync + 'static,
420 {
421 self.delete = Some(DeleteFn::Async(Box::new(delete)));
422 self
423 }
424
425 pub fn delete_async<F>(self, delete: F) -> Self
433 where
434 F: for<'a> DeleteAsync<'a, M> + Send + Sync + 'static,
435 {
436 self.delete_async_with(move |model, dev| delete.call(model, dev))
437 }
438
439 pub fn state<F>(mut self, state: F) -> Self
442 where
443 F: for<'m, 'ctx> Fn(&'m M, &'ctx Dev<M>) -> Result<DevState> + Send + Sync + 'static,
444 {
445 self.state = Some(StateFn::SharedSync(Box::new(state)));
446 self
447 }
448
449 pub fn state_exclusive<F>(mut self, state: F) -> Self
452 where
453 F: for<'m, 'ctx> Fn(&'m mut M, &'ctx Dev<M>) -> Result<DevState> + Send + Sync + 'static,
454 {
455 self.state = Some(StateFn::ExclusiveSync(Box::new(state)));
456 self
457 }
458
459 pub fn state_async_with<F>(mut self, state: F) -> Self
463 where
464 F: for<'a> Fn(&'a M, &'a Dev<M>) -> BoxFuture<'a, Result<DevState>> + Send + Sync + 'static,
465 {
466 self.state = Some(StateFn::SharedAsync(Box::new(state)));
467 self
468 }
469
470 pub fn state_async<F>(self, state: F) -> Self
477 where
478 F: for<'a> HandlerAsync<'a, &'a M, M, DevState> + Send + Sync + 'static,
479 {
480 self.state_async_with(move |model, dev| state.call(model, dev))
481 }
482
483 pub fn state_exclusive_async_with<F>(mut self, state: F) -> Self
487 where
488 F: for<'a> Fn(&'a mut M, &'a Dev<M>) -> BoxFuture<'a, Result<DevState>> + Send + Sync + 'static,
489 {
490 self.state = Some(StateFn::ExclusiveAsync(Box::new(state)));
491 self
492 }
493
494 pub fn state_exclusive_async<F>(self, state: F) -> Self
498 where
499 F: for<'a> HandlerAsync<'a, &'a mut M, M, DevState> + Send + Sync + 'static,
500 {
501 self.state_exclusive_async_with(move |model, dev| state.call(model, dev))
502 }
503
504 pub fn status_with<F>(mut self, status: F) -> Self
508 where
509 F: for<'m, 'ctx> Fn(&'m M, &'ctx Dev<M>) -> Result<Scalar<str>> + Send + Sync + 'static,
510 {
511 self.status = Some(StatusFn::SharedSync(Box::new(status)));
512 self
513 }
514
515 pub fn status<F>(self, status: F) -> Self
522 where
523 F: for<'m> StatusSync<&'m M, M> + Send + Sync + 'static,
524 {
525 self.status_with(move |model, dev| status.call(model, dev))
526 }
527
528 pub fn status_exclusive_with<F>(mut self, status: F) -> Self
532 where
533 F: for<'m, 'ctx> Fn(&'m mut M, &'ctx Dev<M>) -> Result<Scalar<str>> + Send + Sync + 'static,
534 {
535 self.status = Some(StatusFn::ExclusiveSync(Box::new(status)));
536 self
537 }
538
539 pub fn status_exclusive<F>(self, status: F) -> Self
542 where
543 F: for<'m> StatusSync<&'m mut M, M> + Send + Sync + 'static,
544 {
545 self.status_exclusive_with(move |model, dev| status.call(model, dev))
546 }
547
548 pub fn status_async_with<F>(mut self, status: F) -> Self
552 where
553 F: for<'a> Fn(&'a M, &'a Dev<M>) -> BoxFuture<'a, Result<Scalar<str>>> + Send + Sync + 'static,
554 {
555 self.status = Some(StatusFn::SharedAsync(Box::new(status)));
556 self
557 }
558
559 pub fn status_async<F>(self, status: F) -> Self
562 where
563 F: for<'a> StatusAsync<'a, &'a M, M> + Send + Sync + 'static,
564 {
565 self.status_async_with(move |model, dev| status.call(model, dev))
566 }
567
568 pub fn status_exclusive_async_with<F>(mut self, status: F) -> Self
572 where
573 F: for<'a> Fn(&'a mut M, &'a Dev<M>) -> BoxFuture<'a, Result<Scalar<str>>> + Send + Sync + 'static,
574 {
575 self.status = Some(StatusFn::ExclusiveAsync(Box::new(status)));
576 self
577 }
578
579 pub fn status_exclusive_async<F>(self, status: F) -> Self
582 where
583 F: for<'a> StatusAsync<'a, &'a mut M, M> + Send + Sync + 'static,
584 {
585 self.status_exclusive_async_with(move |model, dev| status.call(model, dev))
586 }
587
588 #[track_caller]
598 pub fn command(mut self, def: CommandDef<M>) -> Self {
599 check_own_name(&self.name, "command", &def.name, name::check_tango_command_name, RESERVED_COMMANDS);
600 if self.commands.iter().any(|other| other.name.eq_ignore_ascii_case(&def.name)) {
601 panic!("{}: the command {} is already defined", self.name, def.name);
602 }
603 self.commands.push(Arc::new(def));
604 self
605 }
606
607 #[track_caller]
618 pub fn attr(mut self, def: AttrDef<M>) -> Self {
619 check_own_name(&self.name, "attribute", &def.name, name::check_tango_attr_name, RESERVED_ATTRS);
620 if let Err(err) = def.check() {
621 panic!("{}: {err}", self.name);
622 }
623 if self.attrs.iter().any(|other| other.name.eq_ignore_ascii_case(&def.name)) {
624 panic!("{}: the attribute {} is already defined", self.name, def.name);
625 }
626 self.attrs.push(Arc::new(def));
627 self
628 }
629
630 #[track_caller]
639 pub fn state_config(mut self, config: AttrConfig) -> Self {
640 self.state_attr = state_attr(config);
641 self
642 }
643
644 #[track_caller]
652 pub fn status_config(mut self, config: AttrConfig) -> Self {
653 self.status_attr = status_attr(config);
654 self
655 }
656
657 pub fn push_state_events(mut self, change: Option<bool>, archive: Option<bool>) -> Self {
662 builtin_pushed(&mut self.state_attr, change, archive);
663 self
664 }
665
666 pub fn push_status_events(mut self, change: Option<bool>, archive: Option<bool>) -> Self {
669 builtin_pushed(&mut self.status_attr, change, archive);
670 self
671 }
672
673}
674
675#[track_caller]
677fn state_attr<M: Model>(config: AttrConfig) -> Arc<AttrDef<M>> {
678 builtin_attr(STATE_NAME, AttrDataKind::State, config)
679}
680
681#[track_caller]
683fn status_attr<M: Model>(config: AttrConfig) -> Arc<AttrDef<M>> {
684 builtin_attr(STATUS_NAME, AttrDataKind::String, config)
685}
686
687fn builtin_pushed<M: Model>(def: &mut Arc<AttrDef<M>>, change: Option<bool>, archive: Option<bool>) {
690 let def = Arc::get_mut(def).expect("a class being built is the only owner of its definitions");
691 def.pushed.change = change;
692 def.pushed.archive = archive;
693}
694
695#[track_caller]
698fn builtin_attr<M: Model>(name: &'static str, kind: AttrDataKind, config: AttrConfig) -> Arc<AttrDef<M>> {
699 let mut def = AttrDef::new(name).kind(kind).scalar();
700 def.display_level = DisplayLevel::Operator;
701 def.config = config;
702 if let Err(err) = def.check() {
703 panic!("{err}");
704 }
705 Arc::new(def)
706}
707
708#[track_caller]
714fn check_own_name(class: &str, what: &str, name: &str, valid: fn(&str) -> bool, reserved: &[&str]) {
715 if !valid(name) {
716 panic!("{class}: the {what} name {name:?} is invalid");
717 }
718 if let Some(reserved) = reserved_name(name, reserved) {
719 panic!("{class}: the {what} {name} cannot be defined by a class, \
720 {reserved} is answered by the server itself");
721 }
722}
723
724impl<M: Model> Debug for ClassDef<M> {
725 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
726 f.debug_struct("ClassDef")
727 .field("name", &self.name)
728 .field("doc", &self.doc)
729 .field("doc_url", &self.doc_url)
730 .field("init", &HandlerDebug)
731 .field("delete", &self.delete.as_ref().map(|_| HandlerDebug))
732 .field("state", &self.state)
733 .field("status", &self.status)
734 .field("commands", &self.commands)
735 .field("attrs", &self.attrs)
736 .field("state_attr", &self.state_attr)
737 .field("status_attr", &self.status_attr)
738 .finish()
739 }
740}
741
742pub struct CommandDef<M: Model> {
744 pub(super) name: Cow<'static, str>,
746 pub(super) exec: Option<ExecFn<M>>,
748 pub(super) in_kind: Option<CommandDataKind>,
751 pub(super) in_doc: Cow<'static, str>,
753 pub(super) out_kind: Option<CommandDataKind>,
756 pub(super) out_doc: Cow<'static, str>,
758 pub(super) display_level: DisplayLevel,
761 pub(super) poll_period: Option<Duration>,
764}
765
766pub enum ExecFn<M: Model> {
769 SharedSync(Box<dyn Fn(&M, &Dev<M>, Value) -> Result<Value> + Send + Sync>),
770 ExclusiveSync(Box<dyn Fn(&mut M, &Dev<M>, Value) -> Result<Value> + Send + Sync>),
771 SharedAsync(Box<dyn for<'a> Fn(&'a M, &'a Dev<M>, Value) -> BoxFuture<'a, Result<Value>> + Send + Sync>),
772 ExclusiveAsync(Box<dyn for<'a> Fn(&'a mut M, &'a Dev<M>, Value) -> BoxFuture<'a, Result<Value>> + Send + Sync>),
773}
774
775pub trait ExecShared<'m, M: Model, I> {
778 const IN_KIND: CommandDataKind;
780 const OUT_KIND: CommandDataKind;
782 fn exec(&self, model: &'m M, dev: &Dev<M>, input: Value) -> Result<Value>;
784}
785
786impl<'m, M: Model, I, O, F> ExecShared<'m, M, I> for F
787where
788 I: FromValue + CommandData,
789 O: IntoValue + CommandData,
790 F: Fn(&'m M, &Dev<M>, I) -> Result<O>,
791{
792
793 const IN_KIND: CommandDataKind = I::DATA_KIND;
794 const OUT_KIND: CommandDataKind = O::DATA_KIND;
795
796 #[inline]
797 fn exec(&self, model: &'m M, dev: &Dev<M>, input: Value) -> Result<Value> {
798 Ok(self(model, dev, I::from_value(input)?)?.into_value())
799 }
800
801}
802
803pub trait ExecExclusive<'m, M: Model, I> {
805 const IN_KIND: CommandDataKind;
807 const OUT_KIND: CommandDataKind;
809 fn exec(&self, model: &'m mut M, dev: &Dev<M>, input: Value) -> Result<Value>;
811}
812
813impl<'m, M: Model, I, O, F> ExecExclusive<'m, M, I> for F
814where
815 I: FromValue + CommandData,
816 O: IntoValue + CommandData,
817 F: Fn(&'m mut M, &Dev<M>, I) -> Result<O>,
818{
819
820 const IN_KIND: CommandDataKind = I::DATA_KIND;
821 const OUT_KIND: CommandDataKind = O::DATA_KIND;
822
823 #[inline]
824 fn exec(&self, model: &'m mut M, dev: &Dev<M>, input: Value) -> Result<Value> {
825 Ok(self(model, dev, I::from_value(input)?)?.into_value())
826 }
827
828}
829
830pub trait ExecAsync<'a, R, M: Model, I> {
836 const IN_KIND: CommandDataKind;
838 const OUT_KIND: CommandDataKind;
840 fn exec(&self, model: R, dev: &'a Dev<M>, input: Value) -> BoxFuture<'a, Result<Value>>;
843}
844
845impl<'a, R, M: Model, I, O, F, Fut> ExecAsync<'a, R, M, I> for F
846where
847 I: FromValue + CommandData,
848 O: IntoValue + CommandData,
849 F: Fn(R, &'a Dev<M>, I) -> Fut,
850 Fut: Future<Output = Result<O>> + Send + 'a,
851{
852
853 const IN_KIND: CommandDataKind = I::DATA_KIND;
854 const OUT_KIND: CommandDataKind = O::DATA_KIND;
855
856 #[inline]
857 fn exec(&self, model: R, dev: &'a Dev<M>, input: Value) -> BoxFuture<'a, Result<Value>> {
858 let fut = I::from_value(input).map(|input| self(model, dev, input));
861 Box::pin(async move { Ok(fut?.await?.into_value()) })
862 }
863
864}
865
866impl<M: Model> CommandDef<M> {
867
868 pub fn new<N>(name: N) -> Self
870 where
871 N: Into<Cow<'static, str>>,
872 {
873 Self {
874 name: name.into(),
875 exec: None,
876 in_kind: None,
877 in_doc: Cow::Borrowed(""),
878 out_kind: None,
879 out_doc: Cow::Borrowed(""),
880 display_level: DisplayLevel::default(),
881 poll_period: None,
882 }
883 }
884
885 pub fn in_doc<D>(mut self, doc: D) -> Self
890 where
891 D: Into<Cow<'static, str>>,
892 {
893 self.in_doc = doc.into();
894 self
895 }
896
897 pub fn out_doc<D>(mut self, doc: D) -> Self
899 where
900 D: Into<Cow<'static, str>>,
901 {
902 self.out_doc = doc.into();
903 self
904 }
905
906 pub fn display_level(mut self, level: DisplayLevel) -> Self {
909 self.display_level = level;
910 self
911 }
912
913 pub fn polled(mut self, period: Duration) -> Self {
925 self.poll_period = Some(period);
926 self
927 }
928
929 #[track_caller]
938 pub fn in_kind(mut self, kind: CommandDataKind) -> Self {
939 self.in_kind = Some(merge_kind(&self.name, "argument kind", self.in_kind.take(), kind));
940 self
941 }
942
943 #[track_caller]
952 pub fn out_kind(mut self, kind: CommandDataKind) -> Self {
953 self.out_kind = Some(merge_kind(&self.name, "result kind", self.out_kind.take(), kind));
954 self
955 }
956
957 pub fn exec_with<F>(mut self, func: F) -> Self
965 where
966 F: Fn(&M, &Dev<M>, Value) -> Result<Value> + Send + Sync + 'static,
967 {
968 self.exec = Some(ExecFn::SharedSync(Box::new(func)));
969 self
970 }
971
972 #[track_caller]
985 pub fn exec<F, I>(self, func: F) -> Self
986 where
987 F: for<'m> ExecShared<'m, M, I> + Send + Sync + 'static,
988 {
989 self.in_kind(F::IN_KIND)
990 .out_kind(F::OUT_KIND)
991 .exec_with(move |model, dev, value| func.exec(model, dev, value))
992 }
993
994 pub fn exec_exclusive_with<F>(mut self, func: F) -> Self
997 where
998 F: Fn(&mut M, &Dev<M>, Value) -> Result<Value> + Send + Sync + 'static,
999 {
1000 self.exec = Some(ExecFn::ExclusiveSync(Box::new(func)));
1001 self
1002 }
1003
1004 #[track_caller]
1015 pub fn exec_exclusive<F, I>(self, func: F) -> Self
1016 where
1017 F: for<'m> ExecExclusive<'m, M, I> + Send + Sync + 'static,
1018 {
1019 self.in_kind(F::IN_KIND)
1020 .out_kind(F::OUT_KIND)
1021 .exec_exclusive_with(move |model, dev, value| func.exec(model, dev, value))
1022 }
1023
1024 pub fn exec_async_with<F>(mut self, func: F) -> Self
1028 where
1029 F: for<'a> Fn(&'a M, &'a Dev<M>, Value) -> BoxFuture<'a, Result<Value>> + Send + Sync + 'static,
1030 {
1031 self.exec = Some(ExecFn::SharedAsync(Box::new(func)));
1032 self
1033 }
1034
1035 #[track_caller]
1048 pub fn exec_async<F, I>(self, func: F) -> Self
1049 where
1050 F: for<'a> ExecAsync<'a, &'a M, M, I> + Send + Sync + 'static,
1051 {
1052 self.in_kind(F::IN_KIND)
1053 .out_kind(F::OUT_KIND)
1054 .exec_async_with(move |model, dev, value| func.exec(model, dev, value))
1055 }
1056
1057 pub fn exec_exclusive_async_with<F>(mut self, func: F) -> Self
1061 where
1062 F: for<'a> Fn(&'a mut M, &'a Dev<M>, Value) -> BoxFuture<'a, Result<Value>> + Send + Sync + 'static,
1063 {
1064 self.exec = Some(ExecFn::ExclusiveAsync(Box::new(func)));
1065 self
1066 }
1067
1068 #[track_caller]
1077 pub fn exec_exclusive_async<F, I>(self, func: F) -> Self
1078 where
1079 F: for<'a> ExecAsync<'a, &'a mut M, M, I> + Send + Sync + 'static,
1080 {
1081 self.in_kind(F::IN_KIND)
1082 .out_kind(F::OUT_KIND)
1083 .exec_exclusive_async_with(move |model, dev, value| func.exec(model, dev, value))
1084 }
1085
1086}
1087
1088impl<M: Model> Debug for CommandDef<M> {
1089 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1090 f.debug_struct("CommandDef")
1091 .field("name", &self.name)
1092 .field("exec", &self.exec)
1093 .field("in_kind", &self.in_kind)
1094 .field("in_doc", &self.in_doc)
1095 .field("out_kind", &self.out_kind)
1096 .field("out_doc", &self.out_doc)
1097 .field("display_level", &self.display_level)
1098 .field("poll_period", &self.poll_period)
1099 .finish()
1100 }
1101}
1102
1103pub struct AttrDef<M: Model> {
1105 pub(super) name: Cow<'static, str>,
1107 pub(super) read: Option<ReadFn<M>>,
1109 pub(super) write: Option<WriteFn<M>>,
1111 pub(super) kind: Option<AttrDataKind>,
1113 pub(super) format: Option<AttrDataFormat>,
1115 pub(super) display_level: DisplayLevel,
1118 pub(super) memorized: Option<AttrMemorized>,
1121 pub(super) config: AttrConfig,
1126 pub(super) poll_period: Option<Duration>,
1129 pub(super) pushed: PushedEvents,
1132}
1133
1134#[derive(Debug, Clone, Copy, Default)]
1139pub(super) struct PushedEvents {
1140 pub change: Option<bool>,
1141 pub archive: Option<bool>,
1142 pub data_ready: bool,
1143}
1144
1145pub enum ReadFn<M: Model> {
1148 SharedSync(Box<dyn Fn(&M, &Dev<M>) -> Result<AttrRead<Value>> + Send + Sync>),
1149 ExclusiveSync(Box<dyn Fn(&mut M, &Dev<M>) -> Result<AttrRead<Value>> + Send + Sync>),
1150 SharedAsync(Box<dyn for<'a> Fn(&'a M, &'a Dev<M>) -> BoxFuture<'a, Result<AttrRead<Value>>> + Send + Sync>),
1151 ExclusiveAsync(Box<dyn for<'a> Fn(&'a mut M, &'a Dev<M>) -> BoxFuture<'a, Result<AttrRead<Value>>> + Send + Sync>),
1152}
1153
1154pub enum WriteFn<M: Model> {
1157 SharedSync(Box<dyn Fn(&M, &Dev<M>, Value) -> Result<()> + Send + Sync>),
1158 ExclusiveSync(Box<dyn Fn(&mut M, &Dev<M>, Value) -> Result<()> + Send + Sync>),
1159 SharedAsync(Box<dyn for<'a> Fn(&'a M, &'a Dev<M>, Value) -> BoxFuture<'a, Result<()>> + Send + Sync>),
1160 ExclusiveAsync(Box<dyn for<'a> Fn(&'a mut M, &'a Dev<M>, Value) -> BoxFuture<'a, Result<()>> + Send + Sync>),
1161}
1162
1163pub trait ReadOutput {
1166 const DATA_KIND: AttrDataKind;
1168 const DATA_FORMAT: AttrDataFormat;
1170 fn into_read(self) -> AttrRead<Value>;
1173}
1174
1175impl<O> ReadOutput for O
1176where
1177 O: IntoValue + AttrData,
1178{
1179
1180 const DATA_KIND: AttrDataKind = O::DATA_KIND;
1181 const DATA_FORMAT: AttrDataFormat = O::DATA_FORMAT;
1182
1183 fn into_read(self) -> AttrRead<Value> {
1184 AttrRead {
1185 value: Some(self.into_value()),
1186 w_value: None,
1189 quality: AttrQuality::Valid,
1190 time: SystemTime::now(),
1191 }
1192 }
1193
1194}
1195
1196impl<O> ReadOutput for AttrRead<O>
1197where
1198 O: IntoValue + AttrData,
1199{
1200
1201 const DATA_KIND: AttrDataKind = O::DATA_KIND;
1202 const DATA_FORMAT: AttrDataFormat = O::DATA_FORMAT;
1203
1204 fn into_read(self) -> AttrRead<Value> {
1205 AttrRead {
1206 value: self.value.map(IntoValue::into_value),
1207 w_value: self.w_value.map(IntoValue::into_value),
1210 quality: self.quality,
1211 time: self.time,
1212 }
1213 }
1214
1215}
1216
1217pub trait ReadShared<'m, M: Model> {
1221 const DATA_KIND: AttrDataKind;
1223 const DATA_FORMAT: AttrDataFormat;
1225 fn read(&self, model: &'m M, dev: &Dev<M>) -> Result<AttrRead<Value>>;
1227}
1228
1229impl<'m, M: Model, O, F> ReadShared<'m, M> for F
1230where
1231 F: Fn(&'m M, &Dev<M>) -> Result<O>,
1232 O: ReadOutput,
1233{
1234 const DATA_KIND: AttrDataKind = O::DATA_KIND;
1235 const DATA_FORMAT: AttrDataFormat = O::DATA_FORMAT;
1236
1237 #[inline]
1238 fn read(&self, model: &'m M, dev: &Dev<M>) -> Result<AttrRead<Value>> {
1239 Ok(self(model, dev)?.into_read())
1240 }
1241}
1242
1243pub trait ReadExclusive<'m, M: Model> {
1245 const DATA_KIND: AttrDataKind;
1247 const DATA_FORMAT: AttrDataFormat;
1249 fn read(&self, model: &'m mut M, dev: &Dev<M>) -> Result<AttrRead<Value>>;
1251}
1252
1253impl<'m, M: Model, O, F> ReadExclusive<'m, M> for F
1254where
1255 F: Fn(&'m mut M, &Dev<M>) -> Result<O>,
1256 O: ReadOutput,
1257{
1258 const DATA_KIND: AttrDataKind = O::DATA_KIND;
1259 const DATA_FORMAT: AttrDataFormat = O::DATA_FORMAT;
1260
1261 #[inline]
1262 fn read(&self, model: &'m mut M, dev: &Dev<M>) -> Result<AttrRead<Value>> {
1263 Ok(self(model, dev)?.into_read())
1264 }
1265}
1266
1267pub trait WriteShared<M: Model, I> {
1269 const DATA_KIND: AttrDataKind;
1271 const DATA_FORMAT: AttrDataFormat;
1273 fn write(&self, model: &M, dev: &Dev<M>, value: Value) -> Result<()>;
1275}
1276
1277impl<M: Model, I, F> WriteShared<M, I> for F
1278where
1279 F: Fn(&M, &Dev<M>, I) -> Result<()>,
1280 I: FromValue + AttrData,
1281{
1282 const DATA_KIND: AttrDataKind = I::DATA_KIND;
1283 const DATA_FORMAT: AttrDataFormat = I::DATA_FORMAT;
1284
1285 #[inline]
1286 fn write(&self, model: &M, dev: &Dev<M>, value: Value) -> Result<()> {
1287 self(model, dev, I::from_value(value)?)
1288 }
1289}
1290
1291pub trait WriteExclusive<M: Model, I> {
1293 const DATA_KIND: AttrDataKind;
1295 const DATA_FORMAT: AttrDataFormat;
1297 fn write(&self, model: &mut M, dev: &Dev<M>, value: Value) -> Result<()>;
1299}
1300
1301impl<M: Model, I, F> WriteExclusive<M, I> for F
1302where
1303 F: Fn(&mut M, &Dev<M>, I) -> Result<()>,
1304 I: FromValue + AttrData,
1305{
1306 const DATA_KIND: AttrDataKind = I::DATA_KIND;
1307 const DATA_FORMAT: AttrDataFormat = I::DATA_FORMAT;
1308
1309 #[inline]
1310 fn write(&self, model: &mut M, dev: &Dev<M>, value: Value) -> Result<()> {
1311 self(model, dev, I::from_value(value)?)
1312 }
1313}
1314
1315pub trait ReadAsync<'a, R, M: Model> {
1320 const DATA_KIND: AttrDataKind;
1322 const DATA_FORMAT: AttrDataFormat;
1324 fn read(&self, model: R, dev: &'a Dev<M>) -> BoxFuture<'a, Result<AttrRead<Value>>>;
1326}
1327
1328impl<'a, R, M: Model, O, F, Fut> ReadAsync<'a, R, M> for F
1329where
1330 F: Fn(R, &'a Dev<M>) -> Fut,
1331 Fut: Future<Output = Result<O>> + Send + 'a,
1332 O: ReadOutput,
1333{
1334 const DATA_KIND: AttrDataKind = O::DATA_KIND;
1335 const DATA_FORMAT: AttrDataFormat = O::DATA_FORMAT;
1336
1337 #[inline]
1338 fn read(&self, model: R, dev: &'a Dev<M>) -> BoxFuture<'a, Result<AttrRead<Value>>> {
1339 let fut = self(model, dev);
1340 Box::pin(async move { Ok(fut.await?.into_read()) })
1341 }
1342}
1343
1344pub trait WriteAsync<'a, R, M: Model, I> {
1348 const DATA_KIND: AttrDataKind;
1350 const DATA_FORMAT: AttrDataFormat;
1352 fn write(&self, model: R, dev: &'a Dev<M>, value: Value) -> BoxFuture<'a, Result<()>>;
1354}
1355
1356impl<'a, R, M: Model, I, F, Fut> WriteAsync<'a, R, M, I> for F
1357where
1358 F: Fn(R, &'a Dev<M>, I) -> Fut,
1359 Fut: Future<Output = Result<()>> + Send + 'a,
1360 I: FromValue + AttrData,
1361{
1362 const DATA_KIND: AttrDataKind = I::DATA_KIND;
1363 const DATA_FORMAT: AttrDataFormat = I::DATA_FORMAT;
1364
1365 #[inline]
1366 fn write(&self, model: R, dev: &'a Dev<M>, value: Value) -> BoxFuture<'a, Result<()>> {
1367 let fut = I::from_value(value).map(|input| self(model, dev, input));
1368 Box::pin(async move { fut?.await })
1369 }
1370}
1371
1372impl<M: Model> AttrDef<M> {
1373
1374 pub fn new<N>(name: N) -> Self
1376 where
1377 N: Into<Cow<'static, str>>,
1378 {
1379 Self {
1380 name: name.into(),
1381 read: None,
1382 write: None,
1383 kind: None,
1384 format: None,
1385 display_level: DisplayLevel::default(),
1386 memorized: None,
1387 config: AttrConfig::default(),
1388 poll_period: None,
1389 pushed: PushedEvents::default(),
1390 }
1391 }
1392
1393 pub fn doc<D>(mut self, doc: D) -> Self
1399 where
1400 D: Into<Cow<'static, str>>,
1401 {
1402 self.config.doc = Some(doc.into());
1403 self
1404 }
1405
1406 pub fn label<L>(mut self, label: L) -> Self
1409 where
1410 L: Into<Cow<'static, str>>,
1411 {
1412 self.config.label = Some(label.into());
1413 self
1414 }
1415
1416 pub fn unit<U>(mut self, unit: U) -> Self
1418 where
1419 U: Into<Cow<'static, str>>,
1420 {
1421 self.config.unit = Some(unit.into());
1422 self
1423 }
1424
1425 pub fn standard_unit(mut self, factor: f64) -> Self {
1429 self.config.standard_unit = Some(factor);
1430 self
1431 }
1432
1433 pub fn display_unit<U>(mut self, unit: U) -> Self
1436 where
1437 U: Into<Cow<'static, str>>,
1438 {
1439 self.config.display_unit = Some(unit.into());
1440 self
1441 }
1442
1443 pub fn display_format<F>(mut self, format: F) -> Self
1446 where
1447 F: Into<Cow<'static, str>>,
1448 {
1449 self.config.display_format = Some(format.into());
1450 self
1451 }
1452
1453 pub fn display_level(mut self, level: DisplayLevel) -> Self {
1456 self.display_level = level;
1457 self
1458 }
1459
1460 #[track_caller]
1477 pub fn range<T, R>(mut self, range: R) -> Self
1478 where
1479 T: Into<AttrNumber> + Copy,
1480 R: RangeBounds<T>,
1481 {
1482 self.config.range = range_config(&self.name, "value range", range);
1483 self
1484 }
1485
1486 #[track_caller]
1493 pub fn alarm<T, R>(mut self, range: R) -> Self
1494 where
1495 T: Into<AttrNumber> + Copy,
1496 R: RangeBounds<T>,
1497 {
1498 self.config.alarm = range_config(&self.name, "alarm range", range);
1499 self
1500 }
1501
1502 #[track_caller]
1510 pub fn warning<T, R>(mut self, range: R) -> Self
1511 where
1512 T: Into<AttrNumber> + Copy,
1513 R: RangeBounds<T>,
1514 {
1515 self.config.warning = range_config(&self.name, "warning range", range);
1516 self
1517 }
1518
1519 pub fn delta<V, T>(mut self, value: V, time: T) -> Self
1525 where
1526 V: Into<AttrNumber>,
1527 T: Into<Option<Duration>>,
1528 {
1529 self.config.delta = Some(AttrDeltaConfig {
1530 value: value.into(),
1531 time: time.into(),
1532 });
1533 self
1534 }
1535
1536 pub fn change_event<A, R>(mut self, abs: A, rel: R) -> Self
1547 where
1548 A: Into<Option<f64>>,
1549 R: Into<Option<f64>>,
1550 {
1551 self.config.change_event.abs_change = abs.into();
1552 self.config.change_event.rel_change = rel.into();
1553 self
1554 }
1555
1556 pub fn periodic_event(mut self, period: Duration) -> Self {
1559 self.config.periodic_event.period = Some(period);
1560 self
1561 }
1562
1563 pub fn archive_event<A, R, P>(mut self, abs: A, rel: R, period: P) -> Self
1567 where
1568 A: Into<Option<f64>>,
1569 R: Into<Option<f64>>,
1570 P: Into<Option<Duration>>,
1571 {
1572 self.config.archive_event.abs_change = abs.into();
1573 self.config.archive_event.rel_change = rel.into();
1574 self.config.archive_event.period = period.into();
1575 self
1576 }
1577
1578 pub fn push_change_event(mut self, detect: bool) -> Self {
1588 self.pushed.change = Some(detect);
1589 self
1590 }
1591
1592 pub fn push_archive_event(mut self, detect: bool) -> Self {
1595 self.pushed.archive = Some(detect);
1596 self
1597 }
1598
1599 pub fn push_data_ready_event(mut self) -> Self {
1603 self.pushed.data_ready = true;
1604 self
1605 }
1606
1607 pub fn memorized(mut self, mode: AttrMemorized) -> Self {
1617 self.memorized = Some(mode);
1618 self
1619 }
1620
1621 pub(super) fn check(&self) -> std::result::Result<(), String> {
1625
1626 if let Some(prop) = unsupported_prop(&self.config, self.kind) {
1627 return Err(format!("the attribute {} cannot have the property {:?}, {}",
1628 self.name, prop.name(), unsupported(self.kind)));
1629 }
1630
1631 if self.memorized.is_none() {
1632 return Ok(());
1633 }
1634
1635 let reason = if self.write.is_none() {
1636 "it is not writable"
1637 } else if !matches!(self.format, None | Some(AttrDataFormat::Scalar)) {
1638 "it is not a scalar"
1639 } else if matches!(self.kind, Some(AttrDataKind::State | AttrDataKind::Encoded)) {
1640 "a value of its kind cannot be memorized"
1641 } else {
1642 return Ok(());
1643 };
1644
1645 Err(format!("the attribute {} cannot be memorized, {reason}", self.name))
1646
1647 }
1648
1649 pub fn polled(mut self, period: Duration) -> Self {
1660 self.poll_period = Some(period);
1661 self
1662 }
1663
1664 #[track_caller]
1673 pub fn kind(mut self, kind: AttrDataKind) -> Self {
1674 self.kind = Some(merge_kind(&self.name, "data kind", self.kind.take(), kind));
1675 self
1676 }
1677
1678 #[track_caller]
1692 pub fn format(mut self, format: AttrDataFormat) -> Self {
1693 self.format = Some(merge_format(&self.name, self.format.take(), format));
1694 self
1695 }
1696
1697 #[track_caller]
1704 pub fn scalar(self) -> Self {
1705 self.format(AttrDataFormat::Scalar)
1706 }
1707
1708 #[track_caller]
1719 pub fn spectrum(self, max_size: usize) -> Self {
1720 self.format(AttrDataFormat::Spectrum(max_size))
1721 }
1722
1723 #[track_caller]
1731 pub fn image(self, max_width: usize, max_height: usize) -> Self {
1732 self.format(AttrDataFormat::Image(max_width, max_height))
1733 }
1734
1735 pub fn read_with<F>(mut self, func: F) -> Self
1742 where
1743 F: Fn(&M, &Dev<M>) -> Result<AttrRead<Value>> + Send + Sync + 'static,
1744 {
1745 self.read = Some(ReadFn::SharedSync(Box::new(func)));
1746 self
1747 }
1748
1749 #[track_caller]
1762 pub fn read<F>(self, func: F) -> Self
1763 where
1764 F: for<'m> ReadShared<'m, M> + Send + Sync + 'static,
1765 {
1766 self.kind(F::DATA_KIND)
1767 .format(F::DATA_FORMAT)
1768 .read_with(move |model, dev| func.read(model, dev))
1769 }
1770
1771 pub fn read_exclusive_with<F>(mut self, func: F) -> Self
1774 where
1775 F: Fn(&mut M, &Dev<M>) -> Result<AttrRead<Value>> + Send + Sync + 'static,
1776 {
1777 self.read = Some(ReadFn::ExclusiveSync(Box::new(func)));
1778 self
1779 }
1780
1781 #[track_caller]
1789 pub fn read_exclusive<F>(self, func: F) -> Self
1790 where
1791 F: for<'m> ReadExclusive<'m, M> + Send + Sync + 'static,
1792 {
1793 self.kind(F::DATA_KIND)
1794 .format(F::DATA_FORMAT)
1795 .read_exclusive_with(move |model, dev| func.read(model, dev))
1796 }
1797
1798 pub fn read_async_with<F>(mut self, func: F) -> Self
1802 where
1803 F: for<'a> Fn(&'a M, &'a Dev<M>) -> BoxFuture<'a, Result<AttrRead<Value>>> + Send + Sync + 'static,
1804 {
1805 self.read = Some(ReadFn::SharedAsync(Box::new(func)));
1806 self
1807 }
1808
1809 #[track_caller]
1818 pub fn read_async<F>(self, func: F) -> Self
1819 where
1820 F: for<'a> ReadAsync<'a, &'a M, M> + Send + Sync + 'static,
1821 {
1822 self.kind(F::DATA_KIND)
1823 .format(F::DATA_FORMAT)
1824 .read_async_with(move |model, dev| func.read(model, dev))
1825 }
1826
1827 pub fn read_exclusive_async_with<F>(mut self, func: F) -> Self
1831 where
1832 F: for<'a> Fn(&'a mut M, &'a Dev<M>) -> BoxFuture<'a, Result<AttrRead<Value>>> + Send + Sync + 'static,
1833 {
1834 self.read = Some(ReadFn::ExclusiveAsync(Box::new(func)));
1835 self
1836 }
1837
1838 #[track_caller]
1847 pub fn read_exclusive_async<F>(self, func: F) -> Self
1848 where
1849 F: for<'a> ReadAsync<'a, &'a mut M, M> + Send + Sync + 'static,
1850 {
1851 self.kind(F::DATA_KIND)
1852 .format(F::DATA_FORMAT)
1853 .read_exclusive_async_with(move |model, dev| func.read(model, dev))
1854 }
1855
1856 pub fn write_with<F>(mut self, func: F) -> Self
1861 where
1862 F: Fn(&M, &Dev<M>, Value) -> Result<()> + Send + Sync + 'static,
1863 {
1864 self.write = Some(WriteFn::SharedSync(Box::new(func)));
1865 self
1866 }
1867
1868 #[track_caller]
1880 pub fn write<F, I>(self, func: F) -> Self
1881 where
1882 F: WriteShared<M, I> + Send + Sync + 'static,
1883 {
1884 self.kind(F::DATA_KIND)
1885 .format(F::DATA_FORMAT)
1886 .write_with(move |model, dev, value| func.write(model, dev, value))
1887 }
1888
1889 pub fn write_exclusive_with<F>(mut self, func: F) -> Self
1892 where
1893 F: Fn(&mut M, &Dev<M>, Value) -> Result<()> + Send + Sync + 'static,
1894 {
1895 self.write = Some(WriteFn::ExclusiveSync(Box::new(func)));
1896 self
1897 }
1898
1899 #[track_caller]
1908 pub fn write_exclusive<F, I>(self, func: F) -> Self
1909 where
1910 F: WriteExclusive<M, I> + Send + Sync + 'static,
1911 {
1912 self.kind(F::DATA_KIND)
1913 .format(F::DATA_FORMAT)
1914 .write_exclusive_with(move |model, dev, value| func.write(model, dev, value))
1915 }
1916
1917 pub fn write_async_with<F>(mut self, func: F) -> Self
1921 where
1922 F: for<'a> Fn(&'a M, &'a Dev<M>, Value) -> BoxFuture<'a, Result<()>> + Send + Sync + 'static,
1923 {
1924 self.write = Some(WriteFn::SharedAsync(Box::new(func)));
1925 self
1926 }
1927
1928 #[track_caller]
1936 pub fn write_async<F, I>(self, func: F) -> Self
1937 where
1938 F: for<'a> WriteAsync<'a, &'a M, M, I> + Send + Sync + 'static,
1939 {
1940 self.kind(F::DATA_KIND)
1941 .format(F::DATA_FORMAT)
1942 .write_async_with(move |model, dev, value| func.write(model, dev, value))
1943 }
1944
1945 pub fn write_exclusive_async_with<F>(mut self, func: F) -> Self
1949 where
1950 F: for<'a> Fn(&'a mut M, &'a Dev<M>, Value) -> BoxFuture<'a, Result<()>> + Send + Sync + 'static,
1951 {
1952 self.write = Some(WriteFn::ExclusiveAsync(Box::new(func)));
1953 self
1954 }
1955
1956 #[track_caller]
1965 pub fn write_exclusive_async<F, I>(self, func: F) -> Self
1966 where
1967 F: for<'a> WriteAsync<'a, &'a mut M, M, I> + Send + Sync + 'static,
1968 {
1969 self.kind(F::DATA_KIND)
1970 .format(F::DATA_FORMAT)
1971 .write_exclusive_async_with(move |model, dev, value| func.write(model, dev, value))
1972 }
1973
1974}
1975
1976impl<M: Model> Debug for AttrDef<M> {
1977 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1978 f.debug_struct("AttrDef")
1979 .field("name", &self.name)
1980 .field("read", &self.read)
1981 .field("write", &self.write)
1982 .field("kind", &self.kind)
1983 .field("format", &self.format)
1984 .field("config", &self.config)
1985 .field("poll_period", &self.poll_period)
1986 .field("pushed", &self.pushed)
1987 .finish()
1988 }
1989}
1990
1991
1992#[cfg(test)]
1993mod tests {
1994
1995 use super::*;
1996 use crate::value::Spectrum;
1997
1998 #[derive(Default)]
1999 struct Model { count: i32, label: String, values: Vec<f64>, labels: Vec<String> }
2000
2001 impl Model {
2002
2003 fn label(&self, _dev: &Dev<Self>, _arg: ()) -> Result<&str> {
2006 Ok(self.label.as_str())
2007 }
2008
2009 fn values(&self, _dev: &Dev<Self>, _arg: ()) -> Result<&[f64]> {
2010 Ok(&self.values)
2011 }
2012
2013 fn set_label(&mut self, _dev: &Dev<Self>, arg: String) -> Result<&str> {
2014 self.label = arg;
2015 Ok(self.label.as_str())
2016 }
2017
2018 fn add(&self, _dev: &Dev<Self>, arg: i32) -> Result<i32> {
2019 Ok(self.count + arg)
2020 }
2021
2022 fn incr(&mut self, _dev: &Dev<Self>, arg: i32) -> Result<i32> {
2023 self.count += arg;
2024 Ok(self.count)
2025 }
2026
2027 fn count(&self, _dev: &Dev<Self>) -> Result<i32> {
2030 Ok(self.count)
2031 }
2032
2033 fn set_count(&mut self, _dev: &Dev<Self>, arg: i32) -> Result<()> {
2034 self.count = arg;
2035 Ok(())
2036 }
2037
2038 fn count_full(&self, _dev: &Dev<Self>) -> Result<AttrRead<i32>> {
2040 Ok(AttrRead {
2041 value: Some(self.count),
2042 w_value: None,
2043 quality: AttrQuality::Valid,
2044 time: SystemTime::now(),
2045 })
2046 }
2047
2048 fn read_label(&self, _dev: &Dev<Self>) -> Result<&str> {
2049 Ok(self.label.as_str())
2050 }
2051
2052 fn read_values(&self, _dev: &Dev<Self>) -> Result<&[f64]> {
2053 Ok(&self.values)
2054 }
2055
2056 fn label_n(&self, _dev: &Dev<Self>, index: usize) -> Result<&str> {
2059 Ok(self.labels[index].as_str())
2060 }
2061
2062 fn tick(&mut self, _dev: &Dev<Self>) -> Result<i32> {
2064 self.count += 1;
2065 Ok(self.count)
2066 }
2067
2068 }
2069
2070 fn version(_model: &Model, _dev: &Dev<Model>, _arg: ()) -> Result<&'static str> {
2072 Ok("1.0.0")
2073 }
2074
2075 #[test]
2078 fn exec_signatures() {
2079
2080 let def = CommandDef::<Model>::new("Add").exec(Model::add);
2082 assert_eq!(def.in_kind, Some(CommandDataKind::Long));
2083 assert_eq!(def.out_kind, Some(CommandDataKind::Long));
2084
2085 let _ = CommandDef::<Model>::new("Incr").exec_exclusive(Model::incr);
2087
2088 let _ = CommandDef::<Model>::new("Status")
2091 .exec(|model: &Model, _dev: &Dev<Model>, (): ()| Ok(model.label.clone()));
2092
2093 let def = CommandDef::<Model>::new("Label")
2096 .out_kind(CommandDataKind::String)
2097 .exec_with(|model: &Model, dev, value| {
2098 Ok(model.label(dev, <()>::from_value(value)?)?.into())
2099 });
2100 assert_eq!(def.out_kind, Some(CommandDataKind::String));
2101
2102 let def = CommandDef::<Model>::new("Sum")
2104 .exec(|_model: &Model, _dev: &Dev<Model>, arg: Vec<f64>| Ok(arg.iter().sum::<f64>()));
2105 assert_eq!(def.in_kind, Some(CommandDataKind::DoubleArray));
2106 assert_eq!(def.out_kind, Some(CommandDataKind::Double));
2107
2108 let _ = CommandDef::<Model>::new("Scale")
2110 .exec(|_model: &Model, _dev: &Dev<Model>, arg: Vec<f64>| Ok(arg.iter().map(|v| v * 2.0).collect::<Vec<f64>>()));
2111 let _ = CommandDef::<Model>::new("Reverse")
2112 .exec(|_model: &Model, _dev: &Dev<Model>, arg: Vec<String>| Ok(arg.into_iter().rev().collect::<Vec<String>>()));
2113 let _ = CommandDef::<Model>::new("Zeros")
2114 .exec(|_model: &Model, _dev: &Dev<Model>, (): ()| Ok(Spectrum::<f64>::from(vec![0.0; 4])));
2115
2116 let def = CommandDef::<Model>::new("Version").exec(version);
2118 assert_eq!(def.out_kind, Some(CommandDataKind::String));
2119
2120 let def = CommandDef::<Model>::new("Label")
2122 .out_doc("The label of the device")
2123 .exec(Model::label);
2124 assert_eq!(def.in_kind, Some(CommandDataKind::Void));
2125 assert_eq!(def.out_kind, Some(CommandDataKind::String));
2126
2127 let def = CommandDef::<Model>::new("Values").exec(Model::values);
2128 assert_eq!(def.out_kind, Some(CommandDataKind::DoubleArray));
2129
2130 let def = CommandDef::<Model>::new("SetLabel").exec_exclusive(Model::set_label);
2132 assert_eq!(def.in_kind, Some(CommandDataKind::String));
2133 assert_eq!(def.out_kind, Some(CommandDataKind::String));
2134
2135 let def = CommandDef::<Model>::new("Status")
2138 .out_kind(CommandDataKind::String)
2139 .exec_with(|model: &Model, _dev, _value| Ok(model.label.as_str().into()));
2140 assert_eq!(def.in_kind, None);
2141 assert_eq!(def.out_kind, Some(CommandDataKind::String));
2142
2143 let _ = CommandDef::<Model>::new("Echo")
2145 .in_kind(CommandDataKind::String)
2146 .out_kind(CommandDataKind::String)
2147 .exec_with(|model: &Model, _dev, value| {
2148 let arg = <&str>::try_from(&value)?;
2149 Ok(format!("{}{arg}", model.label).into())
2150 });
2151
2152 let _ = CommandDef::<Model>::new("SetLabel")
2154 .in_kind(CommandDataKind::String)
2155 .out_kind(CommandDataKind::String)
2156 .exec_exclusive_with(|model: &mut Model, _dev, value| {
2157 model.label = String::try_from(value)?;
2158 Ok(model.label.as_str().into())
2159 });
2160
2161 }
2162
2163 #[test]
2166 fn attr_signatures() {
2167
2168 let def = AttrDef::<Model>::new("Count")
2170 .read(Model::count)
2171 .write_exclusive(Model::set_count);
2172 assert_eq!(def.kind, Some(AttrDataKind::Long));
2173 assert_eq!(def.format, Some(AttrDataFormat::Scalar));
2174
2175 let def = AttrDef::<Model>::new("Label").read(Model::read_label);
2177 assert_eq!(def.kind, Some(AttrDataKind::String));
2178 assert_eq!(def.format, Some(AttrDataFormat::Scalar));
2179
2180 let def = AttrDef::<Model>::new("Values").read(Model::read_values);
2181 assert_eq!(def.kind, Some(AttrDataKind::Double));
2182 assert_eq!(def.format, Some(AttrDataFormat::Spectrum(0)));
2183
2184 let def = AttrDef::<Model>::new("CountFull").read(Model::count_full);
2186 assert_eq!(def.kind, Some(AttrDataKind::Long));
2187
2188 let _ = AttrDef::<Model>::new("Ticks").read_exclusive(Model::tick);
2190
2191 let _ = AttrDef::<Model>::new("Double")
2193 .read(|model: &Model, _dev: &Dev<Model>| Ok(model.count * 2));
2194
2195 let _ = AttrDef::<Model>::new("Raw")
2197 .kind(AttrDataKind::Double)
2198 .format(AttrDataFormat::Spectrum(4096))
2199 .read_with(|model: &Model, _dev| Ok(AttrRead {
2200 value: Some(model.values.as_slice().into()),
2201 w_value: None,
2202 quality: AttrQuality::Valid,
2203 time: SystemTime::now(),
2204 }));
2205
2206 }
2207
2208 #[test]
2211 fn attr_config() {
2212
2213 let def = AttrDef::<Model>::new("Position")
2214 .read(Model::count)
2215 .doc("The position of the axis")
2216 .label("Position")
2217 .unit("mm")
2218 .standard_unit(1e-3)
2219 .display_unit("mm")
2220 .display_format("%8.3f")
2221 .display_level(DisplayLevel::Expert)
2222 .delta(0.5, Duration::from_millis(200))
2223 .change_event(0.001, None)
2224 .periodic_event(Duration::from_secs(1))
2225 .archive_event(0.1, None, Duration::from_secs(10))
2226 .memorized(AttrMemorized::RestoreAndWrite)
2227 .polled(Duration::from_millis(100));
2228
2229 assert_eq!(def.config.doc.as_deref(), Some("The position of the axis"));
2230 assert_eq!(def.config.label.as_deref(), Some("Position"));
2231 assert_eq!(def.config.unit.as_deref(), Some("mm"));
2232 assert_eq!(def.config.standard_unit, Some(1e-3));
2233 assert_eq!(def.config.display_unit.as_deref(), Some("mm"));
2234 assert_eq!(def.config.display_format.as_deref(), Some("%8.3f"));
2235 assert_eq!(def.display_level, DisplayLevel::Expert);
2236
2237 assert_eq!(def.config.delta, Some(AttrDeltaConfig {
2240 value: AttrNumber::Double(0.5),
2241 time: Some(Duration::from_millis(200)),
2242 }));
2243
2244 assert_eq!(def.config.change_event.abs_change, Some(0.001));
2247 assert_eq!(def.config.change_event.rel_change, None);
2248 assert_eq!(def.config.periodic_event.period, Some(Duration::from_secs(1)));
2249 assert_eq!(def.config.archive_event.abs_change, Some(0.1));
2250 assert_eq!(def.config.archive_event.period, Some(Duration::from_secs(10)));
2251
2252 assert_eq!(def.memorized, Some(AttrMemorized::RestoreAndWrite));
2253 assert_eq!(def.poll_period, Some(Duration::from_millis(100)));
2254
2255 let def = AttrDef::<Model>::new("Count").read(Model::count);
2258 assert_eq!(def.config, AttrConfig::default());
2259 assert_eq!(def.poll_period, None);
2260
2261 }
2262
2263 #[test]
2266 fn attr_ranges() {
2267
2268 let def = AttrDef::<Model>::new("Position")
2269 .read(Model::count)
2270 .range(-100.0..=100.0)
2271 .warning(-90.5..)
2272 .alarm(..=95.0);
2273
2274 assert_eq!(def.config.range, AttrRangeConfig {
2275 min: Some(AttrNumber::Double(-100.0)),
2276 max: Some(AttrNumber::Double(100.0)),
2277 });
2278
2279 assert_eq!(def.config.warning, AttrRangeConfig {
2281 min: Some(AttrNumber::Double(-90.5)),
2282 max: None,
2283 });
2284
2285 assert_eq!(def.config.alarm, AttrRangeConfig {
2287 min: None,
2288 max: Some(AttrNumber::Double(95.0)),
2289 });
2290
2291 let def = AttrDef::<Model>::new("Count")
2294 .read(Model::count)
2295 .range(-8..=8i32)
2296 .alarm(..=u64::MAX);
2297
2298 assert_eq!(def.config.range, AttrRangeConfig {
2299 min: Some(AttrNumber::Long(-8)),
2300 max: Some(AttrNumber::Long(8)),
2301 });
2302 assert_eq!(def.config.alarm.max, Some(AttrNumber::ULong(u64::MAX)));
2303
2304 assert_ne!(AttrNumber::ULong(u64::MAX), AttrNumber::ULong(u64::MAX - 1));
2307 assert_eq!(AttrNumber::ULong(u64::MAX).as_f64(), AttrNumber::ULong(u64::MAX - 1).as_f64());
2308
2309 assert_eq!(AttrNumber::Long(2), AttrNumber::Double(2.0));
2311 assert!(AttrNumber::Long(-1) < AttrNumber::ULong(0));
2312 assert!(AttrNumber::ULong(u64::MAX) > AttrNumber::ULong(u64::MAX - 1));
2313 assert_ne!(AttrNumber::Double(f64::NAN), AttrNumber::Double(f64::NAN));
2314
2315 }
2316
2317 #[test]
2318 #[should_panic(expected = "the value range cannot have an exclusive bound")]
2319 fn exclusive_range_bound() {
2320 let _ = AttrDef::<Model>::new("Position").range(-100.0..100.0);
2321 }
2322
2323 #[test]
2326 fn attr_layouts() {
2327
2328 let def = AttrDef::<Model>::new("Count").read(Model::count).scalar();
2329 assert_eq!(def.format, Some(AttrDataFormat::Scalar));
2330
2331 let def = AttrDef::<Model>::new("Values").read(Model::read_values).spectrum(4096);
2334 assert_eq!(def.format, Some(AttrDataFormat::Spectrum(4096)));
2335
2336 let def = AttrDef::<Model>::new("Values").spectrum(4096).read(Model::read_values);
2337 assert_eq!(def.kind, Some(AttrDataKind::Double));
2338 assert_eq!(def.format, Some(AttrDataFormat::Spectrum(4096)));
2339
2340 let def = AttrDef::<Model>::new("Frame")
2342 .kind(AttrDataKind::Double)
2343 .image(640, 480);
2344 assert_eq!(def.format, Some(AttrDataFormat::Image(640, 480)));
2345
2346 let def = AttrDef::<Model>::new("Values").read(Model::read_values).spectrum(0);
2348 assert_eq!(def.format, Some(AttrDataFormat::Spectrum(0)));
2349
2350 }
2351
2352 #[test]
2353 #[should_panic(expected = "the data format is already defined as Scalar")]
2354 fn incompatible_layout() {
2355 let _ = AttrDef::<Model>::new("Count").read(Model::count).spectrum(8);
2356 }
2357
2358 #[test]
2361 fn command_config() {
2362
2363 let def = CommandDef::<Model>::new("Add")
2364 .exec(Model::add)
2365 .display_level(DisplayLevel::Expert)
2366 .polled(Duration::from_secs(1));
2367
2368 assert_eq!(def.display_level, DisplayLevel::Expert);
2369 assert_eq!(def.poll_period, Some(Duration::from_secs(1)));
2370
2371 let def = CommandDef::<Model>::new("Add").exec(Model::add);
2373 assert_eq!(def.display_level, DisplayLevel::Operator);
2374 assert_eq!(def.poll_period, None);
2375
2376 }
2377
2378 #[test]
2380 fn class_doc() {
2381 let def = ClassDef::<Model>::new_default("Motor").doc("A single axis");
2382 assert_eq!(def.doc, "A single axis");
2383 let def = ClassDef::<Model>::new_default("Motor");
2384 assert_eq!(def.doc, "A Tango device");
2385 }
2386
2387 #[test]
2390 fn compatible_kinds() {
2391
2392 let def = CommandDef::<Model>::new("Add")
2394 .in_kind(CommandDataKind::Long)
2395 .exec(Model::add)
2396 .out_kind(CommandDataKind::Long);
2397 assert_eq!(def.in_kind, Some(CommandDataKind::Long));
2398 assert_eq!(def.out_kind, Some(CommandDataKind::Long));
2399
2400 let def = AttrDef::<Model>::new("Values")
2403 .read(Model::read_values)
2404 .format(AttrDataFormat::Spectrum(4096));
2405 assert_eq!(def.kind, Some(AttrDataKind::Double));
2406 assert_eq!(def.format, Some(AttrDataFormat::Spectrum(4096)));
2407
2408 let def = AttrDef::<Model>::new("Values")
2409 .format(AttrDataFormat::Spectrum(4096))
2410 .read(Model::read_values);
2411 assert_eq!(def.format, Some(AttrDataFormat::Spectrum(4096)));
2412
2413 }
2414
2415 #[test]
2416 #[should_panic(expected = "the argument kind is already defined as String")]
2417 fn incompatible_in_kind() {
2418 let _ = CommandDef::<Model>::new("Add")
2419 .in_kind(CommandDataKind::String)
2420 .exec(Model::add);
2421 }
2422
2423 #[test]
2424 #[should_panic(expected = "the result kind is already defined as Long")]
2425 fn incompatible_out_kind() {
2426 let _ = CommandDef::<Model>::new("Add")
2427 .exec(Model::add)
2428 .out_kind(CommandDataKind::Long64);
2429 }
2430
2431 #[test]
2432 #[should_panic(expected = "the data kind is already defined as String")]
2433 fn incompatible_attr_kind() {
2434 let _ = AttrDef::<Model>::new("Label")
2435 .read(Model::read_label)
2436 .write_exclusive(Model::set_count);
2437 }
2438
2439 #[test]
2440 #[should_panic(expected = "the data format is already defined as Scalar")]
2441 fn incompatible_attr_format() {
2442 let _ = AttrDef::<Model>::new("Count")
2443 .read(Model::count)
2444 .format(AttrDataFormat::Spectrum(8));
2445 }
2446
2447 #[test]
2448 #[should_panic(expected = "the maximum size is already defined as 8")]
2449 fn incompatible_attr_max() {
2450 let _ = AttrDef::<Model>::new("Values")
2451 .format(AttrDataFormat::Spectrum(8))
2452 .format(AttrDataFormat::Spectrum(4096));
2453 }
2454
2455
2456 #[test]
2457 #[should_panic(expected = "Test: the attribute Label cannot have the property \"max_alarm\", not supported by an attribute of type String")]
2458 fn unsupported_attr_prop() {
2459 let _ = ClassDef::<Model>::new_default("Test")
2460 .attr(AttrDef::new("Label")
2461 .read(Model::read_label)
2462 .alarm(..=5));
2463 }
2464
2465 #[test]
2466 #[should_panic(expected = "Test: the command name \"Do it\" is invalid")]
2467 fn invalid_command_name() {
2468 let _ = ClassDef::<Model>::new_default("Test").command(CommandDef::new("Do it"));
2469 }
2470
2471 #[test]
2472 #[should_panic(expected = "Test: the attribute name \"_Speed\" is invalid")]
2473 fn invalid_attr_name() {
2474 let _ = ClassDef::<Model>::new_default("Test").attr(AttrDef::new("_Speed").kind(AttrDataKind::Double).scalar());
2475 }
2476
2477 #[test]
2478 #[should_panic(expected = "the attribute State cannot have the property \"min_value\", not supported by an attribute of type State")]
2479 fn unsupported_state_prop() {
2480 let _ = ClassDef::<Model>::new_default("Test")
2481 .state_config(AttrConfig { range: AttrRangeConfig { min: Some(AttrNumber::Long(0)), max: None }, ..AttrConfig::default() });
2482 }
2483
2484 #[test]
2485 #[should_panic(expected = "the attribute Count cannot be memorized, it is not writable")]
2486 fn memorized_read_only() {
2487 let _ = ClassDef::<Model>::new_default("Test")
2488 .attr(AttrDef::new("Count")
2489 .read(Model::count)
2490 .memorized(AttrMemorized::RestoreSetPoint));
2491 }
2492
2493 #[test]
2494 #[should_panic(expected = "the attribute Values cannot be memorized, it is not a scalar")]
2495 fn memorized_spectrum() {
2496 let _ = ClassDef::<Model>::new_default("Test")
2497 .attr(AttrDef::new("Values")
2498 .memorized(AttrMemorized::RestoreAndWrite)
2499 .kind(AttrDataKind::Double)
2500 .format(AttrDataFormat::Spectrum(8))
2501 .write_with(|_model: &Model, _dev, _value| Ok(())));
2502 }
2503
2504 #[test]
2508 fn closures_borrowing() {
2509
2510 for index in 0..3 {
2513 let def = CommandDef::<Model>::new(format!("Label{index}"))
2514 .out_kind(CommandDataKind::String)
2515 .exec_with(move |model: &Model, dev, _value| {
2516 Ok(model.label_n(dev, index)?.into())
2517 });
2518 assert_eq!(def.out_kind, Some(CommandDataKind::String));
2519 }
2520
2521 let _ = CommandDef::<Model>::new("Push")
2523 .in_kind(CommandDataKind::String)
2524 .out_kind(CommandDataKind::String)
2525 .exec_exclusive_with(|model: &mut Model, _dev, value| {
2526 model.labels.push(String::try_from(value)?);
2527 Ok(model.labels.last().unwrap().as_str().into())
2528 });
2529
2530 for index in 0..3 {
2532 let def = AttrDef::<Model>::new(format!("Label{index}"))
2533 .kind(AttrDataKind::String)
2534 .format(AttrDataFormat::Scalar)
2535 .read_with(move |model: &Model, dev| {
2536 Ok(AttrRead {
2537 value: Some(model.label_n(dev, index)?.into()),
2538 w_value: None,
2539 quality: AttrQuality::Valid,
2540 time: SystemTime::now(),
2541 })
2542 });
2543 assert_eq!(def.kind, Some(AttrDataKind::String));
2544 }
2545
2546 }
2547
2548 struct Owning { values: Vec<f64> }
2552
2553 impl Owning {
2554 fn len(&self, _dev: &Dev<Self>, _arg: ()) -> Result<i32> { Ok(self.values.len() as i32) }
2555 fn first(&self, _dev: &Dev<Self>) -> Result<f64> { Ok(self.values[0]) }
2556 }
2557
2558 fn owning_defs(prefix: &str) -> (CommandDef<Owning>, AttrDef<Owning>) {
2561 let command = CommandDef::<Owning>::new("Len")
2562 .exec(Owning::len)
2563 .out_doc(prefix.to_owned());
2564 let attr = AttrDef::<Owning>::new("First")
2565 .read(Owning::first)
2566 .write_with({
2569 let prefix = prefix.to_owned();
2570 move |_model: &Owning, _dev, _value| {
2571 let _ = &prefix;
2572 Ok(())
2573 }
2574 });
2575 (command, attr)
2576 }
2577
2578 #[test]
2579 fn model_owned() {
2580 let values = [1.0, 2.0, 3.0];
2581 let prefix = format!("{} values", values.len());
2582 let (command, attr) = owning_defs(&prefix);
2583 drop(prefix);
2584 assert_eq!(command.out_kind, Some(CommandDataKind::Long));
2585 assert_eq!(attr.kind, Some(AttrDataKind::Double));
2586 }
2587
2588 struct AsyncModel { count: i32, label: String }
2591
2592 impl AsyncModel {
2593
2594 async fn add(&self, _dev: &Dev<Self>, arg: i32) -> Result<i32> {
2595 Ok(self.count + arg)
2596 }
2597
2598 async fn label(&self, _dev: &Dev<Self>, _arg: ()) -> Result<&str> {
2599 Ok(self.label.as_str())
2600 }
2601
2602 async fn incr(&mut self, _dev: &Dev<Self>, arg: i32) -> Result<i32> {
2603 self.count += arg;
2604 Ok(self.count)
2605 }
2606
2607 async fn count(&self, _dev: &Dev<Self>) -> Result<i32> {
2608 Ok(self.count)
2609 }
2610
2611 async fn set_count(&mut self, _dev: &Dev<Self>, arg: i32) -> Result<()> {
2612 self.count = arg;
2613 Ok(())
2614 }
2615
2616 async fn read_label(&self, _dev: &Dev<Self>) -> Result<&str> {
2617 Ok(self.label.as_str())
2618 }
2619
2620 async fn check_label(&self, _dev: &Dev<Self>, arg: String) -> Result<()> {
2621 let _ = arg.len();
2622 Ok(())
2623 }
2624
2625 async fn tick(&mut self, _dev: &Dev<Self>) -> Result<i32> {
2626 self.count += 1;
2627 Ok(self.count)
2628 }
2629
2630 async fn state(&self, _dev: &Dev<Self>) -> Result<DevState> {
2631 Ok(DevState::On)
2632 }
2633
2634 async fn status(&mut self, _dev: &Dev<Self>) -> Result<&str> {
2635 Ok(&self.label)
2636 }
2637
2638 fn status_label(&self, _dev: &Dev<Self>) -> Result<&str> {
2639 Ok(&self.label)
2640 }
2641
2642 }
2643
2644 #[test]
2648 fn exec_async_signatures() {
2649
2650 let def = CommandDef::<AsyncModel>::new("Add").exec_async(AsyncModel::add);
2651 assert_eq!(def.in_kind, Some(CommandDataKind::Long));
2652 assert_eq!(def.out_kind, Some(CommandDataKind::Long));
2653 assert!(matches!(def.exec, Some(ExecFn::SharedAsync(_))));
2654
2655 let def = CommandDef::<AsyncModel>::new("Label").exec_async(AsyncModel::label);
2657 assert_eq!(def.in_kind, Some(CommandDataKind::Void));
2658 assert_eq!(def.out_kind, Some(CommandDataKind::String));
2659
2660 let def = CommandDef::<AsyncModel>::new("Incr").exec_exclusive_async(AsyncModel::incr);
2661 assert_eq!(def.in_kind, Some(CommandDataKind::Long));
2662 assert!(matches!(def.exec, Some(ExecFn::ExclusiveAsync(_))));
2663
2664 let def = CommandDef::<AsyncModel>::new("Echo")
2666 .in_kind(CommandDataKind::String)
2667 .out_kind(CommandDataKind::String)
2668 .exec_async_with(|model: &AsyncModel, _dev, value| Box::pin(async move {
2669 let arg = <&str>::try_from(&value)?;
2670 Ok(format!("{}{arg}", model.label).into())
2671 }));
2672 assert_eq!(def.in_kind, Some(CommandDataKind::String));
2673 assert!(matches!(def.exec, Some(ExecFn::SharedAsync(_))));
2674
2675 let def = CommandDef::<AsyncModel>::new("SetLabel")
2676 .exec_exclusive_async_with(|model: &mut AsyncModel, _dev, value| Box::pin(async move {
2677 model.label = String::try_from(value)?;
2678 Ok(model.label.as_str().into())
2679 }));
2680 assert_eq!(def.in_kind, None);
2681 assert_eq!(def.out_kind, None);
2682 assert!(matches!(def.exec, Some(ExecFn::ExclusiveAsync(_))));
2683
2684 }
2685
2686 #[test]
2688 fn attr_async_signatures() {
2689
2690 let def = AttrDef::<AsyncModel>::new("Count")
2691 .read_async(AsyncModel::count)
2692 .write_exclusive_async(AsyncModel::set_count);
2693 assert_eq!(def.kind, Some(AttrDataKind::Long));
2694 assert_eq!(def.format, Some(AttrDataFormat::Scalar));
2695 assert!(matches!(def.read, Some(ReadFn::SharedAsync(_))));
2696 assert!(matches!(def.write, Some(WriteFn::ExclusiveAsync(_))));
2697
2698 let def = AttrDef::<AsyncModel>::new("Label")
2699 .read_async(AsyncModel::read_label)
2700 .write_async(AsyncModel::check_label);
2701 assert_eq!(def.kind, Some(AttrDataKind::String));
2702 assert!(matches!(def.write, Some(WriteFn::SharedAsync(_))));
2703
2704 let def = AttrDef::<AsyncModel>::new("Ticks").read_exclusive_async(AsyncModel::tick);
2705 assert!(matches!(def.read, Some(ReadFn::ExclusiveAsync(_))));
2706
2707 let def = AttrDef::<AsyncModel>::new("Raw")
2708 .kind(AttrDataKind::Long)
2709 .scalar()
2710 .read_async_with(|model: &AsyncModel, _dev| Box::pin(async move {
2711 Ok(AttrRead {
2712 value: Some(model.count.into()),
2713 w_value: None,
2714 quality: AttrQuality::Valid,
2715 time: SystemTime::now(),
2716 })
2717 }))
2718 .write_exclusive_async_with(|model: &mut AsyncModel, _dev, value| Box::pin(async move {
2719 model.count = i32::try_from(value)?;
2720 Ok(())
2721 }));
2722 assert!(matches!(def.read, Some(ReadFn::SharedAsync(_))));
2723 assert!(matches!(def.write, Some(WriteFn::ExclusiveAsync(_))));
2724
2725 }
2726
2727 #[test]
2728 #[should_panic(expected = "the data kind is already defined as String")]
2729 fn incompatible_attr_async_kind() {
2730 let _ = AttrDef::<AsyncModel>::new("Label")
2731 .read_async(AsyncModel::read_label)
2732 .write_exclusive_async(AsyncModel::set_count);
2733 }
2734
2735 #[test]
2738 fn class_async_handlers() {
2739
2740 let def = ClassDef::<AsyncModel>::new("Motor", |_dev| Ok(AsyncModel { count: 0, label: String::new() }))
2741 .state_async(AsyncModel::state)
2742 .status_exclusive_async(AsyncModel::status);
2743 assert!(matches!(def.state, Some(StateFn::SharedAsync(_))));
2744 assert!(matches!(def.status, Some(StatusFn::ExclusiveAsync(_))));
2745
2746 let def = def
2747 .state_exclusive_async_with(|_model: &mut AsyncModel, _dev| Box::pin(async { Ok(DevState::Moving) }))
2748 .status_async_with(|model: &AsyncModel, _dev| Box::pin(async move { Ok(Scalar::from(model.label.as_str())) }));
2749 assert!(matches!(def.state, Some(StateFn::ExclusiveAsync(_))));
2750 assert!(matches!(def.status, Some(StatusFn::SharedAsync(_))));
2751
2752 }
2753
2754 #[test]
2757 fn class_status_handlers() {
2758
2759 let def = ClassDef::<AsyncModel>::new("Motor", |_dev| Ok(AsyncModel { count: 0, label: String::new() }))
2760 .status(AsyncModel::status_label);
2761 assert!(matches!(def.status, Some(StatusFn::SharedSync(_))));
2762
2763 let def = def.status_exclusive(|model: &mut AsyncModel, _dev: &Dev<AsyncModel>| Ok(format!("Count is {}", model.count)));
2764 assert!(matches!(def.status, Some(StatusFn::ExclusiveSync(_))));
2765
2766 }
2767
2768}