Changeset - 3f0b1a4ef61f
[Not reviewed]
0 3 0
Christopher Esterhuyse - 5 years ago 2020-02-05 17:11:01
christopheresterhuyse@gmail.com
api change
3 files changed with 33 insertions and 24 deletions:
0 comments (0 inline, 0 general)
src/common.rs
Show inline comments
 
///////////////////// PRELUDE /////////////////////
 

	
 
pub use core::{
 
    cmp::Ordering,
 
    fmt::Debug,
 
    hash::{Hash, Hasher},
 
    ops::{Range, RangeFrom},
 
    time::Duration,
 
};
 
pub use indexmap::{IndexMap, IndexSet};
 
pub use maplit::{hashmap, hashset};
 
pub use mio::{
 
    net::{TcpListener, TcpStream},
 
    Event, Evented, Events, Poll, PollOpt, Ready, Token,
 
};
 
pub use std::{
 
    collections::{hash_map::Entry, BTreeMap, HashMap, HashSet},
 
    convert::TryInto,
 
    net::SocketAddr,
 
    sync::Arc,
 
    time::Instant,
 
};
 
pub use Polarity::*;
 

	
 
///////////////////// DEFS /////////////////////
 

	
 
pub type Payload = Vec<u8>;
 
pub type ControllerId = u32;
 
pub type ChannelIndex = u32;
 

	
 
/// This is a unique identifier for a channel (i.e., port).
 
#[derive(Debug, Eq, PartialEq, Clone, Hash, Copy, Ord, PartialOrd)]
 
pub struct ChannelId {
 
    pub(crate) controller_id: ControllerId,
 
    pub(crate) channel_index: ChannelIndex,
 
}
 

	
 
#[derive(Debug, Eq, PartialEq, Clone, Hash, Copy, Ord, PartialOrd)]
 
pub enum Polarity {
 
    Putter, // output port (from the perspective of the component)
 
    Getter, // input port (from the perspective of the component)
 
}
 

	
 
#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Copy, Clone, Debug)]
 
pub struct Key(u64);
 

	
 
pub enum NewMainErr {
 
    NoSuchComponent,
 
    NonPortTypeParameters,
 
    WrongNumberOfArguments { expected: usize },
 
    WrongPortPolarity { index: usize },
 
}
 
pub trait ProtocolDescription: Sized {
 
    type S: ComponentState<D = Self>;
 

	
 
    fn parse(pdl: &[u8]) -> Result<Self, String>;
 
    fn main_interface_polarities(&self) -> Vec<Polarity>;
 
    fn new_main_component(&self, interface: &[Key]) -> Self::S;
 
    fn new_main_component(
 
        &self,
 
        identifier: &[u8],
 
        ports: &[(Polarity, Key)],
 
    ) -> Result<Self::S, NewMainErr>;
 
}
 

	
 
pub trait ComponentState: Sized + Clone {
 
    type D: ProtocolDescription;
 
    fn pre_sync_run<C: MonoContext<D = Self::D, S = Self>>(
 
        &mut self,
 
        runtime_ctx: &mut C,
 
        protocol_description: &Self::D,
 
    ) -> MonoBlocker;
 

	
 
    fn sync_run<C: PolyContext<D = Self::D>>(
 
        &mut self,
 
        runtime_ctx: &mut C,
 
        protocol_description: &Self::D,
 
    ) -> PolyBlocker;
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub enum MonoBlocker {
 
    Inconsistent,
 
    ComponentExit,
 
    SyncBlockStart,
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub enum PolyBlocker {
 
    Inconsistent,
 
    SyncBlockEnd,
 
    CouldntReadMsg(Key),
 
    CouldntCheckFiring(Key),
 
    PutMsg(Key, Payload),
 
}
 

	
 
pub trait MonoContext {
 
    type D: ProtocolDescription;
 
    type S: ComponentState<D = Self::D>;
 

	
 
    fn new_component(&mut self, moved_keys: HashSet<Key>, init_state: Self::S);
 
    fn new_channel(&mut self) -> [Key; 2];
 
    fn new_random(&mut self) -> u64;
 
}
 
pub trait PolyContext {
 
    type D: ProtocolDescription;
 

	
 
    fn is_firing(&mut self, ekey: Key) -> Option<bool>;
 
    fn read_msg(&mut self, ekey: Key) -> Option<&Payload>;
 
}
 

	
src/protocol/mod.rs
Show inline comments
 
@@ -2,116 +2,116 @@ mod ast;
 
mod eval;
 
pub mod inputsource;
 
mod lexer;
 
mod library;
 
mod parser;
 

	
 
use crate::common::*;
 
use crate::protocol::ast::*;
 
use crate::protocol::eval::*;
 
use crate::protocol::inputsource::*;
 
use crate::protocol::parser::*;
 
use std::hint::unreachable_unchecked;
 

	
 
pub struct ProtocolDescriptionImpl {
 
    heap: Heap,
 
    source: InputSource,
 
    root: RootId,
 
    main: ComponentId,
 
}
 

	
 
impl std::fmt::Debug for ProtocolDescriptionImpl {
 
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
 
        write!(f, "Protocol")
 
    }
 
}
 

	
 
impl ProtocolDescription for ProtocolDescriptionImpl {
 
    type S = ComponentStateImpl;
 

	
 
    fn parse(buffer: &[u8]) -> Result<Self, String> {
 
        let mut heap = Heap::new();
 
        let mut source = InputSource::from_buffer(buffer).unwrap();
 
        let mut parser = Parser::new(&mut source);
 
        match parser.parse(&mut heap) {
 
            Ok(root) => {
 
                // Find main definition (grammar rule ensures this exists)
 
                let sym = heap.get_external_identifier(b"main");
 
                let def = heap[root].get_definition(&heap, sym.upcast()).unwrap();
 
                let main = heap[def].as_component().this();
 
                return Ok(ProtocolDescriptionImpl { heap, source, root, main });
 
            }
 
            Err(err) => {
 
                let mut vec: Vec<u8> = Vec::new();
 
                err.write(&source, &mut vec).unwrap();
 
                Err(String::from_utf8_lossy(&vec).to_string())
 
            }
 
        }
 
    }
 
    fn main_interface_polarities(&self) -> Vec<Polarity> {
 
        let def = &self.heap[self.main];
 
        let mut result = Vec::new();
 
        for &param in def.parameters().iter() {
 
            let param = &self.heap[param];
 
            let type_annot = &self.heap[param.type_annotation];
 
            let ptype = &type_annot.the_type.primitive;
 
            if ptype == &PrimitiveType::Input {
 
                result.push(Polarity::Getter)
 
            } else if ptype == &PrimitiveType::Output {
 
                result.push(Polarity::Putter)
 
            } else {
 
                unreachable!()
 
            }
 
        }
 
        result
 
    }
 
    fn new_main_component(&self, interface: &[Key]) -> ComponentStateImpl {
 
    // fn main_interface_polarities(&self) -> Vec<Polarity> {
 
    //     let def = &self.heap[self.main];
 
    //     let mut result = Vec::new();
 
    //     for &param in def.parameters().iter() {
 
    //         let param = &self.heap[param];
 
    //         let type_annot = &self.heap[param.type_annotation];
 
    //         let ptype = &type_annot.the_type.primitive;
 
    //         if ptype == &PrimitiveType::Input {
 
    //             result.push(Polarity::Getter)
 
    //         } else if ptype == &PrimitiveType::Output {
 
    //             result.push(Polarity::Putter)
 
    //         } else {
 
    //             unreachable!()
 
    //         }
 
    //     }
 
    //     result
 
    // }
 
    fn new_main_component(&self, ports: &[Key]) -> ComponentStateImpl {
 
        let mut args = Vec::new();
 
        for (&x, y) in interface.iter().zip(self.main_interface_polarities()) {
 
        for (&x, y) in ports.iter().zip(self.main_interface_polarities()) {
 
            match y {
 
                Polarity::Getter => args.push(Value::Input(InputValue(x))),
 
                Polarity::Putter => args.push(Value::Output(OutputValue(x))),
 
            }
 
        }
 
        ComponentStateImpl { prompt: Prompt::new(&self.heap, self.main.upcast(), &args) }
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct ComponentStateImpl {
 
    prompt: Prompt,
 
}
 
impl ComponentState for ComponentStateImpl {
 
    type D = ProtocolDescriptionImpl;
 

	
 
    fn pre_sync_run<C: MonoContext<D = ProtocolDescriptionImpl, S = Self>>(
 
        &mut self,
 
        context: &mut C,
 
        pd: &ProtocolDescriptionImpl,
 
    ) -> MonoBlocker {
 
        let mut context = EvalContext::Mono(context);
 
        loop {
 
            let result = self.prompt.step(&pd.heap, &mut context);
 
            match result {
 
                // In component definitions, there are no return statements
 
                Ok(_) => unreachable!(),
 
                Err(cont) => match cont {
 
                    EvalContinuation::Stepping => continue,
 
                    EvalContinuation::Inconsistent => return MonoBlocker::Inconsistent,
 
                    EvalContinuation::Terminal => return MonoBlocker::ComponentExit,
 
                    EvalContinuation::SyncBlockStart => return MonoBlocker::SyncBlockStart,
 
                    // Not possible to end sync block if never entered one
 
                    EvalContinuation::SyncBlockEnd => unreachable!(),
 
                    EvalContinuation::NewComponent(args) => {
 
                        todo!();
 
                        continue;
 
                    }
 
                    // Outside synchronous blocks, no fires/get/put happens
 
                    EvalContinuation::BlockFires(val) => unreachable!(),
 
                    EvalContinuation::BlockGet(val) => unreachable!(),
 
                    EvalContinuation::Put(port, msg) => unreachable!(),
 
                },
 
            }
 
        }
 
    }
 

	
 
    fn sync_run<C: PolyContext<D = ProtocolDescriptionImpl>>(
src/runtime/ffi.rs
Show inline comments
 
@@ -84,152 +84,152 @@ pub extern "C" fn connector_error_clear() -> c_int {
 
    LAST_ERROR.with(|stored_error| {
 
        let mut stored_error = stored_error.borrow_mut();
 
        if stored_error.filled {
 
            stored_error.buf.clear();
 
            stored_error.filled = false;
 
            0
 
        } else {
 
            1
 
        }
 
    })
 
}
 

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

	
 
/// 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 {
 
    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
 
        }
 
    });
 
    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 port_bind_native(
 
pub unsafe extern "C" fn connector_bind_native(
 
    connector: *mut Connector,
 
    proto_port_index: usize,
 
) -> c_int {
 
    // use PortBindErr::*;
 
    let mut b = Box::from_raw(connector); // unsafe!
 
    let ret = match b.bind_port(proto_port_index, PortBinding::Native) {
 
        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 port_bind_passive(
 
pub unsafe extern "C" fn connector_bind_passive(
 
    connector: *mut Connector,
 
    proto_port_index: c_uint,
 
    address: *const c_char,
 
) -> c_int {
 
    if let Some(addr) = try_parse_addr(address) {
 
        // use PortBindErr::*;
 
        let mut b = Box::from_raw(connector); // unsafe!
 
        let ret =
 
            match b.bind_port(proto_port_index.try_into().unwrap(), PortBinding::Passive(addr)) {
 
                Ok(()) => 0,
 
                Err(e) => {
 
                    overwrite_last_error(format!("{:?}", e).as_bytes());
 
                    -1
 
                }
 
            };
 
        Box::into_raw(b); // don't drop!
 
        ret
 
    } else {
 
        overwrite_last_error(b"Failed to parse input as ip address!");
 
        -1
 
    }
 
}
 

	
 
/// Provides a binding annotation for the port with the given index with "active":
 
/// (The port will conenct to a "passive" port at the given address during connect())
 
/// Returns:
 
/// - 0 for success
 
/// - 1 if the port was already bound and was left unchanged
 
/// # Safety
 
/// TODO
 
#[no_mangle]
 
pub unsafe extern "C" fn port_bind_active(
 
pub unsafe extern "C" fn connector_bind_active(
 
    connector: *mut Connector,
 
    proto_port_index: c_uint,
 
    address: *const c_char,
 
) -> c_int {
 
    if let Some(addr) = try_parse_addr(address) {
 
        // use PortBindErr::*;
 
        let mut b = Box::from_raw(connector); // unsafe!
 
        let ret = match b.bind_port(proto_port_index.try_into().unwrap(), PortBinding::Active(addr))
 
        {
 
            Ok(()) => 0,
 
            Err(e) => {
 
                overwrite_last_error(format!("{:?}", e).as_bytes());
 
                -1
 
            }
 
        };
 
        Box::into_raw(b); // don't drop!
 
        ret
 
    } else {
 
        overwrite_last_error(b"Failed to parse input as ip address!");
 
        -1
 
    }
 
}
 

	
 
/// Provides a binding annotation for the port with the given index with "active":
 
/// (The port will conenct to a "passive" port at the given address during connect())
 
/// Returns:
 
/// - 0 SUCCESS: connected successfully
 
/// - TODO error codes
 
/// # Safety
 
/// TODO
 
#[no_mangle]
 
pub unsafe extern "C" fn connector_connect(
 
    connector: *mut Connector,
 
    timeout_millis: u64,
 
) -> c_int {
 
    let mut b = Box::from_raw(connector); // unsafe!
 
    let ret = match b.connect(Duration::from_millis(timeout_millis)) {
 
        Ok(()) => 0,
 
        Err(e) => {
 
            overwrite_last_error(format!("{:?}", e).as_bytes());
 
            -1
 
        }
 
    };
 
    Box::into_raw(b); // don't drop!
 
    ret
 
}
 

	
 
/// Destroys the given connector, freeing its underlying resources.
0 comments (0 inline, 0 general)