1#![expect(clippy::doc_markdown)]
14
15mod server_info;
16pub use server_info::*;
17
18#[cfg(any(feature = "camera", feature = "telescope"))]
19mod camera_telescope_shared;
20
21mod device_state;
22pub use device_state::TimestampedDeviceState;
23
24mod time_repr;
25
26use std::fmt::Debug;
27use std::sync::Arc;
28
29#[macro_use]
30mod macros;
31
32pub mod device;
34pub use device::Device;
35
36pub type ASCOMResultFuture<'async_trait, T> =
40 futures::future::BoxFuture<'async_trait, crate::ASCOMResult<T>>;
41
42rpc_mod! {
43 #[cfg(feature = "camera")]
44 Camera = "camera",
45
46 #[cfg(feature = "cover_calibrator")]
47 CoverCalibrator = "covercalibrator",
48
49 #[cfg(feature = "dome")]
50 Dome = "dome",
51
52 #[cfg(feature = "filter_wheel")]
53 FilterWheel = "filterwheel",
54
55 #[cfg(feature = "focuser")]
56 Focuser = "focuser",
57
58 #[cfg(feature = "observing_conditions")]
59 ObservingConditions = "observingconditions",
60
61 #[cfg(feature = "rotator")]
62 Rotator = "rotator",
63
64 #[cfg(feature = "safety_monitor")]
65 SafetyMonitor = "safetymonitor",
66
67 #[cfg(feature = "switch")]
68 Switch = "switch",
69
70 #[cfg(feature = "telescope")]
71 Telescope = "telescope",
72}
73
74pub(crate) trait RetrieavableDevice: 'static + Device {
75 #[allow(unused)]
76 const TYPE: DeviceType;
77
78 fn get_storage(storage: &Devices) -> &[Arc<Self>];
79
80 #[cfg(feature = "server")]
81 fn to_configured_device(&self, as_number: usize) -> ConfiguredDevice<DeviceType> {
82 ConfiguredDevice {
83 name: self.static_name().to_owned(),
84 ty: Self::TYPE,
85 number: as_number,
86 unique_id: self.unique_id().to_owned(),
87 }
88 }
89}
90
91pub(crate) trait RegistrableDevice<DynTrait: ?Sized>: Debug {
97 fn add_to(self, storage: &mut Devices);
98}
99
100impl Default for Devices {
101 fn default() -> Self {
102 Self::default()
104 }
105}
106
107#[expect(private_bounds)]
109impl Devices {
110 #[tracing::instrument(level = "debug", skip(self))]
118 pub fn register<DynTrait: ?Sized>(&mut self, device: impl RegistrableDevice<DynTrait>) {
119 device.add_to(self);
120 }
121
122 pub fn iter<DynTrait: ?Sized + RetrieavableDevice>(
124 &self,
125 ) -> impl ExactSizeIterator<Item = Arc<DynTrait>> {
126 DynTrait::get_storage(self).iter().map(Arc::clone)
127 }
128
129 pub fn get<DynTrait: ?Sized + RetrieavableDevice>(
133 &self,
134 device_number: usize,
135 ) -> Option<Arc<DynTrait>> {
136 DynTrait::get_storage(self).get(device_number).cloned()
137 }
138
139 #[cfg(feature = "server")]
140 pub(crate) fn get_for_server<DynTrait: ?Sized + RetrieavableDevice>(
141 &self,
142 device_number: usize,
143 ) -> crate::server::Result<Arc<DynTrait>> {
144 DynTrait::get_storage(self)
145 .get(device_number)
146 .map(Arc::clone)
147 .ok_or(crate::server::Error::UnknownDeviceNumber {
148 ty: DynTrait::TYPE,
149 device_number,
150 })
151 }
152}
153
154impl Extend<TypedDevice> for Devices {
155 fn extend<T: IntoIterator<Item = TypedDevice>>(&mut self, iter: T) {
156 for client in iter {
157 self.register(client);
158 }
159 }
160}
161
162impl FromIterator<TypedDevice> for Devices {
163 fn from_iter<T: IntoIterator<Item = TypedDevice>>(iter: T) -> Self {
164 let mut devices = Self::default();
165 devices.extend(iter);
166 devices
167 }
168}