Skip to main content

tango/server/
mod.rs

1//! This module provides a high-level access to the server-side of Tango.
2
3mod def;
4
5mod server;
6mod class;
7mod dev;
8mod attr;
9mod command;
10
11mod admin;
12mod signal;
13
14#[cfg(feature = "cli")]
15mod cli;
16
17pub use def::{ClassDef, CommandDef, AttrDef};
18pub use server::{Server, ServerBuilder, ServerHandle};
19pub use class::{AnyClass, Class};
20pub use dev::{AnyDev, Dev};
21pub use command::Command;
22pub use attr::Attr;
23#[cfg(feature = "cli")]
24pub use cli::ServerArgs;
25
26use std::marker::PhantomData;
27use std::fmt::{self, Debug};
28use std::ops::Deref;
29use std::sync::{Arc, Weak};
30
31use crate::dev::DevState;
32
33
34/// What a device model has to be, gathering in one bound everything a server needs of it:
35/// it is shared between the threads serving the requests, and it lives as long as the
36/// class it belongs to, which is as long as the server serving it.
37///
38/// Every such type is a model, there being nothing to implement: this is the bound the
39/// definitions and the devices are written against rather than a trait a model opts into.
40pub trait Model: Send + Sync + 'static {}
41impl<T: Send + Sync + 'static> Model for T {}
42
43/// The name of the attribute, and of the command, every device gives its state under.
44const STATE_NAME: &str = "State";
45/// The name of the attribute, and of the command, every device gives its status under.
46const STATUS_NAME: &str = "Status";
47/// The name of the command every device is initialized again by.
48const INIT_NAME: &str = "Init";
49/// The names of the attributes every device has whatever its class.
50const RESERVED_ATTRS: &[&str] = &[STATE_NAME, STATUS_NAME];
51/// The names of the commands every device has whatever its class.
52const RESERVED_COMMANDS: &[&str] = &[STATE_NAME, STATUS_NAME, INIT_NAME];
53/// The status of a device that has no model because it has not been initialized yet,
54/// which every device is between the moment it is added and the moment it is synchronized.
55const MISSING_STATUS: &str = "The device is not initialized";
56/// The status of a device whose class derives no status of its own from the model.
57const DEFAULT_STATUS: &str = "Device is on";
58/// The state of a device whose class derives no state of its own from the model, which is
59/// the one every device that has nothing to say of itself is in.
60const DEFAULT_STATE: DevState = DevState::On;
61
62/// The reserved name that name is, if it is one: the state, the status and the
63/// initialization of a device are answered by the server itself, whatever its class and its
64/// devices define, so anything defined under one of those names would never be reached.
65/// 
66/// Given back in the spelling of the reserved name rather than of the one that was asked
67/// for, the two differing only by their case, so that a refusal can point at both.
68fn reserved_name<'r>(name: &str, reserved: &'r [&'r str]) -> Option<&'r str> {
69    reserved.iter().copied().find(|other| name.eq_ignore_ascii_case(other))
70}
71
72/// A reference to something a server owns, which derefs to it but never gives out the
73/// [`Arc`] it holds, and borrows what it was given by: this is what keeps the users of a
74/// server from keeping any of it alive past the shutdown of that server, since ownership
75/// is cyclic and only broken by that shutdown, see [`server::ServerHandle`].
76pub struct Ref<'a, T: ?Sized> {
77    inner: Arc<T>,
78    _borrow: PhantomData<&'a T>,
79}
80
81impl<T: ?Sized> Ref<'_, T> {
82
83    #[inline]
84    pub(super) fn new(inner: Arc<T>) -> Self {
85        Self { inner, _borrow: PhantomData }
86    }
87
88    /// A weak reference to what this refers to, see [`WeakRef`]. This is an associated
89    /// function, as [`Arc::downgrade`] is, so that it never hides a method of the target.
90    #[inline]
91    pub fn downgrade(this: &Self) -> WeakRef<T> {
92        WeakRef { inner: Arc::downgrade(&this.inner) }
93    }
94
95}
96
97impl<T: ?Sized> Deref for Ref<'_, T> {
98    type Target = T;
99    #[inline]
100    fn deref(&self) -> &T {
101        &self.inner
102    }
103}
104
105impl<T: ?Sized + Debug> Debug for Ref<'_, T> {
106    #[inline]
107    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108        Debug::fmt(&*self.inner, f)
109    }
110}
111
112/// A weak reference to something a server owns, see [`Ref::downgrade`], which keeps
113/// nothing of it alive and can therefore be kept anywhere, a thread of its own in
114/// particular. What it upgrades into is a [`Ref`] borrowed from it, so that it is only held
115/// for as long as it is used.
116///
117/// It is tied to that very thing: a device removed, or replaced by a restart under the
118/// same name, no longer upgrades, which is what tells a thread it started to stop.
119pub struct WeakRef<T: ?Sized> {
120    inner: Weak<T>,
121}
122
123impl<T: ?Sized> WeakRef<T> {
124
125    /// What this refers to, if it is still there.
126    #[inline]
127    pub fn upgrade(&self) -> Option<Ref<'_, T>> {
128        self.inner.upgrade().map(Ref::new)
129    }
130
131}
132
133impl<T: ?Sized> Clone for WeakRef<T> {
134    #[inline]
135    fn clone(&self) -> Self {
136        Self { inner: self.inner.clone() }
137    }
138}
139
140impl<T: ?Sized> Debug for WeakRef<T> {
141    #[inline]
142    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
143        f.write_str("(WeakRef)")
144    }
145}