Skip to main content

tango/
dev.rs

1//! All proxy class to devices, classes and servers.
2
3use std::sync::{Arc, OnceLock, RwLock};
4use std::time::{Duration, SystemTime};
5use std::fmt::{self, Debug, Display};
6use std::task::{Context, Poll};
7use std::hash::{Hash, Hasher};
8use std::future::Future;
9use std::cmp::Ordering;
10use std::str::FromStr;
11use std::borrow::Cow;
12use std::{env, mem};
13use std::pin::Pin;
14
15use futures::stream::{BoxStream, Stream, StreamExt};
16use futures::ready;
17use tracing::{debug, instrument, warn};
18use futures::future::{poll_fn, BoxFuture};
19
20use crate::value::{AttrDataFormat, AttrDataKind, CommandDataKind, FromValue, IntoValue, Scalar, Spectrum, Value};
21use crate::database::{prop_params, set_prop_params, DatabaseProxy, GetPropSpec, PropCommands, SetPropSpec};
22use crate::backend::{default_backend, Backend, BackendDev};
23use crate::error::{Error, ErrorKind, Result, reason};
24use crate::name::{ArcTrl, IntoTrl, TrlObject};
25use crate::future::block_on_timeout;
26use crate::local;
27
28
29/// Default deadline budget applied to a single proxy operation (connection + request).
30/// This is a placeholder default (mirroring cppTango's 3s) until a configurable per-proxy
31/// timeout is introduced.
32const DEFAULT_TIMEOUT: Duration = Duration::from_secs(3);
33
34/// The statically known device name for the database device in its server.
35pub(crate) const DATABASE_DEV_NAME: &str = "database";
36
37/// A device proxy is an object that allows querying a remote device.
38/// 
39/// Equality and hash between two device proxies is defined by if their target is similar
40/// or not, not the actual backend being identical!
41/// 
42/// The [`Eq`] and [`Hash`] implementation is entirely based on the internal target of 
43/// of the device, not its `trl`, nor its actual implementation details.
44#[derive(Debug)]
45pub struct DevProxy {
46    /// The inner structure, boxed to reduce exposed size.
47    inner: Box<ProxyInner>,
48    /// The state of this proxy, behind a read-write lock.
49    state: RwLock<ProxyState>,
50}
51
52#[derive(Debug, Clone)]
53struct ProxyInner {
54    // The backend, shared with a reference-counted pointer.
55    backend: Arc<dyn Backend>,
56    /// The source configured for this proxy.
57    source: DevSource,
58    /// The timeout configured for this proxy.
59    timeout: Duration,
60    /// The real target for connection of this proxy.
61    target: ProxyTarget,
62}
63
64#[derive(Debug, Clone)]
65struct ProxyState {
66    /// The actual backend in use, none if the last call errored.
67    backend: Option<Arc<dyn BackendDev>>,
68    /// In case the target is directly a database, this contains he host and port of the
69    /// database connected to, this is used to construct the TRL.
70    database_host_and_port: Option<(Arc<str>, u16)>,
71}
72
73/// Target for a device proxy, this is used so that the DevProxy can also be responsible
74/// for connecting to a database as well as regular devices. The device name might be an
75/// alias!
76#[derive(Debug, Clone, PartialEq, Eq, Hash)]
77pub(crate) enum ProxyTarget {
78    /// Database device from environment.
79    DatabaseFromEnv,
80    /// Database device from host and port.
81    DatabaseAt {
82        host: Arc<str>,
83        port: u16,
84    },
85    /// Regular device from a database.
86    RegularFromDatabase {
87        database: DatabaseProxy,
88        name: Arc<str>,
89    },
90    /// A regular device accessible directly from a given service on a host, no database
91    /// is involved!
92    RegularAt {
93        host: Arc<str>,
94        port: u16,
95        name: Arc<str>,
96    },
97}
98
99impl DevProxy {
100
101    /// Same as [`Self::try_new`] but panics if the TRL is invalid for a device proxy.
102    pub fn new<'a>(trl: impl IntoTrl<'a>) -> Self {
103        Self::new_with_backend(default_backend(), trl)
104    }
105
106    /// Create a new device proxy located by the given Tango Resource Locator, the given
107    /// TRL should not target an attribute or property, or else this function will return
108    /// None.
109    pub fn try_new<'a>(trl: impl IntoTrl<'a>) -> Option<Self> {
110        Self::try_new_with_backend(default_backend(), trl)
111    }
112
113    /// Create a new device from a database and the device's name.
114    pub fn new_from_database(database: &DatabaseProxy, name: &str) -> Self {
115        Self::new_from_database_with_backend(default_backend(), database, name)
116    }
117
118    /// Same as [`Self::try_new`] but panics if the TRL is invalid for a device proxy.
119    pub fn new_with_backend<'a>(backend: Arc<dyn Backend>, trl: impl IntoTrl<'a>) -> Self {
120        Self::try_new_with_backend(backend, trl).expect("The given TRL does not target a device")
121    }
122
123    /// Create a new device proxy located by the given Tango Resource Locator, the given
124    /// TRL should not target an attribute or property, or else this function will return
125    /// None.
126    pub fn try_new_with_backend<'a>(backend: Arc<dyn Backend>, trl: impl IntoTrl<'a>) -> Option<Self> {
127
128        let trl = trl.into_trl().ok()?;
129
130        // We can't target a property!
131        if trl.property().is_some() {
132            return None;
133        }
134
135        let name = match trl.object() {
136            TrlObject::Alias(name) => name,
137            TrlObject::Dev(name) => name,
138            TrlObject::Attr(_, _) => return None,
139        };
140
141        let target = match (trl.db(), trl.host_and_port()) {
142            (true, Some((host, port))) => ProxyTarget::RegularFromDatabase { 
143                database: DatabaseProxy::new_with_backend(Arc::clone(&backend), host, port),
144                name: Arc::from(name),
145            },
146            (true, None) => ProxyTarget::RegularFromDatabase { 
147                database: DatabaseProxy::new_from_env_with_backend(Arc::clone(&backend)), 
148                name: Arc::from(name),
149            },
150            (false, Some((host, port))) => ProxyTarget::RegularAt { 
151                host: Arc::from(host), 
152                port, 
153                name: Arc::from(name),
154            },
155            (false, None) => return None,
156        };
157
158        Some(Self::new_from_target_with_backend(backend, target))
159        
160    }
161
162    /// Create a new device from a database and the device's name, with backend.
163    pub fn new_from_database_with_backend(backend: Arc<dyn Backend>, database: &DatabaseProxy, name: &str) -> Self {
164        Self::new_from_target_with_backend(backend, ProxyTarget::RegularFromDatabase { 
165            database: database.clone(), 
166            name: Arc::from(name),
167        })
168    }
169
170    /// Internal function to create a device proxy for the given target, with backend.
171    pub(crate) fn new_from_target_with_backend(backend: Arc<dyn Backend>, target: ProxyTarget) -> Self {
172        Self {
173            inner: Box::new(ProxyInner {
174                backend,
175                target,
176                source: DevSource::CacheDev,
177                timeout: DEFAULT_TIMEOUT,
178            }),
179            state: RwLock::new(ProxyState {
180                backend: None,
181                database_host_and_port: None,
182            }),
183        }
184    }
185
186    pub fn backend(&self) -> &Arc<dyn Backend> {
187        &self.inner.backend
188    }
189
190    /// Retrieve the timeout duration currently used for all requests.
191    pub fn timeout(&self) -> Duration {
192        self.inner.timeout
193    }
194
195    /// Set the timeout duration and return the previous one. See [`Self::timeout`].
196    pub fn set_timeout(&mut self, timeout: Duration) -> Duration {
197        mem::replace(&mut self.inner.timeout, timeout)
198    }
199
200    /// Retrieve the source of data currently used for attribute readings and commands.
201    pub fn source(&self) -> DevSource {
202        self.inner.source
203    }
204
205    /// Set the source of data and return the previous one. See [`Self::source`].
206    pub fn set_source(&mut self, source: DevSource) -> DevSource {
207        mem::replace(&mut self.inner.source, source)
208    }
209
210    /// Internal function to initialize a brand new connection to this device proxy.
211    /// 
212    /// Boxed, because connecting a device goes through the database, itself a device
213    /// connected by this very function.
214    fn connect_backend(&self) -> BoxFuture<'_, Result<(Arc<dyn BackendDev>, Option<(Arc<str>, u16)>)>> {
215        Box::pin(async move {
216
217            match self.inner.target {
218                ProxyTarget::DatabaseFromEnv => {
219
220                    debug!("Connecting to the database of TANGO_HOST");
221
222                    let databases = env_databases();
223                    if databases.is_empty() {
224                        return Err(Error::new(ErrorKind::TangoHostNotSet)
225                            .with_append_description(match env::var("TANGO_HOST") {
226                                Ok(var) => format!("TANGO_HOST is {var:?}"),
227                                Err(_) => "TANGO_HOST is not defined in the environment".to_string(),
228                            }));
229                    }
230
231                    let mut last_err = None;
232                    for (host, port) in databases {
233
234                        if let Some(dev_backend) = local::find_at(host, *port, DATABASE_DEV_NAME) {
235                            debug!(%host, port, "Connected to the database, served by this process");
236                            return Ok((dev_backend, Some((host.clone(), *port))));
237                        }
238
239                        match self.inner.backend.connect_at(host, *port, DATABASE_DEV_NAME).await {
240                            Ok(dev_backend) => {
241                                debug!(%host, port, "Connected to the database");
242                                return Ok((dev_backend, Some((host.clone(), *port))));
243                            }
244                            Err(err) => {
245                                warn!(%host, port, %err, "Failed to connect to the database, trying the next one");
246                                last_err = Some(err);
247                            }
248                        }
249                    }
250
251                    // Every database in TANGO_HOST has been tried, the last failure being the
252                    // one kept as the cause: naming them all is what tells the reader that the
253                    // other ones were tried too.
254                    let mut err = Error::new(ErrorKind::DatabaseNotConnected)
255                        .with_append_description(format_args!("Tried, from TANGO_HOST: {}", DisplayHostAndPorts(databases)));
256                    if let Some(last_err) = last_err {
257                        err.set_parent(last_err);
258                    }
259                    Err(err)
260
261                }
262                ProxyTarget::DatabaseAt { ref host, port } => {
263                
264                    debug!(%host, port, "Connecting to the database");
265
266                    if let Some(dev_backend) = local::find_at(host, port, DATABASE_DEV_NAME) {
267                        debug!(%host, port, "Connected to the database, served by this process");
268                        return Ok((dev_backend, Some((host.clone(), port))));
269                    }
270
271                    match self.inner.backend.connect_at(&host, port, DATABASE_DEV_NAME).await {
272                        Ok(dev_backend) => {
273                            debug!(%host, port, "Connected to the database");
274                            Ok((dev_backend, Some((host.clone(), port))))
275                        }
276                        Err(err) => Err(Error::new(ErrorKind::DatabaseNotConnected)
277                            .with_append_description(format_args!("Tried: {host}:{port}"))
278                            .with_parent(err)),
279                    }
280
281                }
282                ProxyTarget::RegularFromDatabase { ref database, ref name } => {
283
284                    debug!(dev = %name, "Connecting to the device, through the database");
285                    
286                    let info = match database.import_dev_async(name).await {
287                        Ok(info) if !info.exported =>
288                            return Err(Error::new(ErrorKind::DevNotFound)
289                                .with_description("The device is defined in the database but no running server exports it")
290                                .with_append_description(format_args!("Device {name:?} of the server {:?}", info.server))),
291                        Ok(info) => info,
292                        Err(err) if let ErrorKind::DevNotConnected = err.kind() =>
293                            return Err(Error::new(ErrorKind::DatabaseNotConnected)
294                                .with_parent(err)),
295                        Err(err) => return Err(err),
296                    };
297
298                    // A device this very process serves is reached directly, whatever the
299                    // backend, the reference telling it apart from any other of that name.
300                    if let Some(dev_backend) = local::find(info.itr.value()) {
301                        debug!(dev = %name, "Connected to the device, served by this process");
302                        return Ok((dev_backend, None));
303                    }
304
305                    // The kind is left alone: it is the one the backend found, and 'with_backend'
306                    // keys the reconnection on it. Only the context of the call is added.
307                    match self.inner.backend.connect(info.itr.value()).await {
308                        Ok(dev_backend) => {
309                            debug!(dev = %name, "Connected to the device");
310                            Ok((dev_backend, None))
311                        }
312                        Err(err) => Err(err.with_append_description(format_args!(
313                            "While connecting to the device {name:?} of the server {:?}, exported by the database on host {:?}",
314                            info.server, info.host))),
315                    }
316
317                }
318                ProxyTarget::RegularAt { ref host, port, ref name } => {
319                
320                    debug!(%host, port, dev = %name, "Connecting to the device");
321
322                    if let Some(dev_backend) = local::find_at(host, port, name) {
323                        debug!(%host, port, dev = %name, "Connected to the device, served by this process");
324                        return Ok((dev_backend, None));
325                    }
326
327                    match self.inner.backend.connect_at(&host, port, &name).await {
328                        Ok(dev_backend) => {
329                            debug!(%host, port, dev = %name, "Connected to the device");
330                            Ok((dev_backend, None))
331                        }
332                        Err(err) => Err(err.with_append_description(format_args!(
333                            "While connecting to the device {name:?} at {host}:{port}"))),
334                    }
335
336                }
337            }
338
339        })
340    }
341
342    /// Give back the backend this proxy reaches its device through, connecting it if that
343    /// has not happened yet.
344    ///
345    /// The connection is awaited with no lock of the proxy held: a guard cannot travel
346    /// across an await, and keeping one here would hold every other reader of the proxy
347    /// for the whole of a round trip. Two callers landing here at once therefore both
348    /// connect, and the one that stores its backend first is the one that is kept, the
349    /// other connection being dropped on the spot.
350    async fn ensure_backend(&self) -> Result<Arc<dyn BackendDev>> {
351
352        if let Some(backend) = self.state.read().unwrap().backend.as_ref() {
353            return Ok(Arc::clone(backend));
354        }
355
356        let (backend, database_host_and_port) = self.connect_backend().await?;
357
358        let mut state = self.state.write().unwrap();
359        match state.backend {
360            Some(ref backend) => Ok(Arc::clone(backend)),
361            None => {
362                state.backend = Some(Arc::clone(&backend));
363                state.database_host_and_port = database_host_and_port;
364                Ok(backend)
365            }
366        }
367
368    }
369
370    fn reset_backend(&self) {
371        let mut state = self.state.write().unwrap();
372        state.backend = None;
373        state.database_host_and_port = None;
374    }
375
376    fn check_backend<T>(&self, res: Result<T>) -> Result<T> {
377        if let Err(err) = &res && err.kind() == ErrorKind::DevNotConnected {
378            self.reset_backend();
379        }
380        res
381    }
382
383    pub(crate) fn block_on<F: Future>(&self, fut: F) -> Result<F::Output> {
384        block_on_timeout(fut, self.inner.timeout)
385    }
386
387    fn database_host_and_port(&self) -> Result<Option<(Arc<str>, u16)>> {
388        self.block_on(self.database_host_and_port_async())?
389    }
390
391    /// The host and port of the database this proxy reached its device through, connecting
392    /// it if that has not happened yet, see [`Self::database_host_and_port`].
393    pub(crate) async fn database_host_and_port_async(&self) -> Result<Option<(Arc<str>, u16)>> {
394        self.ensure_backend().await?;
395        Ok(self.state.read().unwrap().database_host_and_port.clone())
396    }
397
398    /// Return the [`DatabaseProxy`] this device has been requested from! If the device
399    /// is no db and is not a database, then it returns None.
400    pub fn database(&self) -> Result<&DatabaseProxy> {
401        match self.inner.target {
402            ProxyTarget::DatabaseFromEnv |
403            ProxyTarget::DatabaseAt { .. } => 
404                Ok(DatabaseProxy::from_dev(self)),
405            ProxyTarget::RegularFromDatabase { ref database, .. } => 
406                Ok(database),
407            ProxyTarget::RegularAt { .. } => 
408                Err(Error::new(ErrorKind::DatabaseNeeded)),
409        }
410    }
411
412    /// Resolve this device's fully qualified device name.
413    #[instrument(skip(self), fields(target = %self.inner.target))]
414    pub fn trl(&self) -> Result<ArcTrl> {
415        match self.inner.target {
416            ProxyTarget::DatabaseFromEnv => {
417                let name = self.name()?;
418                let (host, port) = self.database_host_and_port()?
419                    .expect("This should be defined if the target is a database");
420                Ok(format!("tango://{host}:{port}/{name}").parse::<ArcTrl>().unwrap())
421            }
422            ProxyTarget::DatabaseAt { ref host, port } => {
423                let name = self.name()?;
424                Ok(format!("tango://{host}:{port}/{name}").parse::<ArcTrl>().unwrap())
425            }
426            ProxyTarget::RegularFromDatabase { ref database, ref name } => {
427                let (host, port) = database.database_host_and_port()?
428                    .expect("This should be defined if the target is a database");
429                Ok(format!("tango://{host}:{port}/{name}").parse::<ArcTrl>().unwrap())
430            }
431            ProxyTarget::RegularAt { ref host, port, ref name } => {
432                Ok(format!("tango://{host}:{port}/{name}#dbase=no").parse::<ArcTrl>().unwrap())
433            }
434        }
435    }
436
437    /// Connect this proxy to its device if that has not happened yet, so that its clones
438    /// share that connection instead of each making its own.
439    #[instrument(skip(self), fields(target = %self.inner.target))]
440    pub fn connect(&self) -> Result<()> {
441        self.block_on(self.connect_async())?
442    }
443
444    /// Connect this proxy to its device if that has not happened yet, see [`Self::connect`].
445    pub async fn connect_async(&self) -> Result<()> {
446        self.ensure_backend().await.map(drop)
447    }
448
449    /// Resolve this device's name.
450    #[instrument(skip(self), fields(target = %self.inner.target))]
451    pub fn name(&self) -> Result<Arc<str>> {
452        self.block_on(self.name_async())?
453    }
454
455    /// Resolve this device's name, see [`Self::name`].
456    pub async fn name_async(&self) -> Result<Arc<str>> {
457        let backend = self.ensure_backend().await?;
458        self.check_backend(backend.name().await)
459    }
460
461    /// Resolve this device's admin device name.
462    #[instrument(skip(self), fields(target = %self.inner.target))]
463    pub fn admin_dev_name(&self) -> Result<Arc<str>> {
464        self.block_on(self.admin_dev_name_async())?
465    }
466
467    /// Resolve this device's admin device name, see [`Self::admin_dev_name`].
468    pub async fn admin_dev_name_async(&self) -> Result<Arc<str>> {
469        let backend = self.ensure_backend().await?;
470        self.check_backend(backend.admin_dev_name().await)
471    }
472
473    /// Resolve this device's admin device and return it!
474    #[instrument(skip(self), fields(target = %self.inner.target))]
475    pub fn admin_dev(&self) -> Result<DevProxy> {
476        Ok(self.admin_dev_of(self.admin_dev_name()?))
477    }
478
479    /// Resolve this device's admin device and return it, see [`Self::admin_dev`].
480    pub async fn admin_dev_async(&self) -> Result<DevProxy> {
481        Ok(self.admin_dev_of(self.admin_dev_name_async().await?))
482    }
483
484    /// The proxy to the admin device of this one, from the name of it: asking the device
485    /// for that name is the only part of this that reaches it, so it is what the two
486    /// methods above do and this is everything they share.
487    fn admin_dev_of(&self, name: Arc<str>) -> DevProxy {
488
489        let backend = Arc::clone(&self.inner.backend);
490
491        DevProxy::new_from_target_with_backend(backend, match &self.inner.target {
492            ProxyTarget::DatabaseFromEnv => todo!(),
493            ProxyTarget::DatabaseAt { .. } => {
494                // Self can be a DatabaseProxy, so we use it!
495                ProxyTarget::RegularFromDatabase { 
496                    database: DatabaseProxy::with_dev(self.clone()), 
497                    name,
498                }
499            }
500            ProxyTarget::RegularFromDatabase { database, .. } => {
501                ProxyTarget::RegularFromDatabase { 
502                    database: database.clone(), 
503                    name,
504                }
505            }
506            ProxyTarget::RegularAt { host, port, .. } => {
507                ProxyTarget::RegularAt { 
508                    host: Arc::clone(host), 
509                    port: *port, 
510                    name,
511                }
512            }
513        })
514
515    }
516
517    /// Get what the device says it is: the class it is an instance of, the server running
518    /// it and where, and the versions of whatever that server is built out of.
519    ///
520    /// All of it is the server's own description of itself and none of it is asked of the
521    /// database, so it answers for a device served without one.
522    #[instrument(skip(self), fields(target = %self.inner.target))]
523    pub fn info(&self) -> Result<DevInfo> {
524        self.block_on(self.info_async())?
525    }
526
527    /// Get what the device says it is, see [`Self::info`].
528    pub async fn info_async(&self) -> Result<DevInfo> {
529        let backend = self.ensure_backend().await?;
530        self.check_backend(backend.info().await)
531    }
532
533    /// Ping this device.
534    #[instrument(skip(self), fields(target = %self.inner.target))]
535    pub fn ping(&self) -> Result<()> {
536        self.block_on(self.ping_async())?
537    }
538
539    /// Ping this device, see [`Self::ping`].
540    pub async fn ping_async(&self) -> Result<()> {
541        let backend = self.ensure_backend().await?;
542        self.check_backend(backend.ping().await)
543    }
544
545    /// Get the device state.
546    #[instrument(skip(self), fields(target = %self.inner.target))]
547    pub fn state(&self) -> Result<DevState> {
548        self.block_on(self.state_async())?
549    }
550
551    /// Get the device state, see [`Self::state`].
552    pub async fn state_async(&self) -> Result<DevState> {
553        let backend = self.ensure_backend().await?;
554        self.check_backend(backend.state().await)
555    }
556
557    /// Get the device status.
558    #[instrument(skip(self), fields(target = %self.inner.target))]
559    pub fn status(&self) -> Result<String> {
560        self.block_on(self.status_async())?
561    }
562
563    /// Get the device status, see [`Self::status`].
564    pub async fn status_async(&self) -> Result<String> {
565        let backend = self.ensure_backend().await?;
566        self.check_backend(backend.status().await)
567    }
568
569    /// Initialize the device again, executing its `Init` command.
570    pub fn init(&self) -> Result<()> {
571        self.command("Init", ())
572    }
573
574    /// Initialize the device again, see [`Self::init`].
575    pub fn init_async(&self) -> impl Future<Output = Result<()>> + Send {
576        self.command_async("Init", ())
577    }
578
579    /// Request the device black box.
580    #[instrument(skip(self), fields(target = %self.inner.target))]
581    pub fn black_box(&self, max: Option<usize>) -> Result<Vec<String>> {
582        self.block_on(self.black_box_async(max))?
583    }
584
585    /// Request the device black box, see [`Self::black_box`].
586    pub async fn black_box_async(&self, max: Option<usize>) -> Result<Vec<String>> {
587        let backend = self.ensure_backend().await?;
588        self.check_backend(backend.black_box(max).await)
589    }
590
591    /// Execute a remote command, giving back what it answered with, converted into the type
592    /// it is expected to be, see [`FromValue`].
593    ///
594    /// The value shares the octets the device answered with, so asking for a [`Value`] or
595    /// for one of the buffers it holds — a [`crate::value::Spectrum`] of a million points
596    /// above all — copies nothing, where the usual owned types are copied out of it.
597    #[instrument(skip(self, input), fields(target = %self.inner.target))]
598    pub fn command_async<I, O>(&self, name: &str, input: I) -> impl Future<Output = Result<O>> + Send
599    where
600        I: IntoValue,
601        O: FromValue,
602    {
603
604        // TODO: Support for API_CommandTimedOut
605        //   It happens when we execute a command on a server with device-level
606        //   serialization, which prevent it from executing our command because another
607        //   action is holding the lock on the device monitor thread (another long
608        //   command or attribute).
609
610        let command = Scalar::from(name);
611        let input = input.into_value();
612        async move {
613            let backend = self.ensure_backend().await?;
614            let res = backend.command(command, input, self.inner.source).await;
615            O::from_value(self.check_backend(res).map_err(command_err)?)
616        }
617
618    }
619
620    /// Execute a remote command, giving back what it answered with, see
621    /// [`Self::command_async`].
622    pub fn command<I, O>(&self, name: &str, input: I) -> Result<O>
623    where
624        I: IntoValue,
625        O: FromValue,
626    {
627        self.block_on(self.command_async(name, input))?
628    }
629
630    /// Read attributes given a specification of attributes. This specification is really
631    /// flexible and allows various signatures for the function:
632    /// 1. `read_attr<T>(&str) -> Result<AttrRead<T>>`
633    /// 2. `read_attr<T>(&[&str]) -> Result<Vec<Result<AttrRead<T>>>>`
634    /// 3. `read_attr<T>([&str; N]) -> Result<[Result<AttrRead<T>>; N]>`
635    /// 4. `read_attr<(A, B, ...)>((&str, &str, ...)) -> Result<(Result<AttrRead<A>>, Result<AttrRead<B>>, ...)>`
636    /// 5. `read_attr<T>(All) -> Result<Vec<NamedResult<AttrRead<T>>>>`
637    ///
638    /// Forms 1 to 3 and 5 convert every attribute into the same type, whereas form 4 gives
639    /// each attribute its own type. Nothing in the names constrains the specification, so
640    /// it has to come either from a turbofish, leaving the names inferred as in
641    /// `read_attr::<i16, _>("enum_scalar")`, or from the type of the binding it is assigned
642    /// to. Reading into a [`Value`] keeps whatever the device answered with, and reading
643    /// into a buffer copies nothing, see [`Self::command_async`].
644    ///
645    /// Each reading comes with the [`Result`] of that one reading, so that a per-attribute
646    /// failure is seen without the whole request failing. Note that, unlike the
647    /// many-attributes forms, the single-attribute form has no per-attribute slot in its
648    /// output and therefore returns that attribute's error directly. The fixed-size forms
649    /// 3 and 4 additionally fail with [`ErrorKind::Internal`] if the device does not answer
650    /// with exactly as many readings as were requested.
651    ///
652    /// All requested attributes are read within a single request, which matters beyond
653    /// saving round trips: if the device enforces serialization, it is held for the whole
654    /// batch and only released at the end, so the readings are consistent with each other
655    /// instead of being sampled at instants another client could have written between.
656    #[instrument(skip(self, names), fields(target = %self.inner.target))]
657    pub fn read_attr_async<Spec, Names: ToNames>(&self, names: Names) -> impl Future<Output = Result<Spec::Output>> + Send
658    where
659        Spec: ReadAttrSpec<Names>,
660    {
661        let names = names.to_names();
662        async move {
663            let backend = self.ensure_backend().await?;
664            let res = backend.read_attr(names, self.inner.source).await;
665            Spec::collect(self.check_backend(res)?)
666        }
667    }
668
669    /// Read attributes, see [`Self::read_attr_async`].
670    pub fn read_attr<Spec, Names: ToNames>(&self, names: Names) -> Result<Spec::Output>
671    where
672        Spec: ReadAttrSpec<Names>,
673    {
674        self.block_on(self.read_attr_async::<Spec, Names>(names))?
675    }
676
677    /// Write attributes given a specification of attributes and their values, giving back
678    /// the outcome of each individual write, in the order they were given. In Tango a write
679    /// only carries a value: quality and timestamp cannot be written. Like for
680    /// [`Self::read_attr`], this specification is really flexible and allows various
681    /// signatures for the function:
682    /// 1. `write_attr((&str, T)) -> Result<()>`
683    /// 2. `write_attr(Vec<(&str, T)>) -> Result<Vec<Result<()>>>`
684    /// 3. `write_attr([(&str, T); N]) -> Result<[Result<()>; N]>`
685    /// 4. `write_attr(((&str, A), (&str, B), ...)) -> Result<(Result<()>, Result<()>, ...)>`
686    ///
687    /// Each written value only needs to implement [`IntoValue`], so unlike for
688    /// [`Self::read_attr`] the value types are inferred from the specification and never
689    /// have to be named. Note that, unlike the many-attributes forms, the single-attribute
690    /// form has no per-attribute slot in its output and therefore returns that attribute's
691    /// error directly. The fixed-size forms 3 and 4 fail with [`ErrorKind::Internal`] if
692    /// the device does not answer for exactly as many attributes as were written.
693    #[instrument(skip(self, spec), fields(target = %self.inner.target))]
694    pub fn write_attr_async<'a, Spec>(&self, spec: Spec) -> impl Future<Output = Result<Spec::Output>> + Send
695    where
696        Spec: WriteAttrSpec<'a>,
697    {
698
699        let values = spec.into_values();
700
701        async move {
702
703            let backend = self.ensure_backend().await?;
704            let res = backend.write_attr(values).await;
705
706            // A refused write is given the kind that fits it rather than the reason code
707            // the device raised with, the same way the request failing as a whole is.
708            let outcomes = self.check_backend(res)?.into_iter()
709                .map(|res| res.map_err(write_attr_err))
710                .collect();
711
712            Spec::collect(outcomes)
713
714        }
715
716    }
717
718    /// Write attributes, see [`Self::write_attr_async`].
719    pub fn write_attr<'a, Spec>(&self, spec: Spec) -> Result<Spec::Output>
720    where
721        Spec: WriteAttrSpec<'a>,
722    {
723        self.block_on(self.write_attr_async(spec))?
724    }
725
726    /// Write attributes and read them back, given the same flexible specification as
727    /// [`Self::write_attr`], but returning the read-back values instead of unit results.
728    /// Each value is converted back into the very type that was written:
729    /// 1. `write_read_attr((&str, T)) -> Result<AttrRead<T>>`
730    /// 2. `write_read_attr(Vec<(&str, T)>) -> Result<Vec<Result<AttrRead<T>>>>`
731    /// 3. `write_read_attr([(&str, T); N]) -> Result<[Result<AttrRead<T>>; N]>`
732    /// 4. `write_read_attr(((&str, A), (&str, B), ...)) -> Result<(Result<AttrRead<A>>, Result<AttrRead<B>>, ...)>`
733    ///
734    /// The read is done by the server right after the write, so this saves a round trip
735    /// compared to a [`Self::write_attr`] followed by a [`Self::read_attr`], and no other
736    /// request can interleave between the two when the device enforces serialization.
737    ///
738    /// Because the read-back is converted back into the written type, each value type must
739    /// also implement [`FromValue`] here, whereas [`Self::write_attr`] only requires
740    /// [`IntoValue`].
741    #[instrument(skip(self, spec), fields(target = %self.inner.target))]
742    pub fn write_read_attr_async<'a, Spec>(&self, spec: Spec) -> impl Future<Output = Result<<Spec::ReadSpec as ReadAttrSpec<Spec::ReadNames>>::Output>> + Send
743    where
744        Spec: WriteAttrSpec<'a>,
745        Spec::ReadSpec: ReadAttrSpec<Spec::ReadNames>,
746    {
747        let values = spec.into_values();
748        async move {
749            let backend = self.ensure_backend().await?;
750            let res = backend.write_read_attr(values).await;
751            Spec::ReadSpec::collect(self.check_backend(res)?)
752        }
753    }
754
755    /// Write attributes and read them back, see [`Self::write_read_attr_async`].
756    pub fn write_read_attr<'a, Spec>(&self, spec: Spec) -> Result<<Spec::ReadSpec as ReadAttrSpec<Spec::ReadNames>>::Output>
757    where
758        Spec: WriteAttrSpec<'a>,
759        Spec::ReadSpec: ReadAttrSpec<Spec::ReadNames>,
760    {
761        self.block_on(self.write_read_attr_async(spec))?
762    }
763
764    /// Get the static information of commands, given the same flexible specification of
765    /// names as [`Self::read_attr`] takes:
766    /// 1. `command_info(&str) -> Result<CommandInfo>`
767    /// 2. `command_info(&[&str]) -> Result<Vec<Result<CommandInfo>>>`
768    /// 3. `command_info([&str; N]) -> Result<[Result<CommandInfo>; N]>`
769    /// 4. `command_info(All) -> Result<Vec<NamedResult<CommandInfo>>>`
770    ///
771    /// Every command comes with the [`Result`] of that one command, an unknown command name
772    /// and a data type that no [`CommandDataKind`] has a variant for being the two the
773    /// device answers with.
774    ///
775    /// Note that, unlike the attributes, the Tango interface has no operation taking a list
776    /// of command names, so asking for several of them costs one request each, where [`All`]
777    /// only costs one for the whole listing.
778    #[instrument(skip(self, spec), fields(target = %self.inner.target))]
779    pub fn command_info_async<Spec: ToNamesSpec<CommandInfo>>(&self, spec: Spec) -> impl Future<Output = Result<Spec::Output>> + Send {
780        let names = spec.to_names();
781        async move {
782            let backend = self.ensure_backend().await?;
783            let res = backend.command_info(names).await;
784            Spec::collect(self.check_backend(res)?)
785        }
786    }
787
788    /// Get the static information of commands, see [`Self::command_info_async`].
789    pub fn command_info<Spec: ToNamesSpec<CommandInfo>>(&self, spec: Spec) -> Result<Spec::Output> {
790        self.block_on(self.command_info_async(spec))?
791    }
792
793    /// Get the static information of attributes, their runtime-modifiable configuration
794    /// included, given the same flexible specification of names as [`Self::read_attr`]
795    /// takes:
796    /// 1. `attr_info(&str) -> Result<AttrInfo>`
797    /// 2. `attr_info(&[&str]) -> Result<Vec<Result<AttrInfo>>>`
798    /// 3. `attr_info([&str; N]) -> Result<[Result<AttrInfo>; N]>`
799    /// 4. `attr_info(All) -> Result<Vec<NamedResult<AttrInfo>>>`
800    ///
801    /// Every attribute comes with the [`Result`] of that one attribute, a data type that no
802    /// [`AttrDataKind`] has a variant for being what the device answers with. Unlike the
803    /// commands, an unknown attribute name fails the whole request, all of them travelling
804    /// in a single one.
805    #[instrument(skip(self, spec), fields(target = %self.inner.target))]
806    pub fn attr_info_async<Spec: ToNamesSpec<AttrInfo>>(&self, spec: Spec) -> impl Future<Output = Result<Spec::Output>> + Send {
807        let names = spec.to_names();
808        async move {
809            let backend = self.ensure_backend().await?;
810            let res = backend.attr_info(names).await;
811            Spec::collect(self.check_backend(res)?)
812        }
813    }
814
815    /// Get the static information of attributes, see [`Self::attr_info_async`].
816    pub fn attr_info<Spec: ToNamesSpec<AttrInfo>>(&self, spec: Spec) -> Result<Spec::Output> {
817        self.block_on(self.attr_info_async(spec))?
818    }
819
820    /// Change the configuration of the given attributes, giving back the outcome of each
821    /// individual change, in the order they were given.
822    ///
823    /// Only the configuration is writable, which is the part of an [`AttrInfo`] that a
824    /// client is allowed to set: what an attribute *is* — its mode, its data kind and its
825    /// format — is what its definition says and is never written from the outside.
826    ///
827    /// The whole configuration of an attribute goes out every time, so changing one
828    /// property of it is reading the configuration with [`Self::attr_info`] and writing
829    /// back what was read with that one property changed, which is what the protocol
830    /// carries.
831    ///
832    /// A field with no value brings it back to what the attribute inherits from its class,
833    /// if anything.
834    #[instrument(skip(self, values), fields(target = %self.inner.target))]
835    pub async fn set_attr_config_async(&self, values: &[(&str, AttrConfig)]) -> Result<Vec<Result<()>>> {
836        let configs = values.iter()
837            .map(|(name, config)| Named::new(Scalar::from(*name), config.clone()))
838            .collect();
839        let backend = self.ensure_backend().await?;
840        let res = backend.set_attr_config(configs).await;
841        self.check_backend(res).map_err(write_attr_err)
842    }
843
844    /// Change the configuration of the given attributes, see
845    /// [`Self::set_attr_config_async`].
846    pub fn set_attr_config(&self, values: &[(&str, AttrConfig)]) -> Result<Vec<Result<()>>> {
847        self.block_on(self.set_attr_config_async(values))?
848    }
849
850    /// The recorded history of a command, which is what the polling of the device left
851    /// behind, oldest entry first and at most `max` of them, every entry being the time the
852    /// run was recorded at and what the command answered then, converted into the type it
853    /// is expected to be, a run that failed carrying the failure it failed with.
854    ///
855    /// A device that is not polled has no history to give, which is a failure and not an
856    /// empty history: nothing was recorded because nothing is recording.
857    #[instrument(skip(self), fields(target = %self.inner.target))]
858    pub async fn command_history_async<T: FromValue>(&self, name: &str, max: usize) -> Result<Vec<(SystemTime, Result<T>)>> {
859        let backend = self.ensure_backend().await?;
860        let res = backend.command_history(name, max).await;
861        Ok(self.check_backend(res).map_err(command_err)?.into_iter()
862            .map(|(time, value)| (time, value.and_then(T::from_value)))
863            .collect())
864    }
865
866    /// The recorded history of a command, see [`Self::command_history_async`].
867    pub fn command_history<T: FromValue>(&self, name: &str, max: usize) -> Result<Vec<(SystemTime, Result<T>)>> {
868        self.block_on(self.command_history_async(name, max))?
869    }
870
871    /// The recorded history of an attribute, see [`Self::command_history_async`], the
872    /// timestamp of every entry being the one the reading itself carries.
873    #[instrument(skip(self), fields(target = %self.inner.target))]
874    pub async fn attr_history_async<T: FromValue>(&self, name: &str, max: usize) -> Result<Vec<Result<AttrRead<T>>>> {
875        let backend = self.ensure_backend().await?;
876        let res = backend.attr_history(name, max).await;
877        Ok(self.check_backend(res)?.into_iter()
878            .map(|read| read.and_then(AttrRead::parse))
879            .collect())
880    }
881
882    /// The recorded history of an attribute, see [`Self::attr_history_async`].
883    pub fn attr_history<T: FromValue>(&self, name: &str, max: usize) -> Result<Vec<Result<AttrRead<T>>>> {
884        self.block_on(self.attr_history_async(name, max))?
885    }
886
887    // The properties of a device are the database's and not the device's, so everything
888    // below asks the device for its name and then the database for what it holds of it,
889    // see the very same methods on [`DatabaseProxy`].
890
891    /// The names of the properties of this device that match the given filter.
892    pub async fn list_prop_async(&self, filter: &str) -> Result<Spectrum<str>> {
893        let dev_name = self.name_async().await?;
894        self.database()?.list_dev_prop_async(&dev_name, filter).await
895    }
896
897    /// The names of the properties of this device, see [`Self::list_prop_async`].
898    pub fn list_prop(&self, filter: &str) -> Result<Spectrum<str>> {
899        self.block_on(self.list_prop_async(filter))?
900    }
901
902    /// The properties of this device, parsed into the shape the given names ask for. Like
903    /// for [`Self::read_attr`], this specification is really flexible and allows various
904    /// signatures for the function:
905    /// 1. `get_prop<T>(&str) -> Result<T>`
906    /// 2. `get_prop<T>(&[&str]) -> Result<Vec<Result<T>>>`
907    /// 3. `get_prop<T>([&str; N]) -> Result<[Result<T>; N]>`
908    /// 4. `get_prop<(A, B, ...)>((&str, &str, ...)) -> Result<(Result<A>, Result<B>, ...)>`
909    /// 5. `get_prop<Spectrum<str>>(All) -> Result<Vec<Named<Spectrum<str>>>>`
910    ///
911    /// See [`DatabaseProxy::get_dev_prop_async`] for what the values may be parsed into
912    /// and what a property the database holds nothing for gives.
913    pub fn get_prop_async<Spec, Names: ToNames>(&self, names: Names) -> impl Future<Output = Result<Spec::Output>> + Send
914    where
915        Spec: GetPropSpec<Names>,
916    {
917        // The name of the device, which goes first, is only known once it is asked for, so
918        // the names are taken out as a buffer of their own first.
919        let names = names.to_names();
920        async move {
921            let dev_name = self.name_async().await?;
922            let params = names.map(|names| prop_params(&dev_name, names.iter()));
923            let mut reply = self.database()?.get_raw_prop_async(PropCommands::DEV, &dev_name, params).await?;
924            Spec::collect(&mut reply)
925        }
926    }
927
928    /// The properties of this device, see [`Self::get_prop_async`].
929    pub fn get_prop<Spec, Names: ToNames>(&self, names: Names) -> Result<Spec::Output>
930    where
931        Spec: GetPropSpec<Names>,
932    {
933        self.block_on(self.get_prop_async::<Spec, Names>(names))?
934    }
935
936    /// Write the given properties of this device, given as pairs of a name and a value,
937    /// which allows various signatures for the function:
938    /// 1. `set_prop((&str, T)) -> Result<()>`
939    /// 2. `set_prop([(&str, T); N]) -> Result<()>`
940    /// 3. `set_prop(Vec<(&str, T)>) -> Result<()>`
941    /// 4. `set_prop(((&str, A), (&str, B), ...)) -> Result<()>`
942    ///
943    /// See [`DatabaseProxy::set_dev_prop_async`] for what the values may be.
944    pub fn set_prop_async<'a, Spec>(&self, spec: Spec) -> impl Future<Output = Result<()>> + Send
945    where
946        Spec: SetPropSpec<'a>,
947    {
948        let params = set_prop_params(spec);
949        async move {
950            let dev_name = self.name_async().await?;
951            self.database()?.prop_command_async("DbPutDeviceProperty", prop_params(&dev_name, params.iter().map(|param| &**param))).await
952        }
953    }
954
955    /// Write the given properties of this device, see [`Self::set_prop_async`].
956    pub fn set_prop<'a, Spec>(&self, spec: Spec) -> Result<()>
957    where
958        Spec: SetPropSpec<'a>,
959    {
960        self.block_on(self.set_prop_async(spec))?
961    }
962
963    /// Delete the given properties of this device, which allows various signatures for the
964    /// function:
965    /// 1. `del_prop(&str) -> Result<()>`
966    /// 2. `del_prop(&[&str]) -> Result<()>`
967    /// 3. `del_prop([&str; N]) -> Result<()>`
968    /// 4. `del_prop((&str, &str, ...)) -> Result<()>`
969    ///
970    /// See [`DatabaseProxy::del_dev_prop_async`].
971    pub fn del_prop_async<Names: ToNamesNotAll>(&self, names: Names) -> impl Future<Output = Result<()>> + Send {
972        let names = names.to_names_not_all();
973        async move {
974            let dev_name = self.name_async().await?;
975            self.database()?.prop_command_async("DbDeleteDeviceProperty", prop_params(&dev_name, names.iter())).await
976        }
977    }
978
979    /// Delete the given properties of this device, see [`Self::del_prop_async`].
980    pub fn del_prop<Names: ToNamesNotAll>(&self, names: Names) -> Result<()> {
981        self.block_on(self.del_prop_async(names))?
982    }
983
984    /// Subscribe to the readings of an attribute, of one of the kinds a device pushes them
985    /// under, the channel giving the latest of them, see [`DevChannel`].
986    ///
987    /// Nothing is subscribed until the channel is polled, or its subscription ensured, see
988    /// [`DevChannel::ensure_subscribed_async`]. There is no initial value: the first event
989    /// is the next one the device pushes, so read the attribute once subscribed to know
990    /// where it stands.
991    pub fn subscribe_attr_value<T: FromValue>(&self, name: &str, event: AttrValueEvent) -> DevChannel<AttrRead<T>> {
992        DevChannel::new(self.clone(), name, ChannelKind::Value(event), ChannelEvents::poll_value)
993    }
994
995    /// Subscribe to an attribute being announced as ready to be read, which carries nothing
996    /// of the attribute: reading it is the subscriber's to do. See
997    /// [`Self::subscribe_attr_value`].
998    pub fn subscribe_attr_ready(&self, name: &str) -> DevChannel<()> {
999        DevChannel::new(self.clone(), name, ChannelKind::Ready, ChannelEvents::poll_ready)
1000    }
1001
1002    /// Subscribe to the configuration of an attribute changing, every event carrying the
1003    /// configuration as it stands after the change. See [`Self::subscribe_attr_value`].
1004    pub fn subscribe_attr_conf(&self, name: &str) -> DevChannel<AttrInfo> {
1005        DevChannel::new(self.clone(), name, ChannelKind::Conf, ChannelEvents::poll_conf)
1006    }
1007
1008    // pub async fn get_attr_properties<T>(&self, name: &str) -> Result<AttrProperties<T>, DevError> {
1009    //     todo!()
1010    // }
1011
1012    // pub async fn set_attr_properties<T>(&self, name: &str, properties: AttrProperties<T>) -> Result<(), DevError> {
1013    //     todo!()
1014    // }
1015
1016}
1017
1018/// This clone implementation might block if the device proxy is being initialized with a
1019/// backend at the same time, but it should not be an issue and with eventually timeout
1020/// if necessary.
1021impl Clone for DevProxy {
1022    fn clone(&self) -> Self {
1023        Self {
1024            inner: Box::new(ProxyInner {
1025                backend: self.inner.backend.clone(),
1026                target: self.inner.target.clone(),
1027                source: self.inner.source,
1028                timeout: self.inner.timeout,
1029            }),
1030            state: self.state.try_read().ok()
1031                .map(|guard| RwLock::new((*guard).clone()))
1032                .unwrap_or_else(|| RwLock::new(ProxyState {
1033                    backend: None,
1034                    database_host_and_port: None,
1035                })),
1036        }
1037    }
1038}
1039
1040impl PartialEq for DevProxy {
1041    #[inline]
1042    fn eq(&self, other: &Self) -> bool {
1043        Arc::ptr_eq(&self.inner.backend, &other.inner.backend) && self.inner.target == other.inner.target
1044    }
1045}
1046
1047impl Eq for DevProxy { }
1048
1049impl Hash for DevProxy {
1050    #[inline]
1051    fn hash<H: Hasher>(&self, state: &mut H) {
1052        Arc::as_ptr(&self.inner.backend).hash(state);
1053        self.inner.target.hash(state);
1054    }
1055}
1056
1057/// The struct is internal so we just impl Display on it, in order to properly display it
1058/// in the tracing spans!
1059impl fmt::Display for ProxyTarget {
1060    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1061        match self {
1062            ProxyTarget::DatabaseFromEnv => 
1063                write!(f, "db"),
1064            ProxyTarget::DatabaseAt { host, port } => 
1065                write!(f, "db@{host}:{port}"),
1066            ProxyTarget::RegularFromDatabase { name, .. } => 
1067                write!(f, "{name}"),
1068            ProxyTarget::RegularAt { host, port, name } => 
1069                write!(f, "{name}@{host}:{port}"),
1070        }
1071    }
1072}
1073
1074// =========================== //
1075//          To names           //
1076// =========================== //
1077
1078/// Supporting trait for being generic over the different types that can be interpreted 
1079/// as names, either single or many names.
1080///
1081/// The names are given to a backend as one buffer of strings, which a served device shares
1082/// in what it answers with, and which a buffer of names already given passes through
1083/// untouched: names read back from a device, or listed by the database, are given again
1084/// without being copied.
1085///
1086/// **Supporting trait**: it is only there to make this crate's API easier to use, it is
1087/// implemented for everything that API accepts and is not one to implement anywhere else.
1088pub trait ToNames: Sized {
1089
1090    /// The names, in the order they were given, absent to target **all** elements, borrowed
1091    /// where they are: what a request copies into its own parameters, once, rather than
1092    /// first into a buffer of their own, see [`Spectrum::from_strs`].
1093    fn iter_names(&self) -> Option<impl Iterator<Item = &str>>;
1094
1095    /// The names as one buffer, see [`Self::iter_names`].
1096    #[inline]
1097    fn to_names(self) -> Option<Spectrum<str>> {
1098        self.iter_names().map(names_buf)
1099    }
1100
1101}
1102
1103/// The names as one buffer, copied out of where they are.
1104fn names_buf<'a>(names: impl Iterator<Item = &'a str>) -> Spectrum<str> {
1105    Spectrum::from_strs(names).expect("names of more than 4 GiB")
1106}
1107
1108/// Same as [`ToNames`] but this marker ensures that no None will be returned by to_names.
1109///
1110/// **Supporting trait**: it is only there to make this crate's API easier to use, it is
1111/// implemented for everything that API accepts and is not one to implement anywhere else.
1112pub trait ToNamesNotAll: ToNames {
1113
1114    /// Utility function to ensure no `None` could be returned for the names.
1115    #[inline]
1116    fn iter_names_not_all(&self) -> impl Iterator<Item = &str> {
1117        self.iter_names().expect("should not return the 'all' marker")
1118    }
1119
1120    /// Utility function to ensure no `None` could be returned for the names.
1121    #[inline]
1122    fn to_names_not_all(self) -> Spectrum<str> {
1123        self.to_names().expect("should not return the 'all' marker")
1124    }
1125
1126}
1127
1128/// Something along with the name it is of, the name sharing the octets it was decoded out
1129/// of like any other string.
1130///
1131/// This is what a request answering for several names gives one of per name: the result
1132/// of that one name, which is not the one of the request. The request failing fails it as
1133/// a whole, while an entry failing is the device failing for that one name, which the other
1134/// entries are unaffected by.
1135#[derive(Debug, Clone, PartialEq)]
1136pub struct Named<T> {
1137    /// The name.
1138    pub name: Scalar<str>,
1139    /// What is of that name.
1140    pub value: T,
1141}
1142
1143impl<T> Named<T> {
1144
1145    #[inline]
1146    pub fn new(name: Scalar<str>, value: T) -> Self {
1147        Self { name, value }
1148    }
1149
1150    /// The same name along with what that function makes of its value.
1151    #[inline]
1152    pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Named<U> {
1153        Named { name: self.name, value: f(self.value) }
1154    }
1155
1156}
1157
1158/// What a request answering for several names gives one of per name, see [`Named`].
1159pub type NamedResult<T> = Named<Result<T>>;
1160
1161/// A marker struct for specifying names for various functions that are using [`ToNames`]
1162/// to specify to select **all** names available on the device.
1163pub struct All;
1164impl ToNames for All {
1165    #[inline]
1166    fn iter_names(&self) -> Option<impl Iterator<Item = &str>> {
1167        None::<std::iter::Empty<&str>>
1168    }
1169}
1170
1171impl ToNames for &str {
1172    #[inline]
1173    fn iter_names(&self) -> Option<impl Iterator<Item = &str>> {
1174        Some(std::iter::once(*self))
1175    }
1176}
1177impl ToNamesNotAll for &str { }
1178
1179impl ToNames for &[&str] {
1180    #[inline]
1181    fn iter_names(&self) -> Option<impl Iterator<Item = &str>> {
1182        Some(self.iter().copied())
1183    }
1184}
1185impl ToNamesNotAll for &[&str] { }
1186
1187impl<const N: usize> ToNames for [&str; N] {
1188    #[inline]
1189    fn iter_names(&self) -> Option<impl Iterator<Item = &str>> {
1190        Some(self.iter().copied())
1191    }
1192}
1193impl<const N: usize> ToNamesNotAll for [&str; N] { }
1194
1195impl ToNames for Spectrum<str> {
1196    #[inline]
1197    fn iter_names(&self) -> Option<impl Iterator<Item = &str>> {
1198        Some(self.iter())
1199    }
1200    #[inline]
1201    fn to_names(self) -> Option<Spectrum<str>> {
1202        Some(self)
1203    }
1204}
1205impl ToNamesNotAll for Spectrum<str> { }
1206
1207impl ToNames for &Spectrum<str> {
1208    #[inline]
1209    fn iter_names(&self) -> Option<impl Iterator<Item = &str>> {
1210        Some(self.iter())
1211    }
1212    #[inline]
1213    fn to_names(self) -> Option<Spectrum<str>> {
1214        Some(self.clone())
1215    }
1216}
1217impl ToNamesNotAll for &Spectrum<str> { }
1218
1219macro_rules! impl_to_names_tuple {
1220    ( @name: $comp:ident ) => { &str };
1221    ( @one: $comp:ident ) => { 1 };
1222    ( $( $comp:ident )* ) => {
1223        #[allow(unused_variables)]
1224        impl ToNames for ( $(impl_to_names_tuple!(@name: $comp),)* ) {
1225            #[inline]
1226            fn iter_names(&self) -> Option<impl Iterator<Item = &str>> {
1227                let ( $($comp,)* ) = *self;
1228                Some(<[&str; 0 $( + impl_to_names_tuple!(@one: $comp) )*]>::into_iter([ $($comp,)* ]))
1229            }
1230        }
1231        impl ToNamesNotAll for ( $(impl_to_names_tuple!(@name: $comp),)* ) { }
1232    };
1233}
1234
1235impl_to_names_tuple!();
1236impl_to_names_tuple!(a);
1237impl_to_names_tuple!(a b);
1238impl_to_names_tuple!(a b c);
1239impl_to_names_tuple!(a b c d);
1240impl_to_names_tuple!(a b c d e);
1241impl_to_names_tuple!(a b c d e f);
1242
1243/// Generic specification type used for command and attribute info, as there is no 
1244/// special processing to do on the resulted value! This is an extension to the ToNames,
1245/// because this spec's output only depends on the actual type of the names we give.
1246///
1247/// **Supporting trait**: it is only there to make this crate's API easier to use, it is
1248/// implemented for everything that API accepts and is not one to implement anywhere else.
1249pub trait ToNamesSpec<T>: ToNames {
1250
1251    /// The final type of the output.
1252    type Output;
1253
1254    /// Build the output out of the entries the device answered with, one per name.
1255    ///
1256    /// The shape of the output is what the names that were given say it is, which is what
1257    /// this is implemented on.
1258    fn collect(entries: Vec<NamedResult<T>>) -> Result<Self::Output>;
1259
1260}
1261
1262/// One name, one entry: that entry *is* the output, and its failure is the output's own
1263/// since there is no slot of its own to carry it in.
1264impl<T> ToNamesSpec<T> for &str {
1265
1266    type Output = T;
1267
1268    fn collect(entries: Vec<NamedResult<T>>) -> Result<Self::Output> {
1269        match entries.into_iter().next() {
1270            Some(entry) => entry.value,
1271            None => Err(unexpected_len_err(1)),
1272        }
1273    }
1274
1275}
1276
1277impl<T> ToNamesSpec<T> for &[&str] {
1278
1279    type Output = Vec<Result<T>>;
1280
1281    fn collect(entries: Vec<NamedResult<T>>) -> Result<Self::Output> {
1282        Ok(entries.into_iter().map(|entry| entry.value).collect())
1283    }
1284
1285}
1286
1287impl<T> ToNamesSpec<T> for Spectrum<str> {
1288
1289    type Output = Vec<Result<T>>;
1290
1291    fn collect(entries: Vec<NamedResult<T>>) -> Result<Self::Output> {
1292        <&[&str] as ToNamesSpec<T>>::collect(entries)
1293    }
1294
1295}
1296
1297impl<T> ToNamesSpec<T> for &Spectrum<str> {
1298
1299    type Output = Vec<Result<T>>;
1300
1301    fn collect(entries: Vec<NamedResult<T>>) -> Result<Self::Output> {
1302        <&[&str] as ToNamesSpec<T>>::collect(entries)
1303    }
1304
1305}
1306
1307impl<T, const N: usize> ToNamesSpec<T> for [&str; N] {
1308
1309    type Output = [Result<T>; N];
1310
1311    fn collect(entries: Vec<NamedResult<T>>) -> Result<Self::Output> {
1312        take_array(entries.into_iter().map(|entry| entry.value))
1313    }
1314
1315}
1316
1317impl<T> ToNamesSpec<T> for All {
1318
1319    // Nothing was named here, so every entry carries its own name and this is the one
1320    // form whose output has room for it.
1321    type Output = Vec<NamedResult<T>>;
1322
1323    fn collect(entries: Vec<NamedResult<T>>) -> Result<Self::Output> {
1324        Ok(entries)
1325    }
1326
1327}
1328
1329/// The entries of an output of a fixed shape, one per slot and in order: a device that
1330/// answers with another number of them broke what the protocol says of it, which a last
1331/// entry being there behind the slots tells as well as one of them missing.
1332pub(crate) fn take_array<T, const N: usize>(mut entries: impl Iterator<Item = T>) -> Result<[T; N]> {
1333    let mut slots = [const { None }; N];
1334    for slot in &mut slots {
1335        *slot = Some(entries.next().ok_or_else(|| unexpected_len_err(N))?);
1336    }
1337    if entries.next().is_some() {
1338        return Err(unexpected_len_err(N));
1339    }
1340    Ok(slots.map(|slot| slot.expect("every slot is filled")))
1341}
1342
1343macro_rules! impl_to_names_spec_tuple {
1344    ( @one: $index:tt ) => { 1 };
1345    ( @name: $index:tt ) => { &str };
1346    ( @t: $index:tt ) => { T };
1347    ( @next: $index:tt, $entries:ident ) => { $entries.next().ok_or_else(|| unexpected_len_err(LEN))?.value };
1348    ( $( $index:tt )* ) => {
1349
1350        impl<T> ToNamesSpec<T> for ( $( impl_to_names_spec_tuple!(@name: $index), )* ) {
1351
1352            type Output = ( $( Result< impl_to_names_spec_tuple!(@t: $index) >,)* );
1353
1354            fn collect(entries: Vec<NamedResult<T>>) -> Result<Self::Output> {
1355                const LEN: usize = 0 $( + impl_to_names_spec_tuple!(@one: $index) )*;
1356                // The entries are in the order the names were given, which is the order the
1357                // components of a tuple are built in.
1358                let mut entries = entries.into_iter();
1359                let output = ( $( impl_to_names_spec_tuple!(@next: $index, entries), )* );
1360                if entries.next().is_some() {
1361                    return Err(unexpected_len_err(LEN));
1362                }
1363                Ok(output)
1364            }
1365
1366        }
1367
1368    };
1369}
1370
1371impl_to_names_spec_tuple!(0);
1372impl_to_names_spec_tuple!(0 1);
1373impl_to_names_spec_tuple!(0 1 2);
1374impl_to_names_spec_tuple!(0 1 2 3);
1375impl_to_names_spec_tuple!(0 1 2 3 4);
1376impl_to_names_spec_tuple!(0 1 2 3 4 5);
1377
1378// =========================== //
1379//       Read attributes       //
1380// =========================== //
1381
1382/// A trait for attribute specifiers, which allows a great flexibility in how 
1383/// [`DevProxy::read_attr`] works.
1384///
1385/// **Supporting trait**: it is only there to make this crate's API easier to use, it is
1386/// implemented for everything that API accepts and is not one to implement anywhere else.
1387pub trait ReadAttrSpec<Names> {
1388
1389    /// The final type of the output.
1390    type Output;
1391
1392    /// Build the output out of the readings, one per attribute.
1393    ///
1394    /// The shape of the output is what the names that were given say it is, and what every
1395    /// reading is converted into is what this is implemented on.
1396    fn collect(reads: Vec<NamedResult<AttrRead<Value>>>) -> Result<Self::Output>;
1397
1398}
1399
1400impl<'name, T: FromValue> ReadAttrSpec<&'name str> for T {
1401
1402    type Output = AttrRead<T>;
1403
1404    fn collect(reads: Vec<NamedResult<AttrRead<Value>>>) -> Result<Self::Output> {
1405        match reads.into_iter().next() {
1406            Some(entry) => entry.value?.parse(),
1407            None => Err(unexpected_len_err(1)),
1408        }
1409    }
1410
1411}
1412
1413impl<'name, T: FromValue> ReadAttrSpec<&'_ [&'name str]> for T {
1414
1415    type Output = Vec<Result<AttrRead<T>>>;
1416
1417    fn collect(reads: Vec<NamedResult<AttrRead<Value>>>) -> Result<Self::Output> {
1418        Ok(reads.into_iter().map(|entry| entry.value.and_then(AttrRead::parse)).collect())
1419    }
1420
1421}
1422
1423impl<T: FromValue> ReadAttrSpec<Spectrum<str>> for T {
1424
1425    type Output = Vec<Result<AttrRead<T>>>;
1426
1427    fn collect(reads: Vec<NamedResult<AttrRead<Value>>>) -> Result<Self::Output> {
1428        <T as ReadAttrSpec<&[&str]>>::collect(reads)
1429    }
1430
1431}
1432
1433impl<T: FromValue> ReadAttrSpec<&Spectrum<str>> for T {
1434
1435    type Output = Vec<Result<AttrRead<T>>>;
1436
1437    fn collect(reads: Vec<NamedResult<AttrRead<Value>>>) -> Result<Self::Output> {
1438        <T as ReadAttrSpec<&[&str]>>::collect(reads)
1439    }
1440
1441}
1442
1443impl<'name, T: FromValue, const N: usize> ReadAttrSpec<[&'name str; N]> for T {
1444
1445    type Output = [Result<AttrRead<T>>; N];
1446
1447    fn collect(reads: Vec<NamedResult<AttrRead<Value>>>) -> Result<Self::Output> {
1448        take_array(reads.into_iter().map(|entry| entry.value.and_then(AttrRead::parse)))
1449    }
1450
1451}
1452
1453impl<T: FromValue> ReadAttrSpec<All> for T {
1454
1455    // Nothing was named here, so every reading carries the name of its attribute.
1456    type Output = Vec<NamedResult<AttrRead<T>>>;
1457
1458    fn collect(reads: Vec<NamedResult<AttrRead<Value>>>) -> Result<Self::Output> {
1459        Ok(reads.into_iter().map(|entry| entry.map(|read| read.and_then(AttrRead::parse))).collect())
1460    }
1461
1462}
1463
1464macro_rules! impl_read_attr_spec_tuple {
1465    ( @one: $comp:ident ) => { 1 };
1466    ( @name: $comp:ident ) => { &'name str };
1467    ( $( $comp:ident )* ) => {
1468
1469        impl<'name, $($comp,)* > ReadAttrSpec<( $( impl_read_attr_spec_tuple!(@name: $comp), )* )> for ( $($comp,)* )
1470        where
1471            $( $comp: FromValue, )*
1472        {
1473
1474            type Output = ( $( Result<AttrRead<$comp>>,)* );
1475
1476            fn collect(reads: Vec<NamedResult<AttrRead<Value>>>) -> Result<Self::Output> {
1477                const LEN: usize = 0 $( + impl_read_attr_spec_tuple!(@one: $comp) )*;
1478                // The readings are in the order the names were given, which is the order
1479                // the components of a tuple are built in, and every one of them is
1480                // converted into the type of its own component.
1481                let mut reads = reads.into_iter();
1482                let output = ( $( reads.next().ok_or_else(|| unexpected_len_err(LEN))?.value.and_then(AttrRead::parse::<$comp>), )* );
1483                if reads.next().is_some() {
1484                    return Err(unexpected_len_err(LEN));
1485                }
1486                Ok(output)
1487            }
1488
1489        }
1490
1491    };
1492}
1493
1494impl_read_attr_spec_tuple!(A);
1495impl_read_attr_spec_tuple!(A B);
1496impl_read_attr_spec_tuple!(A B C);
1497impl_read_attr_spec_tuple!(A B C D);
1498impl_read_attr_spec_tuple!(A B C D E);
1499impl_read_attr_spec_tuple!(A B C D E F);
1500
1501// =========================== //
1502//      Write attributes       //
1503// =========================== //
1504
1505/// An abstract specification of single to many AttrWrite-like, which is used by the
1506/// [`DevProxy::write_attr`] in order to be very flexible.
1507///
1508/// **Supporting trait**: it is only there to make this crate's API easier to use, it is
1509/// implemented for everything that API accepts and is not one to implement anywhere else.
1510pub trait WriteAttrSpec<'a>: Sized {
1511
1512    /// Make this write specification into the values it represents, each with the name of
1513    /// its attribute.
1514    fn into_values(self) -> Vec<Named<Value>>;
1515
1516    /// The final type of the output.
1517    type Output;
1518
1519    /// Build the output out of the outcomes of the write, which come in the order the
1520    /// values were given: a write answers one outcome per value and names nothing back,
1521    /// see [`DevProxy::write_attr_async`].
1522    fn collect(writes: Vec<Result<()>>) -> Result<Self::Output>;
1523
1524    /// Names for the read specification type.
1525    type ReadNames;
1526    /// The read specification type, for when using write_read_attr.
1527    type ReadSpec;
1528
1529}
1530
1531/// For a singe attribute.
1532impl<'a, T: IntoValue> WriteAttrSpec<'a> for (&'a str, T) {
1533
1534    #[inline]
1535    fn into_values(self) -> Vec<Named<Value>> {
1536        vec![Named::new(Scalar::from(self.0), self.1.into_value())]
1537    }
1538
1539    type Output = ();
1540
1541    fn collect(writes: Vec<Result<()>>) -> Result<Self::Output> {
1542        match writes.into_iter().next() {
1543            Some(res) => res,
1544            None => Err(unexpected_len_err(1)),
1545        }
1546    }
1547
1548    type ReadNames = &'a str;
1549    type ReadSpec = T;
1550
1551}
1552
1553/// For a array of attributes.
1554impl<'a, T: IntoValue, const N: usize> WriteAttrSpec<'a> for [(&'a str, T); N] {
1555
1556    #[inline]
1557    fn into_values(self) -> Vec<Named<Value>> {
1558        named_values(self.into_iter().map(|(name, value)| (name, value.into_value())).collect())
1559    }
1560
1561    type Output = [Result<()>; N];
1562
1563    fn collect(writes: Vec<Result<()>>) -> Result<Self::Output> {
1564        take_array(writes.into_iter())
1565    }
1566
1567    type ReadNames = [&'a str; N];
1568    type ReadSpec = T;
1569
1570}
1571
1572/// For a vector of attributes.
1573impl<'a, T: IntoValue> WriteAttrSpec<'a> for Vec<(&'a str, T)> {
1574
1575    #[inline]
1576    fn into_values(self) -> Vec<Named<Value>> {
1577        named_values(self.into_iter().map(|(name, value)| (name, value.into_value())).collect())
1578    }
1579
1580    type Output = Vec<Result<()>>;
1581
1582    fn collect(writes: Vec<Result<()>>) -> Result<Self::Output> {
1583        Ok(writes)
1584    }
1585
1586    type ReadNames = &'a [&'a str];
1587    type ReadSpec = T;
1588
1589}
1590
1591/// The values of a write, every name a scalar of its own sharing a single copy of all the
1592/// names, see [`Spectrum::get_scalar`].
1593fn named_values(values: Vec<(&str, Value)>) -> Vec<Named<Value>> {
1594    let names = names_buf(values.iter().map(|&(name, _)| name));
1595    values.into_iter()
1596        .enumerate()
1597        .map(|(index, (_, value))| Named::new(names.get_scalar([index]).expect("as many names as values"), value))
1598        .collect()
1599}
1600
1601macro_rules! impl_write_attr_spec_tuple {
1602    ( @name: $comp:ident ) => { &'a str };
1603    ( @one: $comp:ident ) => { 1 };
1604    ( @unit: $comp:ident ) => { Result<()> };
1605    ( @next: $comp:ident, $writes:ident ) => { $writes.next().ok_or_else(|| unexpected_len_err(LEN))? };
1606    ( $( $comp:ident )* ) => {
1607
1608        #[allow(non_snake_case)]
1609        impl<'a, $($comp: IntoValue, )*> WriteAttrSpec<'a> for ( $( (&'a str, $comp), )* ) {
1610
1611            #[inline]
1612            fn into_values(self) -> Vec<Named<Value>> {
1613                let ( $($comp,)* ) = self;
1614                named_values(vec![$(($comp.0, $comp.1.into_value()), )* ])
1615            }
1616
1617            type Output = ( $( impl_write_attr_spec_tuple!(@unit: $comp), )* );
1618
1619            fn collect(writes: Vec<Result<()>>) -> Result<Self::Output> {
1620                const LEN: usize = 0 $( + impl_write_attr_spec_tuple!(@one: $comp) )*;
1621                // The outcomes come in the order the values were given, which is the order
1622                // the components of a tuple are built in.
1623                let mut writes = writes.into_iter();
1624                let output = ( $( impl_write_attr_spec_tuple!(@next: $comp, writes), )* );
1625                if writes.next().is_some() {
1626                    return Err(unexpected_len_err(LEN));
1627                }
1628                Ok(output)
1629            }
1630
1631            type ReadNames = ( $(impl_write_attr_spec_tuple!(@name: $comp), )* );
1632            type ReadSpec = ( $($comp, )* );
1633
1634        }
1635
1636    };
1637}
1638
1639impl_write_attr_spec_tuple!(A);
1640impl_write_attr_spec_tuple!(A B);
1641impl_write_attr_spec_tuple!(A B C);
1642impl_write_attr_spec_tuple!(A B C D);
1643impl_write_attr_spec_tuple!(A B C D E);
1644impl_write_attr_spec_tuple!(A B C D E F);
1645
1646// =========================== //
1647//          Commands           //
1648// =========================== //
1649
1650/// Static information about a command.
1651#[derive(Debug, Clone, PartialEq, Eq)]
1652pub struct CommandInfo {
1653    /// The display level of the attribute.
1654    pub display_level: DisplayLevel,
1655    /// Input data kind.
1656    pub in_kind: CommandDataKind,
1657    /// Output data kind.
1658    pub out_kind: CommandDataKind,
1659    /// Description for the output data.
1660    pub in_doc: Option<Cow<'static, str>>,
1661    /// Description for the input data.
1662    pub out_doc: Option<Cow<'static, str>>,
1663}
1664
1665// =========================== //
1666//         Attributes          //
1667// =========================== //
1668
1669/// Represent the reading for a single attribute.
1670#[derive(Debug, Clone, PartialEq, Eq)]
1671pub struct AttrRead<T> {
1672    /// The read value of the attribute, if any. Absent if quality is Invalid or if the
1673    /// attribute is not readable.
1674    pub value: Option<T>,
1675    /// The write value of the attribute, if any. Absent if quality is Invalid or if the
1676    /// attribute is not writable.
1677    pub w_value: Option<T>,
1678    /// The quality of the value.
1679    pub quality: AttrQuality,
1680    /// The timestamp of the value.
1681    pub time: SystemTime,
1682}
1683
1684impl<T> AttrRead<T> {
1685
1686    pub fn new(value: T) -> Self {
1687        Self {
1688            value: Some(value),
1689            w_value: None,
1690            quality: AttrQuality::Valid,
1691            time: SystemTime::now(),
1692        }
1693    }
1694
1695    pub fn with_quality(mut self, quality: AttrQuality) -> Self {
1696        self.quality = quality;
1697        self
1698    }
1699
1700    pub fn with_time(mut self, time: SystemTime) -> Self {
1701        self.time = time;
1702        self
1703    }
1704
1705}
1706
1707impl AttrRead<Value> {
1708
1709    /// This reading, its values converted into the type they are expected to be.
1710    fn parse<T: FromValue>(self) -> Result<AttrRead<T>> {
1711        Ok(AttrRead {
1712            value: match self.value {
1713                Some(value) => Some(T::from_value(value)
1714                    .map_err(|err| err.with_append_description("Failed to parse read value"))?),
1715                None => None,
1716            },
1717            w_value: match self.w_value {
1718                Some(value) => Some(T::from_value(value)
1719                    .map_err(|err| err.with_append_description("Failed to parse write value"))?),
1720                None => None,
1721            },
1722            quality: self.quality,
1723            time: self.time,
1724        })
1725    }
1726
1727}
1728
1729/// Quality factor of the attribute.
1730#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1731pub enum AttrQuality {
1732    Valid,
1733    Invalid,
1734    Alarm,
1735    Changing,
1736    Warning,
1737}
1738
1739/// An extension to AttrConfig with static information about the attribute.
1740#[derive(Debug, Clone, PartialEq)]
1741pub struct AttrInfo {
1742    /// The configuration of the attribute, which is the whole of what a client is allowed
1743    /// to change of it, see [`AttrConfig`]. Everything else here is what the attribute is,
1744    /// which the device declares and nothing outside of it ever changes.
1745    pub config: AttrConfig,
1746    /// The attribute mode.
1747    pub mode: AttrMode,
1748    /// The data kind to be expected.
1749    pub data_kind: AttrDataKind,
1750    /// The data format to be expected, along with the maximum dimensions the attribute is
1751    /// declared with for the formats that have any.
1752    pub data_format: AttrDataFormat,
1753    /// The display level of the attribute.
1754    pub display_level: DisplayLevel,
1755    /// The memorized mode, absent for an attribute that remembers nothing.
1756    pub memorized: Option<AttrMemorized>,
1757}
1758
1759/// Attribute read/write mode.
1760#[derive(Debug, Clone, PartialEq, Eq)]
1761pub enum AttrMode {
1762    /// Read-only attribute
1763    Read,
1764    /// The attribute is technically read-only on the server side, but is associated to
1765    /// another write-only attribute that acts are the setpoint for that read-only value.
1766    ReadWithWrite {
1767        /// The name of the associated write attribute.
1768        write_attr_name: Cow<'static, str>,
1769    },
1770    /// Write-only attribute.
1771    Write,
1772    /// Read/write attribute.
1773    ReadWrite,
1774}
1775
1776/// Represent the current configuration of an attribute
1777///
1778/// The default configuration is the one of an attribute that declares nothing: no
1779/// description, no unit, no bound of any kind, no event configured, at the operator
1780/// display level, which is what a definition starts from and then fills in.
1781///
1782/// This is exactly what Tango keeps as the *attribute properties* of a device in the
1783/// database, and therefore exactly what a client is allowed to change, which is what
1784/// [`crate::backend::BackendDev::set_attr_config`] carries. Everything else a client reads
1785/// about an attribute is what the attribute *is* rather than how it is configured, and is
1786/// declared by the device, see [`AttrInfo`].
1787#[derive(Debug, Clone, PartialEq, Default)]
1788pub struct AttrConfig {
1789    /// The optional description of the attribute, which a client may change like any other
1790    /// property, `description` being one of the attribute properties Tango keeps.
1791    pub doc: Option<Cow<'static, str>>,
1792    /// The optional label of the attribute.
1793    pub label: Option<Cow<'static, str>>,
1794    /// The optional real unit of the attribute: how the raw attribute value is
1795    /// represented.
1796    pub unit: Option<Cow<'static, str>>,
1797    /// The conversion factor for going from the raw attribute value to the international
1798    /// unit system.
1799    pub standard_unit: Option<f64>,
1800    /// The optional unit for displaying to the user.
1801    pub display_unit: Option<Cow<'static, str>>,
1802    /// The display format of this value. That format is specified using printf formatting
1803    /// symbols using `%`.
1804    pub display_format: Option<Cow<'static, str>>,
1805    /// The allowed range for this attribute's value.
1806    pub range: AttrRangeConfig,
1807    /// The alarm range for this attribute's value.
1808    pub alarm: AttrRangeConfig,
1809    /// The warning range for this attribute's value.
1810    pub warning: AttrRangeConfig,
1811    /// The optional delta alarm.
1812    pub delta: Option<AttrDeltaConfig>,
1813    /// Configuration of the change event.
1814    pub change_event: AttrChangeEventConfig,
1815    /// Configuration of the periodic event.
1816    pub periodic_event: AttrPeriodicEventConfig,
1817    /// Configuration of the periodic event.
1818    pub archive_event: AttrArchiveEventConfig,
1819    /// What the values of the attribute mean, which only a `DevEnum` has any of: they name
1820    /// its values, an enumerated value being the index of its own label in this list.
1821    ///
1822    /// This is a property like any other and a client may change it, which is why it is
1823    /// here and not beside [`AttrInfo::data_kind`]: what a value of the attribute *is*
1824    /// stays a `DevEnum` whatever the labels are renamed to.
1825    pub enum_labels: Vec<Cow<'static, str>>,
1826    /// Possible extensions.
1827    pub extensions: Vec<Cow<'static, str>>,
1828}
1829
1830/// A limit of an attribute: one of the bounds of one of its ranges, or the delta of its
1831/// read-different-from-set alarm.
1832///
1833/// Tango carries these as strings, the type to read them as being the one of the attribute
1834/// they belong to, and they are numbers by the time they get here: a limit is something to
1835/// compare a value against, which is not something a string does.
1836///
1837/// They are not all the same number, though. A limit is a value of the attribute itself,
1838/// so an attribute of the widest integer kinds has limits a double cannot hold without
1839/// rounding them, and the three ways a Tango value is a number are kept apart rather than
1840/// all being flattened into one:
1841///
1842/// - a floating attribute, `DevFloat` or `DevDouble`, has [`Self::Double`] limits;
1843/// - a signed one, up to `DevLong64`, has [`Self::Long`] limits;
1844/// - an unsigned one, up to `DevULong64`, has [`Self::ULong`] limits.
1845///
1846/// A device that writes a limit its own type cannot hold — half a unit on an integer
1847/// attribute — still has a limit, and it is read as a [`Self::Double`] rather than lost.
1848///
1849/// Two limits compare as the quantities they stand for, whatever variant each is, so that
1850/// `Long(2)` and `Double(2.0)` are equal: two integers are compared exactly, the widest
1851/// ones included, and anything else as doubles, a not-a-number being equal to nothing and
1852/// ordered with nothing.
1853#[derive(Debug, Clone, Copy)]
1854pub enum AttrNumber {
1855    Double(f64),
1856    Long(i64),
1857    ULong(u64),
1858}
1859
1860impl AttrNumber {
1861
1862    /// This limit as a double, which is what comparing it against a value of any other
1863    /// kind goes through, the widest integers losing their last digits the way they do in
1864    /// any other conversion to a double.
1865    pub fn as_f64(self) -> f64 {
1866        match self {
1867            Self::Double(value) => value,
1868            Self::Long(value) => value as f64,
1869            Self::ULong(value) => value as f64,
1870        }
1871    }
1872
1873}
1874
1875impl PartialEq for AttrNumber {
1876    #[inline]
1877    fn eq(&self, other: &Self) -> bool {
1878        self.partial_cmp(other) == Some(Ordering::Equal)
1879    }
1880}
1881
1882impl PartialOrd for AttrNumber {
1883    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1884        match (*self, *other) {
1885            (Self::Long(a), Self::Long(b)) => Some(a.cmp(&b)),
1886            (Self::ULong(a), Self::ULong(b)) => Some(a.cmp(&b)),
1887            (Self::Long(a), Self::ULong(b)) => Some(i128::from(a).cmp(&i128::from(b))),
1888            (Self::ULong(a), Self::Long(b)) => Some(i128::from(a).cmp(&i128::from(b))),
1889            (a, b) => a.as_f64().partial_cmp(&b.as_f64()),
1890        }
1891    }
1892}
1893
1894impl fmt::Display for AttrNumber {
1895    /// Written the way a device writes it, which is what it goes back on the wire as.
1896    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1897        match self {
1898            Self::Double(value) => Display::fmt(value, f),
1899            Self::Long(value) => Display::fmt(value, f),
1900            Self::ULong(value) => Display::fmt(value, f),
1901        }
1902    }
1903}
1904
1905/// Every number that fits in one of the three, so that a limit can be given as the value
1906/// it is rather than as the variant holding it.
1907macro_rules! impl_attr_number_from {
1908    ($variant:ident: $($ty:ty),* $(,)?) => { $(
1909        impl From<$ty> for AttrNumber {
1910            #[inline]
1911            fn from(value: $ty) -> Self {
1912                Self::$variant(value.into())
1913            }
1914        }
1915    )* };
1916}
1917
1918impl_attr_number_from!(Double: f32, f64);
1919impl_attr_number_from!(Long: i8, i16, i32, i64);
1920impl_attr_number_from!(ULong: u8, u16, u32, u64);
1921
1922/// The two bounds of one of the ranges of an attribute, either of which is absent for a
1923/// range that is open on that side, which is also how an attribute says it has no such
1924/// range at all.
1925#[derive(Debug, Clone, Copy, PartialEq, Default)]
1926pub struct AttrRangeConfig {
1927    pub min: Option<AttrNumber>,
1928    pub max: Option<AttrNumber>,
1929}
1930
1931impl AttrRangeConfig {
1932    /// Whether that range has any bound, a range with none being no range at all.
1933    #[inline]
1934    pub fn is_set(&self) -> bool {
1935        self.min.is_some() || self.max.is_some()
1936    }
1937}
1938
1939/// The alarm on the read value drifting away from the written one.
1940#[derive(Debug, Clone, Copy, PartialEq)]
1941pub struct AttrDeltaConfig {
1942    /// How far the two may be apart before the attribute is in alarm, in the type of the
1943    /// attribute, being a value of it like any other limit.
1944    pub value: AttrNumber,
1945    /// How long they may stay that far apart before it counts, absent for immediately.
1946    pub time: Option<Duration>,
1947}
1948
1949/// The criteria of the change event: how much the value has to move for the server to send
1950/// one, absolutely or relatively, either of which may be left out.
1951#[derive(Debug, Clone, Copy, PartialEq, Default)]
1952pub struct AttrChangeEventConfig {
1953    /// The relative change, as a percentage of the previous value.
1954    pub rel_change: Option<f64>,
1955    /// The absolute change, in the unit of the attribute.
1956    pub abs_change: Option<f64>,
1957}
1958
1959impl AttrChangeEventConfig {
1960    /// Whether the change event has any criterion, an event with none never being sent.
1961    #[inline]
1962    pub fn is_set(&self) -> bool {
1963        self.rel_change.is_some() || self.abs_change.is_some()
1964    }
1965}
1966
1967#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
1968pub struct AttrPeriodicEventConfig {
1969    pub period: Option<Duration>,
1970}
1971
1972impl AttrPeriodicEventConfig {
1973    /// Whether the periodic event has a period of its own.
1974    #[inline]
1975    pub fn is_set(&self) -> bool {
1976        self.period.is_some()
1977    }
1978}
1979
1980/// The criteria of the archive event: the same two changes as the change event, and the
1981/// longest an archiver may go without an event when the value does not move.
1982#[derive(Debug, Clone, Copy, PartialEq, Default)]
1983pub struct AttrArchiveEventConfig {
1984    pub rel_change: Option<f64>,
1985    pub abs_change: Option<f64>,
1986    pub period: Option<Duration>,
1987}
1988
1989impl AttrArchiveEventConfig {
1990    /// Whether the archive event has any criterion, a change or a period.
1991    #[inline]
1992    pub fn is_set(&self) -> bool {
1993        self.rel_change.is_some() || self.abs_change.is_some() || self.period.is_some()
1994    }
1995}
1996
1997/// What a memorized attribute does, when its device is initialized, with the value it
1998/// remembers.
1999///
2000/// Both modes store the value of every write in the database, they only differ in what the
2001/// next initialization of the device does with the value it finds there.
2002#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
2003pub enum AttrMemorized {
2004    /// The remembered value is restored as the write value of the attribute and nothing
2005    /// else: a client reading the attribute back finds the setpoint it left, but the write
2006    /// function is never called, so the device does not act on its hardware only because
2007    /// it was restarted.
2008    RestoreSetPoint,
2009    /// The remembered value is written again, through the write function of the attribute,
2010    /// which puts the device back in the state it was left in.
2011    RestoreAndWrite,
2012}
2013
2014// =========================== //
2015//           Device            //
2016// =========================== //
2017
2018/// Static information about a device: what it is and where it runs.
2019///
2020/// None of this is something a client computes anything from, it is what it shows about a
2021/// device, and all of it is decided by the server rather than by the device itself.
2022#[derive(Debug, Clone, PartialEq, Eq, Default)]
2023pub struct DevInfo {
2024    /// The name of the class the device is an instance of.
2025    pub class: String,
2026    /// The `exe/inst` name of the server running the device, which is what it is
2027    /// registered in the database under.
2028    pub server_id: String,
2029    /// The name of the host the server runs on.
2030    pub server_host: String,
2031    /// The IDL version the server says it implements, which is a statement it makes about
2032    /// itself and decides nothing.
2033    pub server_version: i32,
2034    /// Where the documentation of the class is, when it has any.
2035    pub doc_url: Option<Cow<'static, str>>,
2036    /// What the device is, which is free text a class gives itself, absent for a device
2037    /// whose server is too old to have any.
2038    pub dev_type: Option<Cow<'static, str>>,
2039    /// The versions of whatever the server is built out of, as the pairs of a name and a
2040    /// version that the server chooses to publish. Empty for a server too old to have any,
2041    /// this being the one thing IDL v6 added.
2042    pub version_info: Vec<(Cow<'static, str>, Cow<'static, str>)>,
2043}
2044
2045// =========================== //
2046//        Various enums        //
2047// =========================== //
2048
2049/// All possible device states.
2050#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
2051#[repr(u8)]
2052pub enum DevState {
2053    On,
2054    Off,
2055    Close,
2056    Open,
2057    Insert,
2058    Extract,
2059    Moving,
2060    Standby,
2061    Fault,
2062    Init,
2063    Running,
2064    Alarm,
2065    Disable,
2066    Unknown,
2067}
2068
2069/// Source when querying an attribute.
2070#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
2071pub enum DevSource {
2072    /// Do not use the polling cache.
2073    Dev,
2074    /// Only use the polling cache.
2075    Cache,
2076    /// First use the polling cache, and fallback without it.
2077    CacheDev,
2078}
2079
2080#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
2081pub enum DisplayLevel {
2082    /// The level everything is at unless it is said otherwise: what a control room shows.
2083    #[default]
2084    Operator,
2085    Expert,
2086}
2087
2088// =========================== //
2089//           Events            //
2090// =========================== //
2091
2092/// The events of a subscription in place, as the backend gives them, of the kind that was
2093/// subscribed to.
2094enum ChannelEvents {
2095    Value(BoxStream<'static, Result<AttrRead<Value>>>),
2096    Ready(BoxStream<'static, Result<()>>),
2097    Conf(BoxStream<'static, Result<AttrInfo>>),
2098}
2099
2100impl ChannelEvents {
2101
2102    /// Poll the readings of an attribute, converted into the type they are expected to be.
2103    fn poll_value<T: FromValue>(&mut self, cx: &mut Context<'_>) -> Poll<Option<Result<AttrRead<T>>>> {
2104        let Self::Value(stream) = self else { unreachable!("a value channel subscribes to values") };
2105        stream.poll_next_unpin(cx).map(|item| item.map(|read| read.and_then(AttrRead::parse)))
2106    }
2107
2108    /// Poll an attribute being ready to be read.
2109    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Option<Result<()>>> {
2110        let Self::Ready(stream) = self else { unreachable!("a ready channel subscribes to readiness") };
2111        stream.poll_next_unpin(cx)
2112    }
2113
2114    /// Poll the configuration of an attribute.
2115    fn poll_conf(&mut self, cx: &mut Context<'_>) -> Poll<Option<Result<AttrInfo>>> {
2116        let Self::Conf(stream) = self else { unreachable!("a configuration channel subscribes to configurations") };
2117        stream.poll_next_unpin(cx)
2118    }
2119
2120}
2121
2122/// What a [`DevChannel`] subscribes to.
2123#[derive(Debug, Clone, Copy)]
2124enum ChannelKind {
2125    Value(AttrValueEvent),
2126    Ready,
2127    Conf,
2128}
2129
2130/// The events of a subscription to a device, which unsubscribes when it is dropped: it is
2131/// a [`Stream`] for an asynchronous caller, and [`Self::wait`] blocks for a synchronous one.
2132///
2133/// It gives the latest event and not every one of them, a subscriber that does not keep up
2134/// skipping to the latest, and never ends. An item that is an error is one event that
2135/// failed, such as the reading the device was to push, or the subscription failing to be
2136/// made or being lost.
2137///
2138/// # Subscribing
2139///
2140/// The subscription is made lazily, the first time the channel is polled, a failure being
2141/// given as an item like any other. A subscriber that wants to know that it is in place
2142/// before it waits for events ensures it, see [`Self::ensure_subscribed_async`].
2143///
2144/// The subscription of a backend lives as long as the connection it was made over, see
2145/// [`BackendDev`], while the device may be restarted, elsewhere even. The channel holds
2146/// the proxy of the device for that, which finds it again the way it does for any
2147/// request: once the subscription is lost, which the backend tells with the very errors a
2148/// request fails with when its connection is lost, the proxy forgets its connection the
2149/// way it does for a request, and the channel makes the subscription again through it.
2150/// The admin device, which subscribing goes through in Tango, is found again along with
2151/// it: its server is the one of the device, which may have moved with it.
2152///
2153/// Every attempt is made on the poll after the one that gave the failure of the previous
2154/// one, so that a subscriber retries as fast as it reads. The events then come back on
2155/// their own, with no initial value either: read the attribute once the channel gave an
2156/// error to know where it stands after it.
2157pub struct DevChannel<T> {
2158    /// The device, which is moved into an attempt at subscribing for as long as it runs,
2159    /// and back once it is over.
2160    dev: Option<DevProxy>,
2161    /// The name of the attribute subscribed to.
2162    name: Arc<str>,
2163    kind: ChannelKind,
2164    /// Takes an event out of the events of the kind subscribed to, see [`ChannelEvents`].
2165    poll_events: fn(&mut ChannelEvents, &mut Context<'_>) -> Poll<Option<Result<T>>>,
2166    /// The timeout of the device, which bounds the blocking calls of the channel.
2167    timeout: Duration,
2168    state: ChannelState,
2169}
2170
2171enum ChannelState {
2172    /// Giving the events of a subscription in place.
2173    Subscribed(ChannelEvents),
2174    /// Making the subscription, the device being given back with the outcome. The attempt
2175    /// is only made once it is polled.
2176    Subscribing(BoxFuture<'static, (DevProxy, Result<ChannelEvents>)>),
2177}
2178
2179impl ChannelState {
2180
2181    /// An attempt at making the subscription, which goes through the admin device of the
2182    /// device, found again on every attempt, see the [`BackendDev`] subscriptions.
2183    fn subscribing(dev: DevProxy, name: Arc<str>, kind: ChannelKind) -> Self {
2184        Self::Subscribing(Box::pin(async move {
2185            let res = async {
2186                let backend = dev.ensure_backend().await?;
2187                let admin = dev.admin_dev_async().await?;
2188                let admin = admin.ensure_backend().await?;
2189                let res = match kind {
2190                    ChannelKind::Value(event) => backend.subscribe_attr_value(admin, &name, event).await.map(ChannelEvents::Value),
2191                    ChannelKind::Ready => backend.subscribe_attr_ready(admin, &name).await.map(ChannelEvents::Ready),
2192                    ChannelKind::Conf => backend.subscribe_attr_conf(admin, &name).await.map(ChannelEvents::Conf),
2193                };
2194                dev.check_backend(res)
2195            }.await;
2196            (dev, res)
2197        }))
2198    }
2199
2200}
2201
2202impl<T> DevChannel<T> {
2203
2204    /// A channel to an attribute of the device, subscribed to once it is polled, its events
2205    /// being taken out of those of the kind with the given function.
2206    fn new(
2207        dev: DevProxy,
2208        name: &str,
2209        kind: ChannelKind,
2210        poll_events: fn(&mut ChannelEvents, &mut Context<'_>) -> Poll<Option<Result<T>>>,
2211    ) -> Self {
2212        let timeout = dev.timeout();
2213        let name = Arc::<str>::from(name);
2214        let state = ChannelState::subscribing(dev, Arc::clone(&name), kind);
2215        Self { dev: None, name, kind, poll_events, timeout, state }
2216    }
2217
2218    /// Start an attempt at making the subscription again.
2219    fn resubscribe(&mut self) {
2220        let dev = self.dev.take().expect("the device is moved into one attempt at a time");
2221        self.state = ChannelState::subscribing(dev, Arc::clone(&self.name), self.kind);
2222    }
2223
2224    /// Drive the attempt at subscribing to its outcome, if one is running, the next one
2225    /// being made on the next poll if it failed.
2226    fn poll_subscribed(&mut self, cx: &mut Context<'_>) -> Poll<Result<()>> {
2227
2228        let ChannelState::Subscribing(attempt) = &mut self.state else {
2229            return Poll::Ready(Ok(()));
2230        };
2231
2232        let (dev, res) = ready!(attempt.as_mut().poll(cx));
2233        let dev = &*self.dev.insert(dev);
2234
2235        Poll::Ready(match res {
2236            Ok(events) => {
2237                debug!(dev = %dev.inner.target, attr = %self.name, kind = ?self.kind, "Subscribed to the events");
2238                self.state = ChannelState::Subscribed(events);
2239                Ok(())
2240            }
2241            Err(err) => {
2242                debug!(dev = %dev.inner.target, attr = %self.name, kind = ?self.kind, %err, "Failed to subscribe to the events, retrying on the next poll");
2243                self.resubscribe();
2244                Err(err)
2245            }
2246        })
2247
2248    }
2249
2250    /// Make the subscription if it is not in place, giving the failure of the attempt if
2251    /// it failed: the failure is then not given as an item, and the next attempt is made
2252    /// on the next poll.
2253    pub async fn ensure_subscribed_async(&mut self) -> Result<()> {
2254        poll_fn(|cx| self.poll_subscribed(cx)).await
2255    }
2256
2257    /// Make the subscription if it is not in place, see [`Self::ensure_subscribed_async`],
2258    /// at most for the timeout of the device.
2259    pub fn ensure_subscribed(&mut self) -> Result<()> {
2260        let timeout = self.timeout;
2261        block_on_timeout(self.ensure_subscribed_async(), timeout)?
2262    }
2263
2264    /// Wait for the next event, at most for that long, failing with
2265    /// [`ErrorKind::TimedOut`] when none came.
2266    pub fn wait(&mut self, timeout: Duration) -> Result<T> {
2267        match block_on_timeout(self.next(), timeout)? {
2268            Some(item) => item,
2269            None => unreachable!("a device channel never ends"),
2270        }
2271    }
2272
2273}
2274
2275impl<T> Stream for DevChannel<T> {
2276
2277    type Item = Result<T>;
2278
2279    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
2280
2281        let this = self.get_mut();
2282
2283        loop {
2284
2285            if let Err(err) = ready!(this.poll_subscribed(cx)) {
2286                return Poll::Ready(Some(Err(err)));
2287            }
2288
2289            let ChannelState::Subscribed(events) = &mut this.state else {
2290                unreachable!("subscribed once the attempt succeeded");
2291            };
2292
2293            match ready!((this.poll_events)(events, cx)) {
2294                Some(Err(err)) if err.kind() == ErrorKind::DevNotConnected => {
2295                    debug!(attr = %this.name, kind = ?this.kind, %err, "Lost the subscription to the events, subscribing again on the next poll");
2296                    if let Some(dev) = &this.dev {
2297                        dev.reset_backend();
2298                    }
2299                    this.resubscribe();
2300                    return Poll::Ready(Some(Err(err)));
2301                }
2302                Some(item) => return Poll::Ready(Some(item)),
2303                // A backend ending its stream without saying why.
2304                None => {
2305                    debug!(attr = %this.name, kind = ?this.kind, "The subscription to the events ended, subscribing again");
2306                    this.resubscribe();
2307                }
2308            }
2309
2310        }
2311
2312    }
2313
2314}
2315
2316impl<T> Debug for DevChannel<T> {
2317    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2318        f.debug_struct("DevChannel")
2319            .field("dev", &self.dev)
2320            .field("name", &self.name)
2321            .finish_non_exhaustive()
2322    }
2323}
2324
2325/// Kind of event for a device attribute.
2326#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
2327pub enum AttrValueEvent {
2328    Change,
2329    Periodic,
2330    Archive,
2331    User,
2332    Alarm,
2333}
2334
2335/// What the failure of a command is turned into: the reasons cppTango answers with are
2336/// mapped onto the kinds of this crate, and an argument type that did not match carries
2337/// the kind that was expected, read back out of the description, see
2338/// [`expected_cpp_tango_type`].
2339/// The failure of a device answering with a number of entries that is not the one it was
2340/// asked for, which a form of a fixed shape has no output to build out of: the device broke
2341/// what the protocol says of it, so the request fails as a whole rather than an entry of it.
2342#[cold]
2343pub(crate) fn unexpected_len_err(expected: usize) -> Error {
2344    Error::new(ErrorKind::Internal)
2345        .with_description("The device did not answer with as many entries as were requested")
2346        .with_append_description(format_args!("{expected} were expected"))
2347}
2348
2349fn command_err(err: Error) -> Error {
2350    match err.kind() {
2351        ErrorKind::Reason(reason::API_CommandNotFound) => {
2352            err.with_kind(ErrorKind::CommandNotFound)
2353        }
2354        ErrorKind::Reason(reason::API_IncompatibleCmdArgumentType) => {
2355
2356            let expected_kind = expected_cpp_tango_type(err.description())
2357                .and_then(command_data_kind_from_cpp_tango);
2358
2359            let err = err.with_kind(ErrorKind::CommandArgumentKindInvalid);
2360            match expected_kind {
2361                Some(kind) => err.with_append_description(format_args!("Expected kind: {kind:?}")),
2362                None => err,
2363            }
2364
2365        }
2366        _ => err,
2367    }
2368}
2369
2370/// What the failure of one attribute write is turned into, see [`command_err`].
2371fn write_attr_err(err: Error) -> Error {
2372    match err.kind() {
2373        ErrorKind::Reason(reason::API_AttrNotFound) => {
2374            err.with_kind(ErrorKind::AttrNotFound)
2375        }
2376        ErrorKind::Reason(reason::API_AttrNotWritable) => {
2377            err.with_kind(ErrorKind::AttrNotWritable)
2378        }
2379        ErrorKind::Reason(reason::API_IncompatibleAttrDataType) => {
2380
2381            let expected_kind = expected_cpp_tango_type(err.description())
2382                .and_then(attr_data_kind_from_cpp_tango);
2383
2384            let err = err.with_kind(ErrorKind::AttrKindInvalid);
2385            match expected_kind {
2386                Some(kind) => err.with_append_description(format_args!("Expected kind: {kind:?}")),
2387                None => err,
2388            }
2389
2390        }
2391        _ => err,
2392    }
2393}
2394
2395/// Extract the type cppTango says it was expecting out of an error description.
2396///
2397/// The relevant descriptions all name the expected type first, prefixed by the `Tango::`
2398/// namespace, and the type actually found (when they mention it) only after:
2399/// - `Incompatible command argument type, expected type is : Tango::DevBoolean`
2400///   (`Command::throw_bad_type`)
2401/// - `Incompatible attribute type: expected Tango::DevVarDoubleArray (even for single
2402///   value), found Tango::DevVarStringArray` (`WAttribute::check_written_value`)
2403///
2404/// So the first `Tango::`-prefixed word is the expected one, and it's trimmed of any
2405/// trailing punctuation such as the comma or the null byte cppTango's `std::ends` leaves
2406/// behind on some messages.
2407fn expected_cpp_tango_type(description: &str) -> Option<&str> {
2408    description.split_ascii_whitespace()
2409        .find_map(|word| word.strip_prefix("Tango::"))
2410        .map(|ty| ty.trim_matches(|c: char| !c.is_ascii_alphanumeric()))
2411}
2412
2413/// Try to parse the given cpp tango data type into a standard [`CommandDataKind`].
2414///
2415/// The names are the literals given to `Command::throw_bad_type` in cppTango, which match
2416/// the `CmdArgTypeName` table.
2417fn command_data_kind_from_cpp_tango(cpp_type: &str) -> Option<CommandDataKind> {
2418    Some(match cpp_type {
2419        "DevVoid" => CommandDataKind::Void,
2420        "DevBoolean" => CommandDataKind::Bool,
2421        "DevUChar" => CommandDataKind::Octet,
2422        "DevShort" => CommandDataKind::Short,
2423        "DevUShort" => CommandDataKind::UShort,
2424        "DevLong" => CommandDataKind::Long,
2425        "DevULong" => CommandDataKind::ULong,
2426        "DevLong64" => CommandDataKind::Long64,
2427        "DevULong64" => CommandDataKind::ULong64,
2428        "DevFloat" => CommandDataKind::Float,
2429        "DevDouble" => CommandDataKind::Double,
2430        "DevState" => CommandDataKind::State,
2431        "DevString" |
2432        "ConstDevString" => CommandDataKind::String,
2433        "DevVarBooleanArray" => CommandDataKind::BoolArray,
2434        "DevVarCharArray" => CommandDataKind::OctetArray,
2435        "DevVarShortArray" => CommandDataKind::ShortArray,
2436        "DevVarUShortArray" => CommandDataKind::UShortArray,
2437        "DevVarLongArray" => CommandDataKind::LongArray,
2438        "DevVarULongArray" => CommandDataKind::ULongArray,
2439        "DevVarLong64Array" => CommandDataKind::Long64Array,
2440        "DevVarULong64Array" => CommandDataKind::ULong64Array,
2441        "DevVarFloatArray" => CommandDataKind::FloatArray,
2442        "DevVarDoubleArray" => CommandDataKind::DoubleArray,
2443        "DevVarStateArray" => CommandDataKind::StateArray,
2444        "DevVarStringArray" => CommandDataKind::StringArray,
2445        "DevVarLongStringArray" => CommandDataKind::LongStringArray,
2446        "DevVarDoubleStringArray" => CommandDataKind::DoubleStringArray,
2447        "DevEncoded" => CommandDataKind::Encoded,
2448        _ => return None,
2449    })
2450}
2451
2452/// Try to parse the given cpp tango data type into a standard [`AttrDataKind`].
2453///
2454/// An attribute value is always carried as a sequence on the wire, so cppTango always
2455/// names the array type here, even for a scalar attribute; the scalar spellings are
2456/// accepted anyway because [`AttrDataKind`] carries no layout of its own and other
2457/// cppTango versions word it differently.
2458///
2459/// Note that an enumerated attribute is reported as `DevVarShortArray` by cppTango, so it
2460/// is parsed as [`AttrDataKind::Short`]: the labels needed to build
2461/// [`AttrDataKind::Enum`] are simply not in the message.
2462fn attr_data_kind_from_cpp_tango(cpp_type: &str) -> Option<AttrDataKind> {
2463    Some(match cpp_type {
2464        "DevBoolean" | "DevVarBooleanArray" => AttrDataKind::Bool,
2465        "DevUChar" | "DevVarCharArray" => AttrDataKind::Octet,
2466        "DevShort" | "DevVarShortArray" => AttrDataKind::Short,
2467        "DevUShort" | "DevVarUShortArray" => AttrDataKind::UShort,
2468        "DevLong" | "DevVarLongArray" => AttrDataKind::Long,
2469        "DevULong" | "DevVarULongArray" => AttrDataKind::ULong,
2470        "DevLong64" | "DevVarLong64Array" => AttrDataKind::Long64,
2471        "DevULong64" | "DevVarULong64Array" => AttrDataKind::ULong64,
2472        "DevFloat" | "DevVarFloatArray" => AttrDataKind::Float,
2473        "DevDouble" | "DevVarDoubleArray" => AttrDataKind::Double,
2474        "DevState" | "DevVarStateArray" => AttrDataKind::State,
2475        "DevString" | "ConstDevString" | "DevVarStringArray" => AttrDataKind::String,
2476        "DevEncoded" | "DevVarEncodedArray" => AttrDataKind::Encoded,
2477        _ => return None,
2478    })
2479}
2480
2481/// Display the host and port pairs of [`env_databases`] the way they are written in
2482/// `TANGO_HOST`, so that an error naming them can be compared to the variable itself.
2483struct DisplayHostAndPorts<'a>(&'a [(Arc<str>, u16)]);
2484
2485impl Display for DisplayHostAndPorts<'_> {
2486    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2487        for (i, (host, port)) in self.0.iter().enumerate() {
2488            if i != 0 {
2489                f.write_str(", ")?;
2490            }
2491            write!(f, "{host}:{port}")?;
2492        }
2493        Ok(())
2494    }
2495}
2496
2497/// Get the database host/port tuples from the `TANGO_HOST` environment variable.
2498fn env_databases() -> &'static [(Arc<str>, u16)] {
2499    static CACHE: OnceLock<Box<[(Arc<str>, u16)]>> = OnceLock::new();
2500    &**CACHE.get_or_init(|| {
2501
2502        let mut ret = Vec::new();
2503
2504        if let Ok(var) = env::var("TANGO_HOST") {
2505            for part in var.split(',') {
2506                if let Some((host, port_raw)) = part.rsplit_once(':')
2507                && let Ok(port) = u16::from_str(port_raw) {
2508                    ret.push((host.into(), port));
2509                }
2510            }
2511        }
2512        
2513        ret.into_boxed_slice()
2514
2515    })
2516}
2517
2518
2519#[cfg(test)]
2520mod tests {
2521
2522    use crate::value::Scalar;
2523
2524    use super::*;
2525
2526    /// The property requests of a proxy, awaited within a future boxed as `Send`: this only
2527    /// has to compile.
2528    #[allow(dead_code)]
2529    fn props_in_send_future(proxy: &DevProxy) -> BoxFuture<'_, Result<()>> {
2530        Box::pin(async move {
2531            let _speed = proxy.get_prop_async::<f64, _>("speed").await?;
2532            let _all = proxy.get_prop_async::<Spectrum<str>, _>(All).await?;
2533            proxy.set_prop_async(("speed", 2.5)).await?;
2534            proxy.del_prop_async(["speed", "accel"]).await
2535        })
2536    }
2537
2538    /// The requests of a proxy, awaited within a future boxed as `Send`, which is what an
2539    /// asynchronous handler forwarding to another device is: this only has to compile.
2540    #[allow(dead_code)]
2541    fn requests_in_send_future(proxy: &DevProxy) -> BoxFuture<'_, Result<()>> {
2542        Box::pin(async move {
2543            let _: f64 = proxy.command_async("Add", 1.0).await?;
2544            let _: String = proxy.command_async("Echo", "text").await?;
2545            let _ = proxy.read_attr_async::<f64, _>("speed").await?;
2546            let _ = proxy.read_attr_async::<f64, _>(["speed", "accel"]).await?;
2547            let _ = proxy.read_attr_async::<Value, _>(All).await?;
2548            proxy.write_attr_async(("speed", 2.5)).await?;
2549            let _ = proxy.write_attr_async([("speed", 2.5), ("accel", 1.0)]).await?;
2550            let _ = proxy.write_read_attr_async(("speed", 2.5)).await?;
2551            let _ = proxy.command_info_async("Add").await?;
2552            let _ = proxy.attr_info_async(["speed"]).await?;
2553            let names = proxy.list_prop_async("*").await?;
2554            let _ = proxy.read_attr_async::<f64, _>(&names).await?;
2555            let _ = proxy.attr_info_async(names).await?;
2556            Ok(())
2557        })
2558    }
2559
2560    /// A property request is `Send` whatever the names it is given are, since its future
2561    /// holds nothing of them but the copy it makes of them: this only has to compile.
2562    #[allow(dead_code)]
2563    fn props_of_any_names<'a, Names>(proxy: &'a DevProxy, names: Names) -> BoxFuture<'a, Result<<f64 as GetPropSpec<Names>>::Output>>
2564    where
2565        Names: ToNames + 'a,
2566        f64: GetPropSpec<Names>,
2567    {
2568        Box::pin(proxy.get_prop_async::<f64, Names>(names))
2569    }
2570
2571    #[test]
2572    fn expected_kind() {
2573
2574        // Verbatim from cppTango 'Command::throw_bad_type', trailing null byte included
2575        // because the message is built with 'std::ends'.
2576        let cmd = "Incompatible command argument type, expected type is : Tango::DevVarDoubleStringArray\0";
2577        assert_eq!(expected_cpp_tango_type(cmd), Some("DevVarDoubleStringArray"));
2578        assert_eq!(
2579            expected_cpp_tango_type(cmd).and_then(command_data_kind_from_cpp_tango),
2580            Some(CommandDataKind::DoubleStringArray),
2581        );
2582
2583        // Verbatim from cppTango 'WAttribute::check_written_value', which names the found
2584        // type after the expected one: only the expected one should be picked up.
2585        let attr = "Incompatible attribute type: expected Tango::DevVarDoubleArray (even for single value), found Tango::DevVarStringArray\0";
2586        assert_eq!(expected_cpp_tango_type(attr), Some("DevVarDoubleArray"));
2587        assert_eq!(
2588            expected_cpp_tango_type(attr).and_then(attr_data_kind_from_cpp_tango),
2589            Some(AttrDataKind::Double),
2590        );
2591
2592        assert_eq!(attr_data_kind_from_cpp_tango("DevVarEncodedArray"), Some(AttrDataKind::Encoded));
2593        assert_eq!(command_data_kind_from_cpp_tango("DevEncoded"), Some(CommandDataKind::Encoded));
2594
2595        // Unrelated descriptions and unsupported types should not yield any kind.
2596        assert_eq!(expected_cpp_tango_type("Attribute my_attr is not writable"), None);
2597        assert_eq!(command_data_kind_from_cpp_tango("DevVarEncodedArray"), None);
2598
2599    }
2600
2601    /// Readings decided ahead of time, standing in for the ones a backend would have
2602    /// decoded out of what a device answered.
2603    fn reads<const N: usize>(entries: [(&str, Value); N]) -> Vec<NamedResult<AttrRead<Value>>> {
2604        entries.into_iter()
2605            .map(|(name, value)| Named::new(Scalar::from(name), Ok(AttrRead::new(value))))
2606            .collect()
2607    }
2608
2609    /// One name asks for one reading, which is the output itself: there is no slot around
2610    /// it, so what is given back is that reading and nothing else.
2611    #[test]
2612    fn single_reading() {
2613        let reads = reads([("double_scalar", Value::from(2.5))]);
2614        let read = <f64 as ReadAttrSpec<&str>>::collect(reads).unwrap();
2615        assert_eq!(read.value, Some(2.5));
2616    }
2617
2618    /// The readings come back in the order the names were given, and a form of a fixed
2619    /// shape has one slot per name.
2620    #[test]
2621    fn readings_in_order() {
2622        let reads = reads([("first", Value::from(1.0)), ("second", Value::from(2.0))]);
2623        let [first, second] = <f64 as ReadAttrSpec<[&str; 2]>>::collect(reads).unwrap();
2624        assert_eq!(first.unwrap().value, Some(1.0));
2625        assert_eq!(second.unwrap().value, Some(2.0));
2626    }
2627
2628    /// A tuple of names gives every reading the type of its own component, so a device
2629    /// answering with a double and a string is read into both at once.
2630    #[test]
2631    fn readings_of_their_own_types() {
2632        let reads = reads([("double_scalar", Value::from(2.5)), ("string_scalar", Value::from("hello"))]);
2633        let (double, string) = <(f64, String) as ReadAttrSpec<(&str, &str)>>::collect(reads).unwrap();
2634        assert_eq!(double.unwrap().value, Some(2.5));
2635        assert_eq!(string.unwrap().value.as_deref(), Some("hello"));
2636    }
2637
2638    /// A device answering with fewer readings than there are slots to put them in fails the
2639    /// whole request: the output of a fixed shape cannot be built out of what came back.
2640    #[test]
2641    fn missing_reading() {
2642        let reads = reads([("first", Value::from(1.0))]);
2643        let err = <f64 as ReadAttrSpec<[&str; 2]>>::collect(reads).unwrap_err();
2644        assert_eq!(err.kind(), ErrorKind::Internal);
2645    }
2646
2647    /// Reading every attribute of a device names every reading back, since nothing named
2648    /// them on the way out.
2649    #[test]
2650    fn every_reading_named() {
2651        let reads = reads([("first", Value::from(1.0)), ("second", Value::from(2.0))]);
2652        let all = <Value as ReadAttrSpec<All>>::collect(reads).unwrap();
2653        let names = all.iter().map(|read| read.name.value()).collect::<Vec<_>>();
2654        assert_eq!(names, ["first", "second"]);
2655    }
2656
2657    /// The outcomes of a write come back in the order the values were given, one per value
2658    /// and named by none of them.
2659    #[test]
2660    fn write_outcomes() {
2661        let writes = vec![Ok(()), Err(Error::new(ErrorKind::AttrNotWritable))];
2662        let (first, second) = <((&str, f64), (&str, f64)) as WriteAttrSpec>::collect(writes).unwrap();
2663        assert!(first.is_ok());
2664        assert_eq!(second.unwrap_err().kind(), ErrorKind::AttrNotWritable);
2665    }
2666
2667    /// A device answering for a number of values that is not the one that was written
2668    /// fails the whole request, the same way it does for a read.
2669    #[test]
2670    fn unexpected_outcome() {
2671        let writes = vec![Ok(())];
2672        let err = <((&str, f64), (&str, f64)) as WriteAttrSpec>::collect(writes).unwrap_err();
2673        assert_eq!(err.kind(), ErrorKind::Internal);
2674    }
2675
2676}