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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/*
 * File: mod.rs
 * Project: datagram
 * Created Date: 29/09/2023
 * Author: Shun Suzuki
 * -----
 * Last Modified: 26/12/2023
 * Modified By: Shun Suzuki (suzuki@hapis.k.u-tokyo.ac.jp)
 * -----
 * Copyright (c) 2023 Shun Suzuki. All rights reserved.
 *
 */

mod clear;
mod debug;
mod force_fan;
mod gain;
mod mod_delay;
mod modulation;
mod reads_fpga_info;
mod silencer;
mod stm;
mod synchronize;
mod with_timeout;

pub use clear::Clear;
pub use debug::ConfigureDebugOutputIdx;
pub use force_fan::ConfigureForceFan;
pub use gain::{Gain, GainAsAny, GainFilter};
pub use mod_delay::ConfigureModDelay;
pub use modulation::{Modulation, ModulationProperty};
pub use reads_fpga_info::ConfigureReadsFPGAInfo;
pub use silencer::ConfigureSilencer;
pub use stm::{FocusSTM, GainSTM, STMProps};
pub use synchronize::Synchronize;
pub use with_timeout::{DatagramT, DatagramWithTimeout};

use std::time::Duration;

use crate::{error::AUTDInternalError, operation::Operation};

/// Datagram to be sent to devices
pub trait Datagram {
    type O1: Operation;
    type O2: Operation;

    fn operation(self) -> Result<(Self::O1, Self::O2), AUTDInternalError>;

    fn timeout(&self) -> Option<Duration> {
        None
    }
}

impl<D1, D2> Datagram for (D1, D2)
where
    D1: Datagram<O2 = crate::operation::NullOp>,
    D2: Datagram<O2 = crate::operation::NullOp>,
{
    type O1 = D1::O1;
    type O2 = D2::O1;

    fn operation(self) -> Result<(Self::O1, Self::O2), AUTDInternalError> {
        let (o1, _) = self.0.operation()?;
        let (o2, _) = self.1.operation()?;
        Ok((o1, o2))
    }
}

#[cfg(test)]
mod tests {
    use crate::operation::{ClearOp, NullOp};

    use super::*;

    struct TestDatagram1 {
        pub err: bool,
    }
    impl Datagram for TestDatagram1 {
        type O1 = ClearOp;
        type O2 = NullOp;

        fn operation(self) -> Result<(Self::O1, Self::O2), AUTDInternalError> {
            if self.err {
                Err(AUTDInternalError::NotSupported("Err1".to_owned()))
            } else {
                Ok((Self::O1::default(), Self::O2::default()))
            }
        }
    }

    struct TestDatagram2 {
        pub err: bool,
    }
    impl Datagram for TestDatagram2 {
        type O1 = NullOp;
        type O2 = NullOp;

        fn operation(self) -> Result<(Self::O1, Self::O2), AUTDInternalError> {
            if self.err {
                Err(AUTDInternalError::NotSupported("Err2".to_owned()))
            } else {
                Ok((Self::O1::default(), Self::O2::default()))
            }
        }
    }

    #[test]
    fn test_datagram_tuple() {
        let d = (TestDatagram1 { err: false }, TestDatagram2 { err: false });
        let _: (ClearOp, NullOp) =
            <(TestDatagram1, TestDatagram2) as Datagram>::operation(d).unwrap();
    }

    #[test]
    fn test_datagram_tuple_err() {
        let d1 = (TestDatagram1 { err: true }, TestDatagram2 { err: false });
        let r = <(TestDatagram1, TestDatagram2) as Datagram>::operation(d1);
        assert!(r.is_err());

        let d2 = (TestDatagram1 { err: false }, TestDatagram2 { err: true });
        let r = <(TestDatagram1, TestDatagram2) as Datagram>::operation(d2);
        assert!(r.is_err());
    }
}