1pub use tokio;
154
155use quick_xml::events::attributes::AttrError;
156use serde::Deserialize;
157use serde::Serialize;
158
159use std::borrow::Cow;
160
161use std::num;
162
163use std::str;
164use std::sync::Arc;
165
166use chrono::format::ParseError;
167use chrono::prelude::*;
168use std::str::FromStr;
169
170use std::collections::HashMap;
171
172pub static INDI_PROTOCOL_VERSION: &str = "1.7";
173
174pub mod serialization;
175use serialization::*;
176
177pub mod client;
178pub mod telescope;
179
180#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize)]
181pub enum PropertyState {
182 Idle,
183 Ok,
184 Busy,
185 Alert,
186}
187
188#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize)]
189pub enum SwitchState {
190 On,
191 Off,
192}
193
194impl From<bool> for SwitchState {
195 fn from(value: bool) -> Self {
196 match value {
197 true => SwitchState::On,
198 false => SwitchState::Off,
199 }
200 }
201}
202#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize)]
203pub enum SwitchRule {
204 OneOfMany,
205 AtMostOne,
206 AnyOfMany,
207}
208
209#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize)]
210pub enum PropertyPerm {
211 #[serde(rename = "ro")]
212 RO,
213 #[serde(rename = "wo")]
214 WO,
215 #[serde(rename = "rw")]
216 RW,
217}
218
219#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize)]
220pub enum BlobEnable {
221 Never,
222 Also,
223 Only,
224}
225
226pub trait FromParamValue {
227 fn values_from(w: &Parameter) -> Result<&Self, TypeError>
228 where
229 Self: Sized;
230}
231
232#[derive(Debug, PartialEq, Clone)]
233pub struct Switch {
234 pub label: Option<String>,
235 pub value: SwitchState,
236}
237
238impl Into<SwitchState> for Switch {
239 fn into(self) -> SwitchState {
240 self.value
241 }
242}
243
244#[derive(Debug, PartialEq, Clone)]
245pub struct SwitchVector {
246 pub name: String,
247 pub group: Option<String>,
248 pub label: Option<String>,
249 pub state: PropertyState,
250 pub perm: PropertyPerm,
251 pub rule: SwitchRule,
252 pub timeout: Option<u32>,
253 pub timestamp: Option<DateTime<Utc>>,
254
255 pub values: HashMap<String, Switch>,
256}
257
258impl FromParamValue for HashMap<String, Switch> {
259 fn values_from(p: &Parameter) -> Result<&Self, TypeError> {
260 match p {
261 Parameter::SwitchVector(p) => Ok(&p.values),
262 _ => Err(TypeError::TypeMismatch),
263 }
264 }
265}
266
267#[derive(Debug, PartialEq, Clone)]
268pub struct Number {
269 pub label: Option<String>,
270 pub format: String,
271 pub min: f64,
272 pub max: f64,
273 pub step: f64,
274 pub value: Sexagesimal,
275}
276
277impl Into<Sexagesimal> for Number {
278 fn into(self) -> Sexagesimal {
279 self.value
280 }
281}
282
283#[derive(Debug, PartialEq, Clone)]
284pub struct NumberVector {
285 pub name: String,
286 pub group: Option<String>,
287 pub label: Option<String>,
288 pub state: PropertyState,
289 pub perm: PropertyPerm,
290 pub timeout: Option<u32>,
291 pub timestamp: Option<DateTime<Utc>>,
292
293 pub values: HashMap<String, Number>,
294}
295
296impl FromParamValue for HashMap<String, Number> {
297 fn values_from(p: &Parameter) -> Result<&Self, TypeError> {
298 match p {
299 Parameter::NumberVector(p) => Ok(&p.values),
300 _ => Err(TypeError::TypeMismatch),
301 }
302 }
303}
304
305#[derive(Debug, PartialEq, Clone)]
306pub struct Light {
307 pub label: Option<String>,
308 pub value: PropertyState,
309}
310
311#[derive(Debug, PartialEq, Clone)]
312pub struct LightVector {
313 pub name: String,
314 pub label: Option<String>,
315 pub group: Option<String>,
316 pub state: PropertyState,
317 pub timestamp: Option<DateTime<Utc>>,
318
319 pub values: HashMap<String, Light>,
320}
321
322impl FromParamValue for HashMap<String, Light> {
323 fn values_from(p: &Parameter) -> Result<&Self, TypeError> {
324 match p {
325 Parameter::LightVector(p) => Ok(&p.values),
326 _ => Err(TypeError::TypeMismatch),
327 }
328 }
329}
330
331#[derive(Debug, PartialEq, Clone)]
332pub struct Text {
333 pub label: Option<String>,
334 pub value: String,
335}
336
337impl FromParamValue for HashMap<String, Text> {
338 fn values_from(p: &Parameter) -> Result<&Self, TypeError> {
339 match p {
340 Parameter::TextVector(p) => Ok(&p.values),
341 _ => Err(TypeError::TypeMismatch),
342 }
343 }
344}
345
346#[derive(Debug, PartialEq, Clone)]
347pub struct TextVector {
348 pub name: String,
349 pub group: Option<String>,
350 pub label: Option<String>,
351
352 pub state: PropertyState,
353 pub perm: PropertyPerm,
354 pub timeout: Option<u32>,
355 pub timestamp: Option<DateTime<Utc>>,
356
357 pub values: HashMap<String, Text>,
358}
359
360#[derive(Debug, PartialEq, Clone)]
361pub struct Blob {
362 pub label: Option<String>,
363 pub format: Option<String>,
364 pub value: Option<Arc<Vec<u8>>>,
365}
366
367#[derive(Debug, PartialEq, Clone)]
368pub struct BlobVector {
369 pub name: String,
370 pub label: Option<String>,
371 pub group: Option<String>,
372 pub state: PropertyState,
373 pub perm: PropertyPerm,
374 pub timeout: Option<u32>,
375 pub timestamp: Option<DateTime<Utc>>,
376
377 pub values: HashMap<String, Blob>,
378}
379
380impl FromParamValue for HashMap<String, Blob> {
381 fn values_from(p: &Parameter) -> Result<&Self, TypeError> {
382 match p {
383 Parameter::BlobVector(p) => Ok(&p.values),
384 _ => Err(TypeError::TypeMismatch),
385 }
386 }
387}
388
389#[derive(Debug, PartialEq, Clone)]
390pub enum Parameter {
391 TextVector(TextVector),
392 NumberVector(NumberVector),
393 SwitchVector(SwitchVector),
394 LightVector(LightVector),
395 BlobVector(BlobVector),
396}
397
398impl Parameter {
399 pub fn get_group(&self) -> &Option<String> {
400 match self {
401 Parameter::TextVector(p) => &p.group,
402 Parameter::NumberVector(p) => &p.group,
403 Parameter::SwitchVector(p) => &p.group,
404 Parameter::LightVector(p) => &p.group,
405 Parameter::BlobVector(p) => &p.group,
406 }
407 }
408
409 pub fn get_name(&self) -> &String {
410 match self {
411 Parameter::TextVector(p) => &p.name,
412 Parameter::NumberVector(p) => &p.name,
413 Parameter::SwitchVector(p) => &p.name,
414 Parameter::LightVector(p) => &p.name,
415 Parameter::BlobVector(p) => &p.name,
416 }
417 }
418 pub fn get_label(&self) -> &Option<String> {
419 match self {
420 Parameter::TextVector(p) => &p.label,
421 Parameter::NumberVector(p) => &p.label,
422 Parameter::SwitchVector(p) => &p.label,
423 Parameter::LightVector(p) => &p.label,
424 Parameter::BlobVector(p) => &p.label,
425 }
426 }
427 pub fn get_label_display(&self) -> &String {
428 match self.get_label() {
429 Some(label) => label,
430 None => self.get_name(),
431 }
432 }
433 pub fn get_state(&self) -> &PropertyState {
434 match self {
435 Parameter::TextVector(p) => &p.state,
436 Parameter::NumberVector(p) => &p.state,
437 Parameter::SwitchVector(p) => &p.state,
438 Parameter::LightVector(p) => &p.state,
439 Parameter::BlobVector(p) => &p.state,
440 }
441 }
442 pub fn get_timeout(&self) -> &Option<u32> {
443 match self {
444 Parameter::TextVector(p) => &p.timeout,
445 Parameter::NumberVector(p) => &p.timeout,
446 Parameter::SwitchVector(p) => &p.timeout,
447 Parameter::LightVector(_) => &None,
448 Parameter::BlobVector(p) => &p.timeout,
449 }
450 }
451
452 pub fn get_values<T: FromParamValue>(&self) -> Result<&T, TypeError> {
453 T::values_from(self)
454 }
455}
456
457#[derive(Debug)]
458pub enum TypeError {
459 TypeMismatch,
460}
461pub trait TryEq<T> {
462 fn try_eq(&self, other: &T) -> Result<bool, TypeError>;
463}
464
465impl TryEq<Parameter> for Vec<OneSwitch> {
466 fn try_eq(&self, other: &Parameter) -> Result<bool, TypeError> {
467 let current_values = other.get_values::<HashMap<String, Switch>>()?;
468
469 Ok(self.iter().all(|other_value| {
470 Some(other_value.value) == current_values.get(&other_value.name).map(|x| x.value)
471 }))
472 }
473}
474
475impl<I: Into<SwitchState> + Copy> TryEq<Parameter> for Vec<(&str, I)> {
476 fn try_eq(&self, other: &Parameter) -> Result<bool, TypeError> {
477 let current_values = other.get_values::<HashMap<String, Switch>>()?;
478
479 Ok(self.iter().all(|other_value| {
480 Some(other_value.1.into()) == current_values.get(other_value.0).map(|x| x.value)
481 }))
482 }
483}
484
485impl TryEq<Parameter> for Vec<(&str, f64)> {
486 fn try_eq(&self, other: &Parameter) -> Result<bool, TypeError> {
487 let current_values = other.get_values::<HashMap<String, Number>>()?;
488
489 Ok(self.iter().all(|other_value| {
490 Some(other_value.1) == current_values.get(other_value.0).map(|x| x.value.into())
491 }))
492 }
493}
494
495impl TryEq<Parameter> for Vec<(&str, Sexagesimal)> {
496 fn try_eq(&self, other: &Parameter) -> Result<bool, TypeError> {
497 let current_values = other.get_values::<HashMap<String, Number>>()?;
498
499 Ok(self.iter().all(|other_value| {
500 Some(other_value.1) == current_values.get(other_value.0).map(|x| x.value.into())
501 }))
502 }
503}
504
505impl TryEq<Parameter> for Vec<OneNumber> {
506 fn try_eq(&self, other: &Parameter) -> Result<bool, TypeError> {
507 let current_values = other.get_values::<HashMap<String, Number>>()?;
508
509 Ok(self.iter().all(|other_value| {
510 Some(other_value.value) == current_values.get(&other_value.name).map(|x| x.value)
511 }))
512 }
513}
514
515impl TryEq<Parameter> for Vec<(&str, &str)> {
516 fn try_eq(&self, other: &Parameter) -> Result<bool, TypeError> {
517 let current_values = other.get_values::<HashMap<String, Text>>()?;
518
519 Ok(self.iter().all(|other_value| {
520 Some(other_value.1) == current_values.get(other_value.0).map(|x| x.value.as_str())
521 }))
522 }
523}
524
525impl TryEq<Parameter> for Vec<OneText> {
526 fn try_eq(&self, other: &Parameter) -> Result<bool, TypeError> {
527 let current_values = other.get_values::<HashMap<String, Text>>()?;
528
529 Ok(self.iter().all(|other_value| {
530 Some(&other_value.value) == current_values.get(&other_value.name).map(|x| &x.value)
531 }))
532 }
533}