Skip to main content

tango/server/
class.rs

1//! Implementation of the classes of a server.
2
3use std::sync::{Arc, Mutex, Weak};
4use std::collections::HashMap;
5use std::fmt::{self, Debug};
6use std::future::Future;
7
8use crate::dev::{All, Named, ToNames, ToNamesNotAll};
9use crate::database::{GetPropSpec, SetPropSpec};
10use crate::error::{Error, ErrorKind, Result};
11use crate::name::{ArcName, Name};
12use crate::value::Spectrum;
13
14use super::{reserved_name, Model, Ref, RESERVED_ATTRS};
15use super::dev::{AnyDev, Dev};
16use super::server::Server;
17use super::def::ClassDef;
18
19
20/// A class of any model, which is how the server holds its classes.
21pub trait AnyClass: Debug + Send + Sync {
22
23    /// The name of that class.
24    fn name(&self) -> &str;
25
26    /// The rank of that class among the classes of its server, which is the order they
27    /// were made in and the order their devices are initialized in, see [`Server::sync`].
28    fn index(&self) -> usize;
29
30    /// Add a device of that class to the server, see [`Class::add_dev`].
31    fn add_dev(&self, name: &str) -> Result<Arc<dyn AnyDev>>;
32
33}
34
35pub struct Class<M: Model> {
36    /// The name of that class, as its definition gave it, shared with the key it is
37    /// registered under in the server.
38    name: Arc<str>,
39    /// See [`AnyClass::index`].
40    index: usize,
41    /// Self reference, for what a class hands its devices of itself.
42    this: Weak<Self>,
43    server: Arc<Server>,
44    def: Arc<ClassDef<M>>,
45    /// The properties the database holds for the attributes of this class, by attribute
46    /// name, which every device of the class is configured from, see [`Self::attr_props`].
47    attr_props: Mutex<HashMap<ArcName, Arc<[Named<Spectrum<str>>]>>>,
48}
49
50impl<M: Model> Class<M> {
51
52    /// A new class of that server, from its definition, at that rank among the classes of
53    /// the server, see [`AnyClass::index`].
54    pub(super) fn new(server: Arc<Server>, def: Arc<ClassDef<M>>, index: usize) -> Arc<Self> {
55        Arc::new_cyclic(|this| Self {
56            name: Arc::from(&*def.name),
57            index,
58            this: this.clone(),
59            server,
60            def,
61            attr_props: Mutex::new(HashMap::new()),
62        })
63    }
64
65    #[inline]
66    pub fn name(&self) -> &str {
67        &self.name
68    }
69
70    #[inline]
71    pub fn server(&self) -> &Server {
72        &self.server
73    }
74
75    // The properties of a class are the database's: everything below asks the database 
76    // of the server for what it holds of this class, see the very same methods on
77    // [`crate::database::DatabaseProxy`]. The blocking forms are for synchronous handlers, 
78    // which run on the pool, and must never run in an asynchronous one.
79
80    /// The names of the properties of this class that match the given filter.
81    pub async fn list_prop_async(&self, filter: &str) -> Result<Spectrum<str>> {
82        self.server().database().list_class_prop_async(&self.name, filter).await
83    }
84
85    /// The names of the properties of this class, see [`Self::list_prop_async`].
86    pub fn list_prop(&self, filter: &str) -> Result<Spectrum<str>> {
87        self.server().database().list_class_prop(&self.name, filter)
88    }
89
90    /// The properties of this class, parsed into the shape the given names ask for, see
91    /// [`crate::database::DatabaseProxy::get_class_prop`].
92    pub fn get_prop_async<Spec, Names: ToNames>(&self, names: Names) -> impl Future<Output = Result<Spec::Output>> + Send
93    where
94        Spec: GetPropSpec<Names>,
95    {
96        self.server().database().get_class_prop_async::<Spec, Names>(&self.name, names)
97    }
98
99    /// The properties of this class, see [`Self::get_prop_async`].
100    pub fn get_prop<Spec, Names: ToNames>(&self, names: Names) -> Result<Spec::Output>
101    where
102        Spec: GetPropSpec<Names>,
103    {
104        self.server().database().get_class_prop::<Spec, Names>(&self.name, names)
105    }
106
107    /// Write the given properties of this class.
108    pub fn set_prop_async<'a, Spec>(&'a self, spec: Spec) -> impl Future<Output = Result<()>> + Send
109    where
110        Spec: SetPropSpec<'a>,
111    {
112        self.server().database().set_class_prop_async(&self.name, spec)
113    }
114
115    /// Write the given properties of this class, see [`Self::set_prop_async`].
116    pub fn set_prop<'a, Spec>(&'a self, spec: Spec) -> Result<()>
117    where
118        Spec: SetPropSpec<'a>,
119    {
120        self.server().database().set_class_prop(&self.name, spec)
121    }
122
123    /// Delete the given properties of this class.
124    pub fn del_prop_async<Names: ToNamesNotAll>(&self, names: Names) -> impl Future<Output = Result<()>> + Send {
125        self.server().database().del_class_prop_async(&self.name, names)
126    }
127
128    /// Delete the given properties of this class, see [`Self::del_prop_async`].
129    pub fn del_prop<Names: ToNamesNotAll>(&self, names: Names) -> Result<()> {
130        self.server().database().del_class_prop(&self.name, names)
131    }
132
133    /// The properties the database holds for the attributes of this class of those names,
134    /// in the same order, an attribute it holds nothing for having none.
135    /// 
136    /// They are the same for every device of the class, so the database is only asked the
137    /// first time a device has an attribute of that name, and never again: what a device
138    /// is configured with only changes at the level of the device itself, which is the
139    /// one a client changes.
140    ///
141    /// The State and the Status have none, whatever the database holds: they are the
142    /// server's own, which only the device configures, the way cppTango does.
143    pub(super) async fn attr_props(&self, names: &[&str]) -> Result<Vec<Arc<[Named<Spectrum<str>>]>>> {
144
145        // Only refetch the missing attribute names.
146        let missing = {
147            let attr_props = self.attr_props.lock().unwrap();
148            names.iter()
149                .copied()
150                .filter(|name| !attr_props.contains_key(Name::new(name)))
151                .filter(|name| reserved_name(name, RESERVED_ATTRS).is_none())
152                .collect::<Vec<_>>()
153        };
154
155        if !missing.is_empty() {
156            
157            let fetched = self.server()
158                .database()
159                .get_class_attr_prop_async::<Spectrum<str>, _, _>(&self.name, missing.as_slice(), All).await?;
160
161            let mut attr_props = self.attr_props.lock().unwrap();
162            for (name, props) in missing.into_iter().zip(fetched) {
163                attr_props.insert(ArcName::from(Arc::<str>::from(name)), Arc::from(props?));
164            }
165
166        }
167
168        let attr_props = self.attr_props.lock().unwrap();
169        Ok(names
170            .iter()
171            .map(|name| attr_props.get(Name::new(name))
172                .map_or_else(|| Arc::from([]), Arc::clone))
173            .collect())
174
175    }
176
177    #[inline]
178    pub fn def(&self) -> &ClassDef<M> {
179        &self.def
180    }
181
182    /// Add a device of that class to the server, whose name has to be unique server-wide.
183    /// 
184    /// The device is only registered: it is initialized, served and exported by the next
185    /// [`Server::sync`].
186    pub fn add_dev(&self, name: &str) -> Result<Ref<'_, Dev<M>>> {
187        self.new_dev(name).map(Ref::new)
188    }
189
190    /// See [`Self::add_dev`].
191    fn new_dev(&self, name: &str) -> Result<Arc<Dev<M>>> {
192
193        let mut server_devs = self.server.devs.lock().unwrap();
194        if server_devs.contains_key(Name::new(name)) {
195            return Err(Error::new(ErrorKind::DevAlreadyDefined)
196                .with_append_description(format_args!("Device {name:?}")));
197        }
198
199        let name = Arc::<str>::from(name);
200        // A class is only ever reached through a reference to it, so it is alive.
201        let dev = Dev::new(self.this.upgrade().unwrap(), Arc::clone(&name));
202        server_devs.insert(ArcName::from(name), Arc::clone(&dev) as Arc<dyn AnyDev>);
203        drop(server_devs);
204
205        self.server.pending.lock().unwrap().added.push(Arc::clone(&dev) as Arc<dyn AnyDev>);
206        Ok(dev)
207
208    }
209
210}
211
212impl<M: Model> AnyClass for Class<M> {
213
214    #[inline]
215    fn name(&self) -> &str {
216        &self.name
217    }
218
219    #[inline]
220    fn index(&self) -> usize {
221        self.index
222    }
223
224    fn add_dev(&self, name: &str) -> Result<Arc<dyn AnyDev>> {
225        self.new_dev(name).map(|dev| dev as Arc<dyn AnyDev>)
226    }
227
228}
229
230impl<M: Model> Debug for Class<M> {
231    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
232        f.debug_struct("Class").field("name", &self.name).finish_non_exhaustive()
233    }
234}