Changeset - cc23d3cb40d3
[Not reviewed]
0 5 0
Christopher Esterhuyse - 5 years ago 2020-02-05 17:54:35
christopheresterhuyse@gmail.com
natives working
5 files changed with 49 insertions and 22 deletions:
0 comments (0 inline, 0 general)
src/runtime/connector.rs
Show inline comments
 
@@ -12,71 +12,72 @@ impl Default for Unconfigured {
 
    fn default() -> Self {
 
        let controller_id = random_controller_id();
 
        Self { controller_id }
 
    }
 
}
 
impl Default for Connector {
 
    fn default() -> Self {
 
        Self::Unconfigured(Unconfigured::default())
 
    }
 
}
 
impl Connector {
 
    /// Configure the Connector with the given Pdl description.
 
    pub fn configure(&mut self, pdl: &[u8]) -> Result<(), ConfigErr> {
 
    pub fn configure(&mut self, pdl: &[u8], main_component: &[u8]) -> Result<(), ConfigErr> {
 
        use ConfigErr::*;
 
        let controller_id = match self {
 
            Connector::Configured(_) => return Err(AlreadyConfigured),
 
            Connector::Connected(_) => return Err(AlreadyConnected),
 
            Connector::Unconfigured(Unconfigured { controller_id }) => *controller_id,
 
        };
 
        let protocol_description = Arc::new(ProtocolD::parse(pdl).map_err(ParseErr)?);
 
        let configured =
 
            Configured { controller_id, protocol_description, bindings: Default::default() };
 
        let polarities = protocol_description.component_polarities(main_component)?;
 
        let configured = Configured {
 
            controller_id,
 
            protocol_description,
 
            bindings: Default::default(),
 
            polarities,
 
        };
 
        *self = Connector::Configured(configured);
 
        Ok(())
 
    }
 

	
 
    /// Bind the (configured) connector's port corresponding to the
 
    pub fn bind_port(
 
        &mut self,
 
        proto_port_index: usize,
 
        binding: PortBinding,
 
    ) -> Result<(), PortBindErr> {
 
        use PortBindErr::*;
 
        match self {
 
            Connector::Unconfigured { .. } => Err(NotConfigured),
 
            Connector::Connected(_) => Err(AlreadyConnected),
 
            Connector::Configured(configured) => {
 
                if configured.polarities.len() <= proto_port_index {
 
                    return Err(IndexOutOfBounds);
 
                }
 
                configured.bindings.insert(proto_port_index, binding);
 
                Ok(())
 
            }
 
        }
 
    }
 
    pub fn connect(&mut self, timeout: Duration) -> Result<(), ConnectErr> {
 
        let deadline = Instant::now() + timeout;
 
        use ConnectErr::*;
 
        let configured = match self {
 
            Connector::Unconfigured { .. } => return Err(NotConfigured),
 
            Connector::Connected(_) => return Err(AlreadyConnected),
 
            Connector::Configured(configured) => configured,
 
        };
 
        // 1. Unwrap bindings or err
 
        let mut bindings_vec = Vec::with_capacity(configured.bindings.len());
 
        for native_index in 0..configured.bindings.len() {
 
            let binding =
 
                configured.bindings.get(&native_index).ok_or(PortNotBound { native_index })?;
 
            bindings_vec.push(*binding);
 
        }
 
        let bound_proto_interface: Vec<(_, _)> = (0..num_bindings)
 
            .map(|i| configured.bindings.get())
 
        let bound_proto_interface: Vec<(_, _)> = configured
 
            .proto_maybe_bindings
 
            .iter()
 
            .copied()
 
            .enumerate()
 
            .map(|(native_index, (polarity, maybe_binding))| {
 
                Ok((maybe_binding.ok_or(PortNotBound { native_index })?, polarity))
 
            })
 
            .collect::<Result<Vec<(_, _)>, ConnectErr>>()?;
 
        let (controller, native_interface) = Controller::connect(
 
            configured.controller_id,
 
            configured.protocol_description.clone(),
 
            &bound_proto_interface[..],
src/runtime/errors.rs
Show inline comments
 
@@ -19,24 +19,26 @@ pub enum ReadGottenErr {
 
#[derive(Debug)]
 
pub enum PortOpErr {
 
    IndexOutOfBounds,
 
    NotConnected,
 
    WrongPolarity,
 
    DuplicateOperation,
 
}
 
#[derive(Debug)]
 
pub enum ConfigErr {
 
    AlreadyConnected,
 
    ParseErr(String),
 
    AlreadyConfigured,
 
    NoSuchComponent,
 
    NonPortTypeParameters,
 
}
 
#[derive(Debug, Clone)]
 
pub enum ConnectErr {
 
    PortNotBound { native_index: usize },
 
    NotConfigured,
 
    AlreadyConnected,
 
    MetaProtocolDeviation,
 
    Disconnected,
 
    PollInitFailed,
 
    MessengerRecvErr(MessengerRecvErr),
 
    Timeout,
 
    PollingFailed,
 
@@ -70,12 +72,22 @@ pub enum SyncErr {
 
    EndpointErr(EndpointErr),
 
    EvalErr(EvalErr),
 
}
 
#[derive(Debug, Clone)]
 
pub enum EvalErr {
 
    ComponentExitWhileBranching,
 
}
 
#[derive(Debug, Clone)]
 
pub enum MessengerRecvErr {
 
    PollingFailed,
 
    EndpointErr(EndpointErr),
 
}
 
impl From<MainComponentErr> for ConfigErr {
 
    fn from(e: MainComponentErr) -> Self {
 
        use ConfigErr as C;
 
        use MainComponentErr as M;
 
        match e {
 
            M::NoSuchComponent => C::NoSuchComponent,
 
            M::NonPortTypeParameters => C::NonPortTypeParameters,
 
        }
 
    }
 
}
src/runtime/ffi.rs
Show inline comments
 
@@ -101,32 +101,38 @@ pub extern "C" fn connector_new() -> *mut Connector {
 

	
 
/// Creates and returns Reowolf Connector structure allocated on the heap.
 
#[no_mangle]
 
pub extern "C" fn connector_with_controller_id(controller_id: ControllerId) -> *mut Connector {
 
    Box::into_raw(Box::new(Connector::Unconfigured(Unconfigured { controller_id })))
 
}
 

	
 
/// Configures the given Reowolf connector with a protocol description in PDL.
 
/// Returns:
 
/// # Safety
 
/// TODO
 
#[no_mangle]
 
pub unsafe extern "C" fn connector_configure(connector: *mut Connector, pdl: *mut c_char) -> c_int {
 
pub unsafe extern "C" fn connector_configure(
 
    connector: *mut Connector,
 
    pdl: *mut c_char,
 
    main: *mut c_char,
 
) -> c_int {
 
    let mut b = Box::from_raw(connector); // unsafe!
 
    let ret = as_rust_bytes(pdl, |pdl_bytes| match b.configure(pdl_bytes) {
 
        Ok(()) => 0,
 
        Err(e) => {
 
            overwrite_last_error(format!("{:?}", e).as_bytes());
 
            -1
 
        }
 
    let ret = as_rust_bytes(pdl, |pdl_bytes| {
 
        as_rust_bytes(main, |main_bytes| match b.configure(pdl_bytes, main_bytes) {
 
            Ok(()) => 0,
 
            Err(e) => {
 
                overwrite_last_error(format!("{:?}", e).as_bytes());
 
                -1
 
            }
 
        })
 
    });
 
    Box::into_raw(b); // don't drop!
 
    ret
 
}
 

	
 
/// Provides a binding annotation for the port with the given index with "native":
 
/// (The port is exposed for reading and writing from the application)
 
/// Returns:
 
/// # Safety
 
/// TODO
 
#[no_mangle]
 
pub unsafe extern "C" fn connector_bind_native(
src/runtime/mod.rs
Show inline comments
 
@@ -42,24 +42,25 @@ struct SyncBatch {
 
pub enum Connector {
 
    Unconfigured(Unconfigured),
 
    Configured(Configured),
 
    Connected(Connected), // TODO consider boxing. currently takes up a lot of stack real estate
 
}
 
#[derive(Debug)]
 
pub struct Unconfigured {
 
    pub controller_id: ControllerId,
 
}
 
#[derive(Debug)]
 
pub struct Configured {
 
    controller_id: ControllerId,
 
    polarities: Vec<Polarity>,
 
    bindings: HashMap<usize, PortBinding>,
 
    protocol_description: Arc<ProtocolD>,
 
}
 
#[derive(Debug)]
 
pub struct Connected {
 
    native_interface: Vec<(Key, Polarity)>,
 
    sync_batches: Vec<SyncBatch>,
 
    controller: Controller,
 
}
 

	
 
#[derive(Debug, Copy, Clone)]
 
pub enum PortBinding {
src/test/connector.rs
Show inline comments
 
@@ -14,52 +14,55 @@ fn next_addr() -> SocketAddr {
 
        net::{Ipv4Addr, SocketAddrV4},
 
        sync::atomic::{AtomicU16, Ordering::SeqCst},
 
    };
 
    static TEST_PORT: AtomicU16 = AtomicU16::new(7_000);
 
    let port = TEST_PORT.fetch_add(1, SeqCst);
 
    SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), port).into()
 
}
 

	
 
#[test]
 
fn incremental() {
 
    let timeout = Duration::from_millis(1_500);
 
    let addrs = [next_addr(), next_addr()];
 
    static PDL: &[u8] = b"";
 
    let handles = vec![
 
        thread::spawn(move || {
 
            let controller_id = 0;
 
            let mut x = Connector::Unconfigured(Unconfigured { controller_id });
 
            x.configure(
 
                b"primitive main(out a, out b) {
 
                    synchronous {
 
                        msg m = create(0);
 
                        put(a, m);
 
                    }
 
                }",
 
                b"main",
 
            )
 
            .unwrap();
 
            x.bind_port(0, Passive(addrs[0])).unwrap();
 
            x.bind_port(1, Passive(addrs[1])).unwrap();
 
            x.connect(timeout).unwrap();
 
            assert_eq!(0, x.sync(timeout).unwrap());
 
            println!("\n---------\nLOG CID={}\n{}", controller_id, x.get_mut_logger().unwrap());
 
        }),
 
        thread::spawn(move || {
 
            let controller_id = 1;
 
            let mut x = Connector::Unconfigured(Unconfigured { controller_id });
 
            x.configure(
 
                b"primitive main(in a, in b) {
 
                    synchronous {
 
                        get(a);
 
                    }
 
                }",
 
                b"main",
 
            )
 
            .unwrap();
 
            x.bind_port(0, Active(addrs[0])).unwrap();
 
            x.bind_port(1, Active(addrs[1])).unwrap();
 
            x.connect(timeout).unwrap();
 
            assert_eq!(0, x.sync(timeout).unwrap());
 
            println!("\n---------\nLOG CID={}\n{}", controller_id, x.get_mut_logger().unwrap());
 
        }),
 
    ];
 
    for h in handles {
 
        handle(h.join())
 
    }
 
@@ -76,24 +79,25 @@ fn duo_positive() {
 
            b"primitive main(out a, out b) {
 
                synchronous {}
 
                synchronous {}
 
                synchronous {
 
                    msg m = create(0);
 
                    put(a, m);
 
                }
 
                synchronous {
 
                    msg m = create(0);
 
                    put(b, m);
 
                }
 
            }",
 
            b"main",
 
        )
 
        .unwrap();
 
        x.bind_port(0, Passive(addrs[0])).unwrap();
 
        x.bind_port(1, Passive(addrs[1])).unwrap();
 
        x.connect(timeout).unwrap();
 
        assert_eq!(0, x.sync(timeout).unwrap());
 
        assert_eq!(0, x.sync(timeout).unwrap());
 
        assert_eq!(0, x.sync(timeout).unwrap());
 
        assert_eq!(0, x.sync(timeout).unwrap());
 
        println!("\n---------\nLOG CID={}\n{}", controller_id, x.get_mut_logger().unwrap());
 
    });
 
    let b = thread::spawn(move || {
 
@@ -105,24 +109,25 @@ fn duo_positive() {
 
                    synchronous {
 
                        if (fires(a)) {
 
                            get(a);
 
                        }
 
                    }
 
                    synchronous {
 
                        if (fires(b)) {
 
                            get(b);
 
                        }
 
                    }
 
                }
 
            }",
 
            b"main",
 
        )
 
        .unwrap();
 
        x.bind_port(0, Active(addrs[0])).unwrap();
 
        x.bind_port(1, Active(addrs[1])).unwrap();
 
        x.connect(timeout).unwrap();
 
        assert_eq!(0, x.sync(timeout).unwrap());
 
        assert_eq!(0, x.sync(timeout).unwrap());
 
        assert_eq!(0, x.sync(timeout).unwrap());
 
        assert_eq!(0, x.sync(timeout).unwrap());
 
        println!("\n---------\nLOG CID={}\n{}", controller_id, x.get_mut_logger().unwrap());
 
    });
 
    handle(a.join());
 
@@ -135,24 +140,25 @@ fn duo_negative() {
 
    let addrs = [next_addr(), next_addr()];
 
    let a = thread::spawn(move || {
 
        let controller_id = 0;
 
        let mut x = Connector::Unconfigured(Unconfigured { controller_id });
 
        x.configure(
 
            b"primitive main(out a, out b) {
 
                synchronous {}
 
                synchronous {
 
                    msg m = create(0);
 
                    put(a, m); // fires a on second round
 
                }
 
            }",
 
            b"main",
 
        )
 
        .unwrap();
 
        x.bind_port(0, Passive(addrs[0])).unwrap();
 
        x.bind_port(1, Passive(addrs[1])).unwrap();
 
        x.connect(timeout).unwrap();
 
        assert_eq!(0, x.sync(timeout).unwrap());
 
        let r = x.sync(timeout);
 
        println!("\n---------\nLOG CID={}\n{}", controller_id, x.get_mut_logger().unwrap());
 
        match r {
 
            Err(SyncErr::Timeout) => {}
 
            x => unreachable!("{:?}", x),
 
        }
 
@@ -166,24 +172,25 @@ fn duo_negative() {
 
                    synchronous {
 
                        if (fires(a)) {
 
                            get(a);
 
                        }
 
                    }
 
                    synchronous {
 
                        if (fires(b)) { // never fire a on even round
 
                            get(b);
 
                        }
 
                    }
 
                }
 
            }",
 
            b"main",
 
        )
 
        .unwrap();
 
        x.bind_port(0, Active(addrs[0])).unwrap();
 
        x.bind_port(1, Active(addrs[1])).unwrap();
 
        x.connect(timeout).unwrap();
 
        assert_eq!(0, x.sync(timeout).unwrap());
 
        let r = x.sync(timeout);
 
        println!("\n---------\nLOG CID={}\n{}", controller_id, x.get_mut_logger().unwrap());
 
        match r {
 
            Err(SyncErr::Timeout) => {}
 
            x => unreachable!("{:?}", x),
 
        }
 
@@ -193,63 +200,63 @@ fn duo_negative() {
 
}
 

	
 
#[test]
 
fn connect_natives() {
 
    static CHAIN: &[u8] = b"
 
    primitive main(in i, out o) {
 
        while(true) synchronous {}
 
    }";
 
    let timeout = Duration::from_millis(1_500);
 
    let addrs = [next_addr()];
 
    do_all(&[
 
        &|x| {
 
            x.configure(CHAIN).unwrap();
 
            x.configure(CHAIN, b"main").unwrap();
 
            x.bind_port(0, Native).unwrap();
 
            x.bind_port(1, Passive(addrs[0])).unwrap();
 
            x.connect(timeout).unwrap();
 
            assert_eq!(0, x.sync(timeout).unwrap());
 
        },
 
        &|x| {
 
            x.configure(CHAIN).unwrap();
 
            x.configure(CHAIN, b"main").unwrap();
 
            x.bind_port(0, Active(addrs[0])).unwrap();
 
            x.bind_port(1, Native).unwrap();
 
            x.connect(timeout).unwrap();
 
            assert_eq!(0, x.sync(timeout).unwrap());
 
        },
 
    ]);
 
}
 

	
 
#[test]
 
fn forward() {
 
    static FORWARD: &[u8] = b"
 
    primitive main(in i, out o) {
 
        while(true) synchronous {
 
            put(o, get(i));
 
        }
 
    }";
 
    let timeout = Duration::from_millis(1_500);
 
    let addrs = [next_addr()];
 
    do_all(&[
 
        //
 
        &|x| {
 
            x.configure(FORWARD).unwrap();
 
            x.configure(FORWARD, b"main").unwrap();
 
            x.bind_port(0, Native).unwrap();
 
            x.bind_port(1, Passive(addrs[0])).unwrap();
 
            x.connect(timeout).unwrap();
 

	
 
            let msg = b"HELLO!".to_vec();
 
            x.put(0, msg).unwrap();
 
            assert_eq!(0, x.sync(timeout).unwrap());
 
        },
 
        &|x| {
 
            x.configure(FORWARD).unwrap();
 
            x.configure(FORWARD, b"main").unwrap();
 
            x.bind_port(0, Active(addrs[0])).unwrap();
 
            x.bind_port(1, Native).unwrap();
 
            x.connect(timeout).unwrap();
 

	
 
            let expect = b"HELLO!".to_vec();
 
            x.get(0).unwrap();
 
            assert_eq!(0, x.sync(timeout).unwrap());
 
            assert_eq!(expect, x.read_gotten(0).unwrap());
 
        },
 
    ]);
 
}
0 comments (0 inline, 0 general)