1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
use std::future::Future;
use std::{ops::Deref, pin::Pin, sync::Arc};

#[cfg(feature = "futures")]
use futures_io::{AsyncRead, AsyncWrite};

#[cfg(feature = "tokio")]
use tokio::io::{AsyncRead, AsyncWrite};

#[cfg(feature = "async-std")]
use async_std::io::{Read as AsyncRead, Write as AsyncWrite};

use crate::{Result, Url};

/// Boxed connection
pub type BoxedConnection = Box<dyn Connection>;

/// The establishing connection between backend and device
pub type BoxedConnect = Pin<Box<dyn Connect>>;

/// Unified connector object
pub type BoxedConnector = Arc<dyn Connector>;

/// Unified backend object
pub type BoxedBackend = Box<dyn Backend>;

/// The establishing connect between backend and device
pub trait Connect: Future<Output = Result<BoxedConnection>> + Send {}
impl<T> Connect for T where T: Future<Output = Result<BoxedConnection>> + Send {}

/// The established connection between backend and device
pub trait Connection: AsyncRead + AsyncWrite + Send + Unpin {}
impl<T> Connection for T where T: AsyncRead + AsyncWrite + Send + Unpin {}

/// Backend connector interface
pub trait Connector: Send + Sync {
    /// Get device URL
    fn url(&self) -> &Url;

    /// Establish connection to device
    fn connect(&self) -> BoxedConnect;
}

/// Backend interface
pub trait Backend {
    /// The name of backend
    ///
    /// Examples: tcp, serial.
    fn name(&self) -> &str;

    /// The backend description
    fn description(&self) -> &str;

    /// Create connector
    ///
    /// This method should check URL and extract connection options from it.
    ///
    /// Method returns connector instance when URL is compatible with backend.
    fn connector(&self, url: &Url) -> Option<BoxedConnector>;
}

impl<T> Backend for T
where
    T: Deref<Target = dyn Backend>,
{
    fn name(&self) -> &str {
        self.deref().name()
    }
    fn description(&self) -> &str {
        self.deref().description()
    }
    fn connector(&self, url: &Url) -> Option<BoxedConnector> {
        self.deref().connector(url)
    }
}