autd3-driver 38.1.0

AUTD3 driver
Documentation
use std::{fmt::Debug, hash::Hash};

use crate::{datagram::GroupOpGenerator, firmware::operation::OperationGenerator};

use autd3_core::geometry::Device;

impl<'a, K, F, G> OperationGenerator<'a> for GroupOpGenerator<K, F, G>
where
    K: Hash + Eq + Debug,
    F: Fn(&Device) -> Option<K>,
    G: OperationGenerator<'a>,
{
    type O1 = <G as OperationGenerator<'a>>::O1;
    type O2 = <G as OperationGenerator<'a>>::O2;

    fn generate(&mut self, device: &'a Device) -> Option<(Self::O1, Self::O2)> {
        let key = (self.key_map)(device)?;
        self.generators
            .get_mut(&key)
            .and_then(|g| g.generate(device))
    }
}

#[cfg(test)]
mod tests {
    use std::{
        collections::HashMap,
        convert::Infallible,
        sync::{Arc, Mutex},
        time::Duration,
    };

    use super::*;
    use crate::{datagram::Group, firmware::operation::implement::null::NullOp};

    use autd3_core::{
        datagram::{Datagram, DatagramOption, DeviceMask, Inspectable, InspectionResult},
        environment::Environment,
        geometry::Geometry,
    };

    #[derive(Debug, Default)]
    pub struct TestDatagram {
        pub test: Arc<Mutex<Vec<bool>>>,
        pub option: DatagramOption,
    }

    impl Datagram<'_> for TestDatagram {
        type G = NullOp;
        type Error = Infallible;

        fn operation_generator(
            self,
            geometry: &Geometry,
            _: &Environment,
            filter: &DeviceMask,
        ) -> Result<Self::G, Self::Error> {
            geometry.iter().for_each(|dev| {
                self.test.lock().unwrap()[dev.idx()] = filter.is_enabled(dev);
            });
            Ok(NullOp)
        }

        fn option(&self) -> DatagramOption {
            self.option
        }
    }

    impl Inspectable<'_> for TestDatagram {
        type Result = ();

        fn inspect(
            self,
            geometry: &Geometry,
            _: &Environment,
            filter: &DeviceMask,
        ) -> Result<InspectionResult<Self::Result>, Self::Error> {
            Ok(InspectionResult::new(geometry, filter, |_| ()))
        }
    }

    #[test]
    fn option() -> Result<(), Box<dyn std::error::Error>> {
        let option1 = DatagramOption {
            timeout: Duration::from_secs(1),
            parallel_threshold: 10,
        };
        let option2 = DatagramOption {
            timeout: Duration::from_secs(2),
            parallel_threshold: 5,
        };

        assert_eq!(
            option1.merge(option2),
            Group::new(
                |_dev| unreachable!(),
                HashMap::from([
                    (
                        0,
                        TestDatagram {
                            option: option1,
                            ..Default::default()
                        }
                    ),
                    (
                        1,
                        TestDatagram {
                            option: option2,
                            ..Default::default()
                        }
                    ),
                ]),
            )
            .option()
        );

        Ok(())
    }

    #[test]
    fn op() -> Result<(), Box<dyn std::error::Error>> {
        let geometry = crate::tests::create_geometry(3);

        let test = Arc::new(Mutex::new(vec![false; 3]));
        Group::new(
            |dev| match dev.idx() {
                0 | 2 => Some(()),
                _ => None,
            },
            HashMap::from([(
                (),
                TestDatagram {
                    test: test.clone(),
                    option: DatagramOption::default(),
                },
            )]),
        )
        .operation_generator(
            &geometry,
            &Environment::default(),
            &DeviceMask::AllEnabled,
        )?;

        assert!(test.lock().unwrap()[0]);
        assert!(!test.lock().unwrap()[1]);
        assert!(test.lock().unwrap()[2]);

        Ok(())
    }

    #[test]
    fn inspect() -> Result<(), Box<dyn std::error::Error>> {
        let geometry = crate::tests::create_geometry(4);
        let r = Group::new(
            |dev| match dev.idx() {
                1 => None,
                _ => Some(()),
            },
            HashMap::from([((), TestDatagram::default())]),
        )
        .inspect(&geometry, &Environment::default(), &DeviceMask::AllEnabled)?;

        assert!(r[0].is_some());
        assert!(r[1].is_none());
        assert!(r[2].is_some());
        assert!(r[3].is_some());

        Ok(())
    }
}