<commit_before>use std::ops::Range;
use std::sync::Arc;

use super::ast::{self, Assignment, Ast, AstKind, Identifier, Int, Symbol, Text};
use super::cst::{self, Cst, CstDb, CstVecExtension};
use super::cst_to_ast::CstToAst;
use super::error::CompilerError;
use super::hir::{self, Body, Expression, Lambda};
use crate::builtin_functions;
use crate::input::Input;
use im::HashMap;

#[salsa::query_group(AstToHirStorage)]
pub trait AstToHir: CstDb + CstToAst {
    fn hir_to_ast_id(&self, input: Input, id: hir::Id) -> Option<ast::Id>;
    fn hir_to_cst_id(&self, input: Input, id: hir::Id) -> Option<cst::Id>;
    fn hir_to_span(&self, input: Input, id: hir::Id) -> Option<Range<usize>>;
    fn hir_to_display_span(&self, input: Input, id: hir::Id) -> Option<Range<usize>>;

    fn hir(&self, input: Input) -> Option<(Arc<Body>, HashMap<hir::Id, ast::Id>)>;
    fn hir_raw(
        &self,
        input: Input,
    ) -> Option<(Arc<Body>, HashMap<hir::Id, ast::Id>, Vec<CompilerError>)>;
}

fn hir_to_ast_id(db: &dyn AstToHir, input: Input, id: hir::Id) -> Option<ast::Id> {
    let (_, hir_to_ast_id_mapping) = db.hir(input).unwrap();
    hir_to_ast_id_mapping.get(&id).cloned()
}
fn hir_to_cst_id(db: &dyn AstToHir, input: Input, id: hir::Id) -> Option<cst::Id> {
    let id = db.hir_to_ast_id(input.clone(), id)?;
    db.ast_to_cst_id(input, id)
}
fn hir_to_span(db: &dyn AstToHir, input: Input, id: hir::Id) -> Option<Range<usize>> {
    let id = db.hir_to_cst_id(input.clone(), id)?;
    Some(db.find_cst(input, id)?.span())
}
fn hir_to_display_span(db: &dyn AstToHir, input: Input, id: hir::Id) -> Option<Range<usize>> {
    let id = db.hir_to_cst_id(input.clone(), id)?;
    Some(db.find_cst(input, id)?.display_span())
}

fn hir(db: &dyn AstToHir, input: Input) -> Option<(Arc<Body>, HashMap<hir::Id, ast::Id>)> {
    db.hir_raw(input)
        .map(|(hir, id_mapping, _)| (hir, id_mapping))
}
fn hir_raw(
    db: &dyn AstToHir,
    input: Input,
) -> Option<(Arc<Body>, HashMap<hir::Id, ast::Id>, Vec<CompilerError>)> {
    let cst = db.cst(input.clone())?;
    let (ast, ast_cst_id_mapping) = db
        .ast(input)
        .expect("AST must exist if the CST exists for the same input.");

    let builtin_identifiers = builtin_functions::VALUES
        .iter()
        .enumerate()
        .map(|(index, builtin_function)| {
            let string = format!("builtin{:?}", builtin_function);
            (string, hir::Id(vec![index]))
        })
        .collect::<HashMap<_, _>>();
    let mut compiler = Compiler::new(&cst, ast_cst_id_mapping, builtin_identifiers);
    compiler.compile(&ast);
    Some((
        Arc::new(compiler.body),
        compiler.context.id_mapping,
        compiler.context.errors,
    ))
}

#[derive(Default)]
struct Context<'a> {
    cst: &'a [Cst],
    ast_cst_id_mapping: HashMap<ast::Id, cst::Id>,
    id_mapping: HashMap<hir::Id, ast::Id>,
    errors: Vec<CompilerError>,
}
struct Compiler<'a> {
    context: Context<'a>,
    body: Body,
    parent_ids: Vec<usize>,
    next_id: usize,
    identifiers: HashMap<String, hir::Id>,
}
impl<'a> Compiler<'a> {
    fn new(
        cst: &'a [Cst],
        ast_cst_id_mapping: HashMap<ast::Id, cst::Id>,
        builtin_identifiers: HashMap<String, hir::Id>,
    ) -> Self {
        Compiler {
            context: Context {
                cst,
                ast_cst_id_mapping,
                id_mapping: HashMap::new(),
                errors: vec![],
            },
            parent_ids: vec![],
            next_id: 0,
            body: Body::new(),
            identifiers: builtin_identifiers,
        }
    }

    fn compile(&mut self, asts: &[Ast]) {
        if asts.is_empty() {
            self.body.out = Some(self.push_without_ast_mapping(Expression::nothing()));
        } else {
            for ast in asts.into_iter() {
                self.body.out = Some(self.compile_single(ast));
            }
        }
    }
    fn compile_single(&mut self, ast: &Ast) -> hir::Id {
        match &ast.kind {
            AstKind::Int(Int(int)) => self.push(ast.id, Expression::Int(int.to_owned()), None),
            AstKind::Text(Text(string)) => {
                self.push(ast.id, Expression::Text(string.value.to_owned()), None)
            }
            AstKind::Identifier(Identifier(symbol)) => {
                let reference = match self.identifiers.get(&symbol.value) {
                    Some(reference) => reference.to_owned(),
                    None => {
                        self.context.errors.push(CompilerError {
                            message: format!("Unknown reference: {}", symbol.value),
                            span: self.ast_id_to_span(&symbol.id),
                        });
                        return self.push(symbol.id, Expression::Error, None);
                    }
                };
                self.push(ast.id, Expression::Reference(reference.to_owned()), None)
            }
            AstKind::Symbol(Symbol(symbol)) => {
                self.push(ast.id, Expression::Symbol(symbol.value.to_owned()), None)
            }
            AstKind::Lambda(ast::Lambda {
                parameters,
                body: body_asts,
            }) => {
                let context = std::mem::take(&mut self.context);
                let mut body = Body::new();
                let lambda_id = add_ids(&self.parent_ids, self.next_id);
                let mut identifiers = self.identifiers.clone();

                for (parameter_index, parameter) in parameters.iter().enumerate() {
                    let id = hir::Id(add_ids(&lambda_id, parameter_index));
                    body.identifiers
                        .insert(id.to_owned(), parameter.value.to_owned());
                    identifiers.insert(parameter.value.to_owned(), id);
                }
                let mut inner = Compiler {
                    context,
                    body,
                    parent_ids: lambda_id.to_owned(),
                    next_id: parameters.len(),
                    identifiers,
                };

                inner.compile(&body_asts);
                self.context = inner.context;
                self.push(
                    ast.id,
                    Expression::Lambda(Lambda {
                        first_id: hir::Id(add_ids(&lambda_id[..], 0)),
                        parameters: parameters.iter().map(|it| it.value.to_owned()).collect(),
                        body: inner.body,
                    }),
                    None,
                )
            }
            AstKind::Call(ast::Call { name, arguments }) => {
                let argument_ids = arguments
                    .iter()
                    .map(|argument| self.compile_single(argument))
                    .collect();
                let function = match self.identifiers.get(&name.value) {
                    Some(function) => function.to_owned(),
                    None => {
                        self.context.errors.push(CompilerError {
                            message: format!("Unknown function: {}", name.value),
                            span: self.ast_id_to_span(&name.id),
                        });
                        return self.push(name.id, Expression::Error, None);
                    }
                };
                self.push(
                    ast.id,
                    Expression::Call {
                        function,
                        arguments: argument_ids,
                    },
                    None,
                )
            }
            AstKind::Assignment(Assignment { name, body }) => {
                let context = std::mem::take(&mut self.context);
                let mut inner = Compiler {
                    context,
                    body: Body::new(),
                    parent_ids: add_ids(&self.parent_ids, self.next_id),
                    next_id: 0,
                    identifiers: self.identifiers.clone(),
                };
                inner.compile(&body);
                self.context = inner.context;
                self.push(
                    ast.id,
                    Expression::Body(inner.body),
                    Some(name.value.to_owned()),
                )
            }
            AstKind::Error => self.push(ast.id, Expression::Error, None),
        }
    }

    fn push(
        &mut self,
        ast_id: ast::Id,
        expression: Expression,
        identifier: Option<String>,
    ) -> hir::Id {
        let id = self.create_next_id(ast_id);
        self.body.push(id.clone(), expression, identifier.clone());
        self.context.id_mapping.insert(id.clone(), ast_id);
        if let Some(identifier) = identifier {
            self.identifiers.insert(identifier, id.clone());
        }
        id
    }
    fn push_without_ast_mapping(&mut self, expression: Expression) -> hir::Id {
        let id = self.create_next_id_without_ast_mapping();
        self.body.push(id.to_owned(), expression, None);
        id
    }

    fn ast_id_to_span(&self, id: &ast::Id) -> Range<usize> {
        self.context
            .cst
            .find(self.context.ast_cst_id_mapping.get(id).unwrap())
            .expect("AST has no corresponding CST")
            .span()
    }

    fn create_next_id(&mut self, ast_id: ast::Id) -> hir::Id {
        let id = self.create_next_id_without_ast_mapping();
        assert!(matches!(
            self.context.id_mapping.insert(id.to_owned(), ast_id),
            None
        ));
        id
    }
    fn create_next_id_without_ast_mapping(&mut self) -> hir::Id {
        let id = hir::Id(add_ids(&self.parent_ids, self.next_id));
        self.next_id += 1;
        id
    }
}

fn add_ids(parents: &[usize], id: usize) -> Vec<usize> {
    parents.iter().map(|it| *it).chain(vec![id]).collect()
}
<commit_msg>fix(compiler): don't override builtin identifiers<commit_after>use std::ops::Range;
use std::sync::Arc;

use super::ast::{self, Assignment, Ast, AstKind, Identifier, Int, Symbol, Text};
use super::cst::{self, Cst, CstDb, CstVecExtension};
use super::cst_to_ast::CstToAst;
use super::error::CompilerError;
use super::hir::{self, Body, Expression, Lambda};
use crate::builtin_functions;
use crate::input::Input;
use im::HashMap;

#[salsa::query_group(AstToHirStorage)]
pub trait AstToHir: CstDb + CstToAst {
    fn hir_to_ast_id(&self, input: Input, id: hir::Id) -> Option<ast::Id>;
    fn hir_to_cst_id(&self, input: Input, id: hir::Id) -> Option<cst::Id>;
    fn hir_to_span(&self, input: Input, id: hir::Id) -> Option<Range<usize>>;
    fn hir_to_display_span(&self, input: Input, id: hir::Id) -> Option<Range<usize>>;

    fn hir(&self, input: Input) -> Option<(Arc<Body>, HashMap<hir::Id, ast::Id>)>;
    fn hir_raw(
        &self,
        input: Input,
    ) -> Option<(Arc<Body>, HashMap<hir::Id, ast::Id>, Vec<CompilerError>)>;
}

fn hir_to_ast_id(db: &dyn AstToHir, input: Input, id: hir::Id) -> Option<ast::Id> {
    let (_, hir_to_ast_id_mapping) = db.hir(input).unwrap();
    hir_to_ast_id_mapping.get(&id).cloned()
}
fn hir_to_cst_id(db: &dyn AstToHir, input: Input, id: hir::Id) -> Option<cst::Id> {
    let id = db.hir_to_ast_id(input.clone(), id)?;
    db.ast_to_cst_id(input, id)
}
fn hir_to_span(db: &dyn AstToHir, input: Input, id: hir::Id) -> Option<Range<usize>> {
    let id = db.hir_to_cst_id(input.clone(), id)?;
    Some(db.find_cst(input, id)?.span())
}
fn hir_to_display_span(db: &dyn AstToHir, input: Input, id: hir::Id) -> Option<Range<usize>> {
    let id = db.hir_to_cst_id(input.clone(), id)?;
    Some(db.find_cst(input, id)?.display_span())
}

fn hir(db: &dyn AstToHir, input: Input) -> Option<(Arc<Body>, HashMap<hir::Id, ast::Id>)> {
    db.hir_raw(input)
        .map(|(hir, id_mapping, _)| (hir, id_mapping))
}
fn hir_raw(
    db: &dyn AstToHir,
    input: Input,
) -> Option<(Arc<Body>, HashMap<hir::Id, ast::Id>, Vec<CompilerError>)> {
    let cst = db.cst(input.clone())?;
    let (ast, ast_cst_id_mapping) = db
        .ast(input)
        .expect("AST must exist if the CST exists for the same input.");

    let builtin_identifiers = builtin_functions::VALUES
        .iter()
        .enumerate()
        .map(|(index, builtin_function)| {
            let string = format!("builtin{:?}", builtin_function);
            (string, hir::Id(vec![index]))
        })
        .collect::<HashMap<_, _>>();
    let mut compiler = Compiler::new(&cst, ast_cst_id_mapping, builtin_identifiers);
    compiler.compile(&ast);
    Some((
        Arc::new(compiler.body),
        compiler.context.id_mapping,
        compiler.context.errors,
    ))
}

#[derive(Default)]
struct Context<'a> {
    cst: &'a [Cst],
    ast_cst_id_mapping: HashMap<ast::Id, cst::Id>,
    id_mapping: HashMap<hir::Id, ast::Id>,
    errors: Vec<CompilerError>,
}
struct Compiler<'a> {
    context: Context<'a>,
    body: Body,
    parent_ids: Vec<usize>,
    next_id: usize,
    identifiers: HashMap<String, hir::Id>,
}
impl<'a> Compiler<'a> {
    fn new(
        cst: &'a [Cst],
        ast_cst_id_mapping: HashMap<ast::Id, cst::Id>,
        builtin_identifiers: HashMap<String, hir::Id>,
    ) -> Self {
        Compiler {
            context: Context {
                cst,
                ast_cst_id_mapping,
                id_mapping: HashMap::new(),
                errors: vec![],
            },
            parent_ids: vec![],
            next_id: builtin_identifiers.len(),
            body: Body::new(),
            identifiers: builtin_identifiers,
        }
    }

    fn compile(&mut self, asts: &[Ast]) {
        if asts.is_empty() {
            self.body.out = Some(self.push_without_ast_mapping(Expression::nothing()));
        } else {
            for ast in asts.into_iter() {
                self.body.out = Some(self.compile_single(ast));
            }
        }
    }
    fn compile_single(&mut self, ast: &Ast) -> hir::Id {
        match &ast.kind {
            AstKind::Int(Int(int)) => self.push(ast.id, Expression::Int(int.to_owned()), None),
            AstKind::Text(Text(string)) => {
                self.push(ast.id, Expression::Text(string.value.to_owned()), None)
            }
            AstKind::Identifier(Identifier(symbol)) => {
                let reference = match self.identifiers.get(&symbol.value) {
                    Some(reference) => reference.to_owned(),
                    None => {
                        self.context.errors.push(CompilerError {
                            message: format!("Unknown reference: {}", symbol.value),
                            span: self.ast_id_to_span(&symbol.id),
                        });
                        return self.push(symbol.id, Expression::Error, None);
                    }
                };
                self.push(ast.id, Expression::Reference(reference.to_owned()), None)
            }
            AstKind::Symbol(Symbol(symbol)) => {
                self.push(ast.id, Expression::Symbol(symbol.value.to_owned()), None)
            }
            AstKind::Lambda(ast::Lambda {
                parameters,
                body: body_asts,
            }) => {
                let context = std::mem::take(&mut self.context);
                let mut body = Body::new();
                let lambda_id = add_ids(&self.parent_ids, self.next_id);
                let mut identifiers = self.identifiers.clone();

                for (parameter_index, parameter) in parameters.iter().enumerate() {
                    let id = hir::Id(add_ids(&lambda_id, parameter_index));
                    body.identifiers
                        .insert(id.to_owned(), parameter.value.to_owned());
                    identifiers.insert(parameter.value.to_owned(), id);
                }
                let mut inner = Compiler {
                    context,
                    body,
                    parent_ids: lambda_id.to_owned(),
                    next_id: parameters.len(),
                    identifiers,
                };

                inner.compile(&body_asts);
                self.context = inner.context;
                self.push(
                    ast.id,
                    Expression::Lambda(Lambda {
                        first_id: hir::Id(add_ids(&lambda_id[..], 0)),
                        parameters: parameters.iter().map(|it| it.value.to_owned()).collect(),
                        body: inner.body,
                    }),
                    None,
                )
            }
            AstKind::Call(ast::Call { name, arguments }) => {
                let argument_ids = arguments
                    .iter()
                    .map(|argument| self.compile_single(argument))
                    .collect();
                let function = match self.identifiers.get(&name.value) {
                    Some(function) => function.to_owned(),
                    None => {
                        self.context.errors.push(CompilerError {
                            message: format!("Unknown function: {}", name.value),
                            span: self.ast_id_to_span(&name.id),
                        });
                        return self.push(name.id, Expression::Error, None);
                    }
                };
                self.push(
                    ast.id,
                    Expression::Call {
                        function,
                        arguments: argument_ids,
                    },
                    None,
                )
            }
            AstKind::Assignment(Assignment { name, body }) => {
                let context = std::mem::take(&mut self.context);
                let mut inner = Compiler {
                    context,
                    body: Body::new(),
                    parent_ids: add_ids(&self.parent_ids, self.next_id),
                    next_id: 0,
                    identifiers: self.identifiers.clone(),
                };
                inner.compile(&body);
                self.context = inner.context;
                self.push(
                    ast.id,
                    Expression::Body(inner.body),
                    Some(name.value.to_owned()),
                )
            }
            AstKind::Error => self.push(ast.id, Expression::Error, None),
        }
    }

    fn push(
        &mut self,
        ast_id: ast::Id,
        expression: Expression,
        identifier: Option<String>,
    ) -> hir::Id {
        let id = self.create_next_id(ast_id);
        self.body.push(id.clone(), expression, identifier.clone());
        self.context.id_mapping.insert(id.clone(), ast_id);
        if let Some(identifier) = identifier {
            self.identifiers.insert(identifier, id.clone());
        }
        id
    }
    fn push_without_ast_mapping(&mut self, expression: Expression) -> hir::Id {
        let id = self.create_next_id_without_ast_mapping();
        self.body.push(id.to_owned(), expression, None);
        id
    }

    fn ast_id_to_span(&self, id: &ast::Id) -> Range<usize> {
        self.context
            .cst
            .find(self.context.ast_cst_id_mapping.get(id).unwrap())
            .expect("AST has no corresponding CST")
            .span()
    }

    fn create_next_id(&mut self, ast_id: ast::Id) -> hir::Id {
        let id = self.create_next_id_without_ast_mapping();
        assert!(matches!(
            self.context.id_mapping.insert(id.to_owned(), ast_id),
            None
        ));
        id
    }
    fn create_next_id_without_ast_mapping(&mut self) -> hir::Id {
        let id = hir::Id(add_ids(&self.parent_ids, self.next_id));
        self.next_id += 1;
        id
    }
}

fn add_ids(parents: &[usize], id: usize) -> Vec<usize> {
    parents.iter().map(|it| *it).chain(vec![id]).collect()
}
<|endoftext|>


<commit_before>//! Module: czmq-zmonitor

use {czmq_sys, Error, ErrorKind, Result, ZActor, ZMsg, ZSock};
use std::{error, fmt, ptr, result};
use std::os::raw::c_void;
use zmsg::ZMsgable;

#[derive(Debug, PartialEq)]
pub enum ZMonitorEvents {
    Connected,
    ConnectDelayed,
    ConnectRetried,
    Listening,
    BindFailed,
    Accepted,
    AcceptFailed,
    Closed,
    CloseFailed,
    Disconnected,
    MonitorStopped,
    All,
}

impl ZMonitorEvents {
    pub fn to_str<'a>(&'a self) -> &'a str {
        match self {
            &ZMonitorEvents::Connected      => "CONNECTED",
            &ZMonitorEvents::ConnectDelayed => "CONNECT_DELAYED",
            &ZMonitorEvents::ConnectRetried => "CONNECT_RETRIED",
            &ZMonitorEvents::Listening      => "LISTENING",
            &ZMonitorEvents::BindFailed     => "BIND_FAILED",
            &ZMonitorEvents::Accepted       => "ACCEPTED",
            &ZMonitorEvents::AcceptFailed   => "ACCEPT_FAILED",
            &ZMonitorEvents::Closed         => "CLOSED",
            &ZMonitorEvents::CloseFailed    => "CLOSE_FAILED",
            &ZMonitorEvents::Disconnected   => "DISCONNECTED",
            &ZMonitorEvents::MonitorStopped => "MONITOR_STOPPED",
            &ZMonitorEvents::All            => "ALL",
        }
    }

    pub fn from_str(event: &str) -> ZMonitorEvents {
        match event {
            "CONNECTED"       => ZMonitorEvents::Connected,
            "CONNECT_DELAYED" => ZMonitorEvents::ConnectDelayed,
            "CONNECT_RETRIED" => ZMonitorEvents::ConnectRetried,
            "LISTENING"       => ZMonitorEvents::Listening,
            "BIND_FAILED"     => ZMonitorEvents::BindFailed,
            "ACCEPTED"        => ZMonitorEvents::Accepted,
            "ACCEPT_FAILED"   => ZMonitorEvents::AcceptFailed,
            "CLOSED"          => ZMonitorEvents::Closed,
            "CLOSE_FAILED"    => ZMonitorEvents::CloseFailed,
            "DISCONNECTED"    => ZMonitorEvents::Disconnected,
            "MONITOR_STOPPED" => ZMonitorEvents::MonitorStopped,
            "ALL"             => ZMonitorEvents::All,
            _                 => unimplemented!(),
        }
    }
}

pub struct ZMonitor {
    zactor: ZActor,
}

unsafe impl Send for ZMonitor {}

impl ZMonitor {
    pub fn new(zsock: &ZSock) -> Result<ZMonitor> {
        let zactor = unsafe { czmq_sys::zactor_new(czmq_sys::zmonitor, zsock.borrow_raw() as *mut c_void) };

        if zactor == ptr::null_mut() {
            Err(Error::new(ErrorKind::NullPtr, ZMonitorError::Instantiate))
        } else {
            Ok(ZMonitor {
                zactor: ZActor::from_raw(zactor),
            })
        }
    }

    pub fn set_attrs(&self, attrs: &[ZMonitorEvents]) -> Result<()> {
        let msg = ZMsg::new();
        try!(msg.addstr("LISTEN"));
        for a in attrs {
            try!(msg.addstr(a.to_str()));
        }

        self.zactor.send(msg)
    }

    pub fn get_attr(&self) -> Result<result::Result<ZMonitorEvents, Vec<u8>>> {
        let msg = try!(ZMsg::recv(&self.zactor));
        match try!(msg.popstr()) {
            Ok(s) => Ok(Ok(ZMonitorEvents::from_str(&s))),
            Err(v) => Ok(Err(v))
        }
    }

    pub fn start(&self) -> Result<()> {
        try!(self.zactor.send_str("START"));
        self.zactor.sock().wait()
    }

    pub fn verbose(&self) -> Result<()> {
        self.zactor.send_str("VERBOSE")
    }
}

#[derive(Debug)]
pub enum ZMonitorError {
    Instantiate,
}

impl fmt::Display for ZMonitorError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ZMonitorError::Instantiate => write!(f, "Could not instantiate new ZMonitor struct"),
        }
    }
}

impl error::Error for ZMonitorError {
    fn description(&self) -> &str {
        match *self {
            ZMonitorError::Instantiate => "Could not instantiate new ZMonitor struct",
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use {ZSock, ZSockType, zsys_init};

    #[test]
    fn test_attrs() {
        zsys_init();

        let server = ZSock::new(ZSockType::PULL);
        let server_mon = ZMonitor::new(&server).unwrap();
        server_mon.set_attrs(&[ZMonitorEvents::All]).unwrap();
        server_mon.start().unwrap();

        let client = ZSock::new(ZSockType::PUSH);
        let client_mon = ZMonitor::new(&client).unwrap();
        client_mon.set_attrs(&[ZMonitorEvents::All]).unwrap();
        client_mon.start().unwrap();

        server.bind("ipc://zmonitor_test").unwrap();
        assert_eq!(server_mon.get_attr().unwrap().unwrap(), ZMonitorEvents::Listening);

        client.connect("ipc://zmonitor_test").unwrap();
        assert_eq!(client_mon.get_attr().unwrap().unwrap(), ZMonitorEvents::Connected);
    }

    #[test]
    fn test_verbose() {
        zsys_init();

        let zsock = ZSock::new(ZSockType::REP);
        let zmonitor = ZMonitor::new(&zsock).unwrap();
        assert!(zmonitor.verbose().is_ok());
    }
}
<commit_msg>Avoid panicking on unknown/blank sock monitor events<commit_after>//! Module: czmq-zmonitor

use {czmq_sys, Error, ErrorKind, Result, ZActor, ZMsg, ZSock};
use std::{error, fmt, ptr, result};
use std::os::raw::c_void;
use zmsg::ZMsgable;

#[derive(Debug, PartialEq)]
pub enum ZMonitorEvents {
    Connected,
    ConnectDelayed,
    ConnectRetried,
    Listening,
    BindFailed,
    Accepted,
    AcceptFailed,
    Closed,
    CloseFailed,
    Disconnected,
    MonitorStopped,
    All,
    Unknown,
}

impl ZMonitorEvents {
    pub fn to_str<'a>(&'a self) -> &'a str {
        match self {
            &ZMonitorEvents::Connected      => "CONNECTED",
            &ZMonitorEvents::ConnectDelayed => "CONNECT_DELAYED",
            &ZMonitorEvents::ConnectRetried => "CONNECT_RETRIED",
            &ZMonitorEvents::Listening      => "LISTENING",
            &ZMonitorEvents::BindFailed     => "BIND_FAILED",
            &ZMonitorEvents::Accepted       => "ACCEPTED",
            &ZMonitorEvents::AcceptFailed   => "ACCEPT_FAILED",
            &ZMonitorEvents::Closed         => "CLOSED",
            &ZMonitorEvents::CloseFailed    => "CLOSE_FAILED",
            &ZMonitorEvents::Disconnected   => "DISCONNECTED",
            &ZMonitorEvents::MonitorStopped => "MONITOR_STOPPED",
            &ZMonitorEvents::All            => "ALL",
            &ZMonitorEvents::Unknown        => "UNKNOWN",
        }
    }

    pub fn from_str(event: &str) -> ZMonitorEvents {
        match event {
            "CONNECTED"       => ZMonitorEvents::Connected,
            "CONNECT_DELAYED" => ZMonitorEvents::ConnectDelayed,
            "CONNECT_RETRIED" => ZMonitorEvents::ConnectRetried,
            "LISTENING"       => ZMonitorEvents::Listening,
            "BIND_FAILED"     => ZMonitorEvents::BindFailed,
            "ACCEPTED"        => ZMonitorEvents::Accepted,
            "ACCEPT_FAILED"   => ZMonitorEvents::AcceptFailed,
            "CLOSED"          => ZMonitorEvents::Closed,
            "CLOSE_FAILED"    => ZMonitorEvents::CloseFailed,
            "DISCONNECTED"    => ZMonitorEvents::Disconnected,
            "MONITOR_STOPPED" => ZMonitorEvents::MonitorStopped,
            "ALL"             => ZMonitorEvents::All,
            _                 => ZMonitorEvents::Unknown,
        }
    }
}

pub struct ZMonitor {
    zactor: ZActor,
}

unsafe impl Send for ZMonitor {}

impl ZMonitor {
    pub fn new(zsock: &ZSock) -> Result<ZMonitor> {
        let zactor = unsafe { czmq_sys::zactor_new(czmq_sys::zmonitor, zsock.borrow_raw() as *mut c_void) };

        if zactor == ptr::null_mut() {
            Err(Error::new(ErrorKind::NullPtr, ZMonitorError::Instantiate))
        } else {
            Ok(ZMonitor {
                zactor: ZActor::from_raw(zactor),
            })
        }
    }

    pub fn set_attrs(&self, attrs: &[ZMonitorEvents]) -> Result<()> {
        let msg = ZMsg::new();
        try!(msg.addstr("LISTEN"));
        for a in attrs {
            try!(msg.addstr(a.to_str()));
        }

        self.zactor.send(msg)
    }

    pub fn get_attr(&self) -> Result<result::Result<ZMonitorEvents, Vec<u8>>> {
        let msg = try!(ZMsg::recv(&self.zactor));
        match try!(msg.popstr()) {
            Ok(s) => Ok(Ok(ZMonitorEvents::from_str(&s))),
            Err(v) => Ok(Err(v))
        }
    }

    pub fn start(&self) -> Result<()> {
        try!(self.zactor.send_str("START"));
        self.zactor.sock().wait()
    }

    pub fn verbose(&self) -> Result<()> {
        self.zactor.send_str("VERBOSE")
    }
}

#[derive(Debug)]
pub enum ZMonitorError {
    Instantiate,
}

impl fmt::Display for ZMonitorError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ZMonitorError::Instantiate => write!(f, "Could not instantiate new ZMonitor struct"),
        }
    }
}

impl error::Error for ZMonitorError {
    fn description(&self) -> &str {
        match *self {
            ZMonitorError::Instantiate => "Could not instantiate new ZMonitor struct",
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use {ZSock, ZSockType, zsys_init};

    #[test]
    fn test_attrs() {
        zsys_init();

        let server = ZSock::new(ZSockType::PULL);
        let server_mon = ZMonitor::new(&server).unwrap();
        server_mon.set_attrs(&[ZMonitorEvents::All]).unwrap();
        server_mon.start().unwrap();

        let client = ZSock::new(ZSockType::PUSH);
        let client_mon = ZMonitor::new(&client).unwrap();
        client_mon.set_attrs(&[ZMonitorEvents::All]).unwrap();
        client_mon.start().unwrap();

        server.bind("ipc://zmonitor_test").unwrap();
        assert_eq!(server_mon.get_attr().unwrap().unwrap(), ZMonitorEvents::Listening);

        client.connect("ipc://zmonitor_test").unwrap();
        assert_eq!(client_mon.get_attr().unwrap().unwrap(), ZMonitorEvents::Connected);
    }

    #[test]
    fn test_verbose() {
        zsys_init();

        let zsock = ZSock::new(ZSockType::REP);
        let zmonitor = ZMonitor::new(&zsock).unwrap();
        assert!(zmonitor.verbose().is_ok());
    }
}
<|endoftext|>


<commit_before>use crate::ffi::c_void;
use crate::ptr;
use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
use crate::sys::hermit::abi;
use crate::sys::mutex::Mutex;
use crate::time::Duration;

// The implementation is inspired by Andrew D. Birrell's paper
// "Implementing Condition Variables with Semaphores"

pub struct Condvar {
    counter: AtomicUsize,
    sem1: *const c_void,
    sem2: *const c_void,
}

pub type MovableCondvar = Condvar;

unsafe impl Send for Condvar {}
unsafe impl Sync for Condvar {}

impl Condvar {
    pub const fn new() -> Condvar {
        Condvar { counter: AtomicUsize::new(0), sem1: ptr::null(), sem2: ptr::null() }
    }

    pub unsafe fn init(&mut self) {
        let _ = abi::sem_init(&mut self.sem1 as *mut *const c_void, 0);
        let _ = abi::sem_init(&mut self.sem2 as *mut *const c_void, 0);
    }

    pub unsafe fn notify_one(&self) {
        if self.counter.load(SeqCst) > 0 {
            self.counter.fetch_sub(1, SeqCst);
            abi::sem_post(self.sem1);
            abi::sem_timedwait(self.sem2, 0);
        }
    }

    pub unsafe fn notify_all(&self) {
        let counter = self.counter.swap(0, SeqCst);
        for _ in 0..counter {
            abi::sem_post(self.sem1);
        }
        for _ in 0..counter {
            abi::sem_timedwait(self.sem2, 0);
        }
    }

    pub unsafe fn wait(&self, mutex: &Mutex) {
        self.counter.fetch_add(1, SeqCst);
        mutex.unlock();
        abi::sem_timedwait(self.sem1, 0);
        abi::sem_post(self.sem2);
        mutex.lock();
    }

    pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool {
        panic!("wait_timeout not supported on hermit");
    }

    pub unsafe fn destroy(&self) {
        let _ = abi::sem_destroy(self.sem1);
        let _ = abi::sem_destroy(self.sem2);
    }
}
<commit_msg>Rollup merge of #90401 - mkroening:hermit-condvar, r=joshtriplett<commit_after>use crate::ffi::c_void;
use crate::ptr;
use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
use crate::sys::hermit::abi;
use crate::sys::mutex::Mutex;
use crate::time::Duration;

// The implementation is inspired by Andrew D. Birrell's paper
// "Implementing Condition Variables with Semaphores"

pub struct Condvar {
    counter: AtomicUsize,
    sem1: *const c_void,
    sem2: *const c_void,
}

pub type MovableCondvar = Condvar;

unsafe impl Send for Condvar {}
unsafe impl Sync for Condvar {}

impl Condvar {
    pub const fn new() -> Condvar {
        Condvar { counter: AtomicUsize::new(0), sem1: ptr::null(), sem2: ptr::null() }
    }

    pub unsafe fn init(&mut self) {
        let _ = abi::sem_init(&mut self.sem1 as *mut *const c_void, 0);
        let _ = abi::sem_init(&mut self.sem2 as *mut *const c_void, 0);
    }

    pub unsafe fn notify_one(&self) {
        if self.counter.load(SeqCst) > 0 {
            self.counter.fetch_sub(1, SeqCst);
            abi::sem_post(self.sem1);
            abi::sem_timedwait(self.sem2, 0);
        }
    }

    pub unsafe fn notify_all(&self) {
        let counter = self.counter.swap(0, SeqCst);
        for _ in 0..counter {
            abi::sem_post(self.sem1);
        }
        for _ in 0..counter {
            abi::sem_timedwait(self.sem2, 0);
        }
    }

    pub unsafe fn wait(&self, mutex: &Mutex) {
        self.counter.fetch_add(1, SeqCst);
        mutex.unlock();
        abi::sem_timedwait(self.sem1, 0);
        abi::sem_post(self.sem2);
        mutex.lock();
    }

    pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
        self.counter.fetch_add(1, SeqCst);
        mutex.unlock();
        let millis = dur.as_millis().min(u32::MAX as u128) as u32;

        let res = if millis > 0 {
            abi::sem_timedwait(self.sem1, millis)
        } else {
            abi::sem_trywait(self.sem1)
        };

        abi::sem_post(self.sem2);
        mutex.lock();
        res == 0
    }

    pub unsafe fn destroy(&self) {
        let _ = abi::sem_destroy(self.sem1);
        let _ = abi::sem_destroy(self.sem2);
    }
}
<|endoftext|>


<commit_before>use std;
use unicode_xid::UnicodeXID;
use program::{Program};
use name_table::{NameTable};
use fact_table::{FactTable};
use std::str::{FromStr};

use types::{Term, Literal, Clause};

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Error<'a> {
    Msg {
        msg: &'static str,
        rest: &'a str,
    }
}

pub type Result<'a, T> = std::result::Result<(T, &'a str), Error<'a>>;

fn err_msg<'a, T>(msg: &'static str, rest: &'a str) -> Result<'a, T> {
    Err(Error::Msg {
        msg: msg,
        rest: rest,
    })
}

fn some_char_is<F>(opt_char: Option<char>, f: F) -> bool where F: Fn(char) -> bool {
    if let Some(c) = opt_char {
        f(c)
    } else {
        false
    }
}

fn substr_index(src: &str, substr: &str) -> usize {
    let diff = substr.as_ptr() as isize - src.as_ptr() as isize;
    if 0 <= diff && diff as usize <= src.len() {
        diff as usize
    } else {
        panic!("substr_index called with invalid substr")
    }
}

fn slice_src<'a>(src: &'a str, rest: &'a str) -> &'a str {
    let index = substr_index(src, rest);
    src.split_at(index).0
}

fn character_is<F>(src: &str, f: F) -> Result<char> where F: Fn(char) -> bool {
    let mut cs = src.chars();
    let c = cs.next();
    if some_char_is(c, f) {
        let rest = cs.as_str();
        return Ok((c.unwrap(), rest));
    } else {
        return err_msg("Wrong character", src);
    }
}

fn character(src: &str, c: char) -> Result<char> {
    character_is(src, |x| c == x)
}

fn start_and_continue<F, G>(src: &str, f: F, g: G) -> Result<&str>
    where F: Fn(char) -> bool,
          G: Fn(char) -> bool {
    let mut rest;
    let mut cs = src.chars();
    if some_char_is(cs.next(), f) {
        rest = cs.as_str();
    } else {
        return err_msg("Wrong starting character", src);
    }
    while some_char_is(cs.next(), &g) {
        rest = cs.as_str();
    }
    return Ok((slice_src(src, rest), rest));
}

fn prefix<'a, 'b>(src: &'a str, prefix: &'b str) -> Result<'a, &'a str> {
    let mut rest = src;
    let mut cs = src.chars();
    let mut ps = prefix.chars();
    while let Some(p) = ps.next() {
        if let Some(c) = cs.next() {
            if p == c {
                rest = cs.as_str();
                continue;
            }
        }
        return err_msg("Prefix did not match", src);
    }
    return Ok((slice_src(src, rest), rest));
}

fn unsigned_decimal_integer(src: &str) -> Result<usize> {
    if let Ok((_, rest)) = character(src, '0') {
        if character_is(rest, |c| c.is_digit(10)).is_ok() {
            err_msg("Octal literal", src)
        } else {
            Ok((0, rest))
        }
    } else {
        let (num_src, rest) = try!(start_and_continue(src, |c| c.is_digit(10), |c| c.is_digit(10)));
        Ok((usize::from_str(num_src).unwrap(), rest))
    }
}

fn char_is_not_uppercase(c: char) -> bool {
    let mut lowered = c.to_lowercase();
    lowered.next() == Some(c) && lowered.next().is_none()
}

fn lowercase_identifier(src: &str) -> Result<&str> {
    start_and_continue(src, |c| UnicodeXID::is_xid_start(c) && char_is_not_uppercase(c),
    UnicodeXID::is_xid_continue)
}

fn uppercase_identifier(src: &str) -> Result<&str> {
    start_and_continue(src, |c| UnicodeXID::is_xid_start(c) && !char_is_not_uppercase(c),
    UnicodeXID::is_xid_continue)
}

fn skip_whitespace(src: &str) -> &str {
    let mut rest = src;
    let mut cs = src.chars();
    loop {
        let c = cs.next();
        if some_char_is(c, char::is_whitespace) {
            rest = cs.as_str();
        } else if c == Some('#') {
            rest = cs.as_str();
            while some_char_is(cs.next(), |c| c != '\n') {
                rest = cs.as_str();
            }
        } else {
            break;
        }
    }
    return rest;
}

fn terms<'a, 'b>(src: &'a str, var_names: &'b mut NameTable) -> Result<'a, Vec<Term>> {
    let mut rest = src;
    let mut result = Vec::new();
    debug!("Looking for terms...");
    loop {
        rest = skip_whitespace(rest);
        if let Ok((var_name, r)) = uppercase_identifier(rest) {
            debug!("found uppercase identifier");
            rest = r;
            let var_index = var_names.get(var_name);
            result.push(Term::Variable(var_index));
        } else if let Ok((number, r)) = unsigned_decimal_integer(rest) {
            debug!("found decimal integer");
            rest = r;
            result.push(Term::Constant(number));
        } else {
            return err_msg("Unexpected character in argument list", rest);
        }
        rest = skip_whitespace(rest);
        if let Ok((_, r)) = character(rest, ',') {
            rest = r;
        } else {
            return Ok((result, rest));
        }
    }
}

fn literal<'a, 'b>(src: &'a str, var_names: &'b mut NameTable, predicate_names: &'b mut NameTable) -> Result<'a, Literal> {
    let mut rest = src;
    rest = skip_whitespace(rest);
    let (predicate_name, r) = try!(lowercase_identifier(rest));
    rest = r;
    rest = skip_whitespace(rest);
    rest = try!(character(rest, '(')).1;
    rest = skip_whitespace(rest);
    let (ts, r) = try!(terms(rest, var_names));
    rest = r;
    rest = skip_whitespace(rest);
    rest = try!(character(rest, ')')).1;
    let predicate = predicate_names.get(predicate_name);
    return Ok((Literal::new_from_vec(predicate, ts), rest));
}

pub fn program(source: &str) -> Result<(FactTable<()>, Program)> {
    let mut rest = source;
    let mut facts = FactTable::new();
    let mut program = Program::new();
    loop {
        rest = skip_whitespace(rest);
        if rest.len() == 0 {
            facts.extend_num_predicates(program.num_predicates());
            return Ok(((facts, program), rest));
        }
        let start_of_clause = rest;
        let mut var_names = NameTable::new();
        let (head, r) = try!(literal(rest, &mut var_names, &mut program.predicate_names)
                             .map(|(lit, r)| (Some(lit), r))
            .or_else(|_| character(rest, '?').map(|(_, r)| (None, r))));
        rest = r;
        rest = skip_whitespace(rest);
        if let Ok((_, r)) = prefix(rest, ":-") {
            rest = r;
            let mut literals = Vec::new();
            rest = skip_whitespace(rest);
            loop {
                let (lit, r) = try!(literal(rest, &mut var_names, &mut program.predicate_names));
                rest = r;
                literals.push(lit);
                rest = skip_whitespace(rest);
                if let Ok((_, r)) = character(rest, ',') {
                    rest = r;
                } else {
                    break;
                }
            }
            let clause = Clause {
                head: head,
                body: literals,
            };
            if clause.is_valid() {
                program.clause_variable_names.insert(program.clauses.len(), var_names);
                program.clauses.push(clause);
            } else {
                return err_msg("Invalid clause", start_of_clause);
            }
        } else if let (Some(lit), Ok((_, r))) = (head, character(rest, '.')) {
            rest = r;
            if var_names.to_reverse().len() != 0 {
                return err_msg("Fact contained variables", start_of_clause);
            }
            facts.add_fact(lit.to_fact(), ());
        }
    }
}

#[cfg(test)]
mod tests {
    use super::{unsigned_decimal_integer, character_is, lowercase_identifier, uppercase_identifier,
    terms, prefix, literal, program};
    use types::{Term, Literal};
    use name_table::{NameTable};

    #[test]
    fn parse_characters() {
        assert!(character_is("1", |c| c.is_digit(10)).is_ok());
    }

    #[test]
    fn parse_unsigned_decimal_integer() {
        assert!(unsigned_decimal_integer("").is_err());
        assert!(unsigned_decimal_integer("0").is_ok());
        assert!(unsigned_decimal_integer("1").is_ok());
        assert!(unsigned_decimal_integer("10").is_ok());
        assert!(unsigned_decimal_integer("100").is_ok());
        assert!(unsigned_decimal_integer("01").is_err());
        assert!(unsigned_decimal_integer("1234567890").is_ok());
    }

    #[test]
    fn parse_lowercase_identifier() {
        assert!(lowercase_identifier("").is_err());
        assert!(lowercase_identifier("A").is_err());
        assert!(lowercase_identifier("0").is_err());
        assert!(lowercase_identifier("1").is_err());
        assert!(lowercase_identifier("a").is_ok());
        assert_eq!(lowercase_identifier("aB").unwrap().0, "aB");
        assert_eq!(lowercase_identifier("a1").unwrap().0, "a1");
        assert!(lowercase_identifier("_a").is_err());
        assert_eq!(lowercase_identifier("test_identifier").unwrap().0, "test_identifier");
        assert_eq!(lowercase_identifier("test_identifier").unwrap().1, "");
    }

    #[test]
    fn parse_uppercase_identifier() {
        assert!(uppercase_identifier("").is_err());
        assert!(uppercase_identifier("A").is_ok());
        assert!(uppercase_identifier("0").is_err());
        assert!(uppercase_identifier("1").is_err());
        assert!(uppercase_identifier("a").is_err());
        assert!(uppercase_identifier("aB").is_err());
        assert!(uppercase_identifier("Ba").is_ok());
        assert_eq!(uppercase_identifier("Test_identifier").unwrap().0, "Test_identifier");
        assert_eq!(uppercase_identifier("Test_identifier").unwrap().1, "");
    }

    #[test]
    fn parse_terms() {
        let mut var_names = NameTable::new();
        assert!(terms("0", &mut var_names).is_ok());
        assert!(terms("0, 1", &mut var_names).is_ok());
        assert!(terms("0 ,1", &mut var_names).is_ok());
        assert!(terms("0 , 1", &mut var_names).is_ok());
        assert!(terms("X", &mut var_names).is_ok());
        assert_eq!(terms("X", &mut var_names).unwrap().1, "");
        assert!(terms("Y", &mut var_names).is_ok());
        assert_eq!(var_names.get("Y"), 1);
        assert!(terms("100", &mut var_names).is_ok());
        assert!(terms("0 , X, 100", &mut var_names).is_ok());
        assert!(terms("x", &mut var_names).is_err());
        assert!(terms(",", &mut var_names).is_err());
        assert!(terms("", &mut var_names).is_err());
    }

    #[test]
    fn test_prefix() {
        assert!(prefix("test", "te").is_ok());
        assert_eq!(prefix("test", "te").unwrap().1, "st");
    }

    #[test]
    fn test_literal() {
        let mut var_names = NameTable::new();
        let mut pred_names = NameTable::new();
        assert!(literal("a(0)", &mut var_names, &mut pred_names).is_ok());
        assert!(literal("b(0, 1, X, Y)", &mut var_names, &mut pred_names).is_ok());
        assert_eq!(var_names.get("Y"), 1);
        assert_eq!(pred_names.get("b"), 1);
        assert_eq!(literal("b(1, X, Y)", &mut var_names, &mut pred_names).unwrap().0,
        Literal::new_from_vec(1, vec![Term::Constant(1), Term::Variable(0), Term::Variable(1)]));
    }

    #[test]
    fn test_program() {
        assert!(program("a(0).").is_ok());
        assert!(program("a(X) :- b(X)").is_ok());
        assert!(program("a(X) :- b(X), c(Y)").is_ok());
        assert!(program("a(X) :- b(X, Y), c(Y), test(Y)").is_ok());
        assert!(program("#A comment").is_ok());
        assert!(program("#A comment\nA(0).").is_err());
    }
}
<commit_msg>Replace uses of try! in parser with ?<commit_after>use std;
use unicode_xid::UnicodeXID;
use program::{Program};
use name_table::{NameTable};
use fact_table::{FactTable};
use std::str::{FromStr};

use types::{Term, Literal, Clause};

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Error<'a> {
    Msg {
        msg: &'static str,
        rest: &'a str,
    }
}

pub type Result<'a, T> = std::result::Result<(T, &'a str), Error<'a>>;

fn err_msg<'a, T>(msg: &'static str, rest: &'a str) -> Result<'a, T> {
    Err(Error::Msg {
        msg: msg,
        rest: rest,
    })
}

fn some_char_is<F>(opt_char: Option<char>, f: F) -> bool where F: Fn(char) -> bool {
    if let Some(c) = opt_char {
        f(c)
    } else {
        false
    }
}

fn substr_index(src: &str, substr: &str) -> usize {
    let diff = substr.as_ptr() as isize - src.as_ptr() as isize;
    if 0 <= diff && diff as usize <= src.len() {
        diff as usize
    } else {
        panic!("substr_index called with invalid substr")
    }
}

fn slice_src<'a>(src: &'a str, rest: &'a str) -> &'a str {
    let index = substr_index(src, rest);
    src.split_at(index).0
}

fn character_is<F>(src: &str, f: F) -> Result<char> where F: Fn(char) -> bool {
    let mut cs = src.chars();
    let c = cs.next();
    if some_char_is(c, f) {
        let rest = cs.as_str();
        return Ok((c.unwrap(), rest));
    } else {
        return err_msg("Wrong character", src);
    }
}

fn character(src: &str, c: char) -> Result<char> {
    character_is(src, |x| c == x)
}

fn start_and_continue<F, G>(src: &str, f: F, g: G) -> Result<&str>
    where F: Fn(char) -> bool,
          G: Fn(char) -> bool {
    let mut rest;
    let mut cs = src.chars();
    if some_char_is(cs.next(), f) {
        rest = cs.as_str();
    } else {
        return err_msg("Wrong starting character", src);
    }
    while some_char_is(cs.next(), &g) {
        rest = cs.as_str();
    }
    return Ok((slice_src(src, rest), rest));
}

fn prefix<'a, 'b>(src: &'a str, prefix: &'b str) -> Result<'a, &'a str> {
    let mut rest = src;
    let mut cs = src.chars();
    let mut ps = prefix.chars();
    while let Some(p) = ps.next() {
        if let Some(c) = cs.next() {
            if p == c {
                rest = cs.as_str();
                continue;
            }
        }
        return err_msg("Prefix did not match", src);
    }
    return Ok((slice_src(src, rest), rest));
}

fn unsigned_decimal_integer(src: &str) -> Result<usize> {
    if let Ok((_, rest)) = character(src, '0') {
        if character_is(rest, |c| c.is_digit(10)).is_ok() {
            err_msg("Octal literal", src)
        } else {
            Ok((0, rest))
        }
    } else {
        let (num_src, rest) = start_and_continue(src, |c| c.is_digit(10), |c| c.is_digit(10))?;
        Ok((usize::from_str(num_src).unwrap(), rest))
    }
}

fn char_is_not_uppercase(c: char) -> bool {
    let mut lowered = c.to_lowercase();
    lowered.next() == Some(c) && lowered.next().is_none()
}

fn lowercase_identifier(src: &str) -> Result<&str> {
    start_and_continue(src, |c| UnicodeXID::is_xid_start(c) && char_is_not_uppercase(c),
    UnicodeXID::is_xid_continue)
}

fn uppercase_identifier(src: &str) -> Result<&str> {
    start_and_continue(src, |c| UnicodeXID::is_xid_start(c) && !char_is_not_uppercase(c),
    UnicodeXID::is_xid_continue)
}

fn skip_whitespace(src: &str) -> &str {
    let mut rest = src;
    let mut cs = src.chars();
    loop {
        let c = cs.next();
        if some_char_is(c, char::is_whitespace) {
            rest = cs.as_str();
        } else if c == Some('#') {
            rest = cs.as_str();
            while some_char_is(cs.next(), |c| c != '\n') {
                rest = cs.as_str();
            }
        } else {
            break;
        }
    }
    return rest;
}

fn terms<'a, 'b>(src: &'a str, var_names: &'b mut NameTable) -> Result<'a, Vec<Term>> {
    let mut rest = src;
    let mut result = Vec::new();
    debug!("Looking for terms...");
    loop {
        rest = skip_whitespace(rest);
        if let Ok((var_name, r)) = uppercase_identifier(rest) {
            debug!("found uppercase identifier");
            rest = r;
            let var_index = var_names.get(var_name);
            result.push(Term::Variable(var_index));
        } else if let Ok((number, r)) = unsigned_decimal_integer(rest) {
            debug!("found decimal integer");
            rest = r;
            result.push(Term::Constant(number));
        } else {
            return err_msg("Unexpected character in argument list", rest);
        }
        rest = skip_whitespace(rest);
        if let Ok((_, r)) = character(rest, ',') {
            rest = r;
        } else {
            return Ok((result, rest));
        }
    }
}

fn literal<'a, 'b>(src: &'a str, var_names: &'b mut NameTable, predicate_names: &'b mut NameTable) -> Result<'a, Literal> {
    let mut rest = src;
    rest = skip_whitespace(rest);
    let (predicate_name, r) = lowercase_identifier(rest)?;
    rest = r;
    rest = skip_whitespace(rest);
    rest = character(rest, '(')?.1;
    rest = skip_whitespace(rest);
    let (ts, r) = terms(rest, var_names)?;
    rest = r;
    rest = skip_whitespace(rest);
    rest = character(rest, ')')?.1;
    let predicate = predicate_names.get(predicate_name);
    return Ok((Literal::new_from_vec(predicate, ts), rest));
}

pub fn program(source: &str) -> Result<(FactTable<()>, Program)> {
    let mut rest = source;
    let mut facts = FactTable::new();
    let mut program = Program::new();
    loop {
        rest = skip_whitespace(rest);
        if rest.len() == 0 {
            facts.extend_num_predicates(program.num_predicates());
            return Ok(((facts, program), rest));
        }
        let start_of_clause = rest;
        let mut var_names = NameTable::new();
        let (head, r) = literal(rest, &mut var_names, &mut program.predicate_names)
            .map(|(lit, r)| (Some(lit), r))
            .or_else(|_| character(rest, '?').map(|(_, r)| (None, r)))?;
        rest = r;
        rest = skip_whitespace(rest);
        if let Ok((_, r)) = prefix(rest, ":-") {
            rest = r;
            let mut literals = Vec::new();
            rest = skip_whitespace(rest);
            loop {
                let (lit, r) = literal(rest, &mut var_names, &mut program.predicate_names)?;
                rest = r;
                literals.push(lit);
                rest = skip_whitespace(rest);
                if let Ok((_, r)) = character(rest, ',') {
                    rest = r;
                } else {
                    break;
                }
            }
            let clause = Clause {
                head: head,
                body: literals,
            };
            if clause.is_valid() {
                program.clause_variable_names.insert(program.clauses.len(), var_names);
                program.clauses.push(clause);
            } else {
                return err_msg("Invalid clause", start_of_clause);
            }
        } else if let (Some(lit), Ok((_, r))) = (head, character(rest, '.')) {
            rest = r;
            if var_names.to_reverse().len() != 0 {
                return err_msg("Fact contained variables", start_of_clause);
            }
            facts.add_fact(lit.to_fact(), ());
        }
    }
}

#[cfg(test)]
mod tests {
    use super::{unsigned_decimal_integer, character_is, lowercase_identifier, uppercase_identifier,
    terms, prefix, literal, program};
    use types::{Term, Literal};
    use name_table::{NameTable};

    #[test]
    fn parse_characters() {
        assert!(character_is("1", |c| c.is_digit(10)).is_ok());
    }

    #[test]
    fn parse_unsigned_decimal_integer() {
        assert!(unsigned_decimal_integer("").is_err());
        assert!(unsigned_decimal_integer("0").is_ok());
        assert!(unsigned_decimal_integer("1").is_ok());
        assert!(unsigned_decimal_integer("10").is_ok());
        assert!(unsigned_decimal_integer("100").is_ok());
        assert!(unsigned_decimal_integer("01").is_err());
        assert!(unsigned_decimal_integer("1234567890").is_ok());
    }

    #[test]
    fn parse_lowercase_identifier() {
        assert!(lowercase_identifier("").is_err());
        assert!(lowercase_identifier("A").is_err());
        assert!(lowercase_identifier("0").is_err());
        assert!(lowercase_identifier("1").is_err());
        assert!(lowercase_identifier("a").is_ok());
        assert_eq!(lowercase_identifier("aB").unwrap().0, "aB");
        assert_eq!(lowercase_identifier("a1").unwrap().0, "a1");
        assert!(lowercase_identifier("_a").is_err());
        assert_eq!(lowercase_identifier("test_identifier").unwrap().0, "test_identifier");
        assert_eq!(lowercase_identifier("test_identifier").unwrap().1, "");
    }

    #[test]
    fn parse_uppercase_identifier() {
        assert!(uppercase_identifier("").is_err());
        assert!(uppercase_identifier("A").is_ok());
        assert!(uppercase_identifier("0").is_err());
        assert!(uppercase_identifier("1").is_err());
        assert!(uppercase_identifier("a").is_err());
        assert!(uppercase_identifier("aB").is_err());
        assert!(uppercase_identifier("Ba").is_ok());
        assert_eq!(uppercase_identifier("Test_identifier").unwrap().0, "Test_identifier");
        assert_eq!(uppercase_identifier("Test_identifier").unwrap().1, "");
    }

    #[test]
    fn parse_terms() {
        let mut var_names = NameTable::new();
        assert!(terms("0", &mut var_names).is_ok());
        assert!(terms("0, 1", &mut var_names).is_ok());
        assert!(terms("0 ,1", &mut var_names).is_ok());
        assert!(terms("0 , 1", &mut var_names).is_ok());
        assert!(terms("X", &mut var_names).is_ok());
        assert_eq!(terms("X", &mut var_names).unwrap().1, "");
        assert!(terms("Y", &mut var_names).is_ok());
        assert_eq!(var_names.get("Y"), 1);
        assert!(terms("100", &mut var_names).is_ok());
        assert!(terms("0 , X, 100", &mut var_names).is_ok());
        assert!(terms("x", &mut var_names).is_err());
        assert!(terms(",", &mut var_names).is_err());
        assert!(terms("", &mut var_names).is_err());
    }

    #[test]
    fn test_prefix() {
        assert!(prefix("test", "te").is_ok());
        assert_eq!(prefix("test", "te").unwrap().1, "st");
    }

    #[test]
    fn test_literal() {
        let mut var_names = NameTable::new();
        let mut pred_names = NameTable::new();
        assert!(literal("a(0)", &mut var_names, &mut pred_names).is_ok());
        assert!(literal("b(0, 1, X, Y)", &mut var_names, &mut pred_names).is_ok());
        assert_eq!(var_names.get("Y"), 1);
        assert_eq!(pred_names.get("b"), 1);
        assert_eq!(literal("b(1, X, Y)", &mut var_names, &mut pred_names).unwrap().0,
        Literal::new_from_vec(1, vec![Term::Constant(1), Term::Variable(0), Term::Variable(1)]));
    }

    #[test]
    fn test_program() {
        assert!(program("a(0).").is_ok());
        assert!(program("a(X) :- b(X)").is_ok());
        assert!(program("a(X) :- b(X), c(Y)").is_ok());
        assert!(program("a(X) :- b(X, Y), c(Y), test(Y)").is_ok());
        assert!(program("#A comment").is_ok());
        assert!(program("#A comment\nA(0).").is_err());
    }
}
<|endoftext|>


<commit_before>pub mod layout;

use super::{types, ids};

pub struct UiMemberFunctions {
    pub fn_member_id: unsafe fn(&UiMemberCommon) -> &'static str,
    pub fn_is_control: unsafe fn(&UiMemberCommon) -> Option<&UiControlCommon>,
    pub fn_is_control_mut: unsafe fn(&mut UiMemberCommon) -> Option<&mut UiControlCommon>,
    pub fn_size: unsafe fn(&UiMemberCommon) -> (u16, u16),
    /*pub fn_draw: unsafe fn(&mut UiMemberCommon, coords: Option<(i32, i32)>),
    pub fn_measure: unsafe fn(&mut UiMemberCommon, w: u16, h: u16) -> (u16, u16, bool),*/
}

#[repr(C)]
pub struct UiControlCommon {
    pub member_base: UiMemberCommon,
    pub layout: layout::LayoutBase,
}

#[repr(C)]
pub struct UiMemberCommon {
    pub id: ids::Id,
    pub visibility: types::Visibility,

	functions: UiMemberFunctions,
}

impl UiMemberCommon {
    pub fn with_params(visibility: types::Visibility, functions: UiMemberFunctions) -> UiMemberCommon {
        UiMemberCommon {
            id: ids::Id::next(),
            visibility: visibility,
            functions: functions,
        }
    }

    pub fn member_id(&self) -> &'static str {
    	unsafe { (self.functions.fn_member_id)(self) }
    }

    pub fn is_control(&self) -> Option<&UiControlCommon> {
    	unsafe { (self.functions.fn_is_control)(self) }
    }
    pub fn is_control_mut(&mut self) -> Option<&mut UiControlCommon> {
    	unsafe { (self.functions.fn_is_control_mut)(self) }
    }
    pub fn size(&self) -> (u16, u16) {
    	unsafe { (self.functions.fn_size)(self) }
    }
    /*pub fn draw(&mut self, coords: Option<(i32, i32)>) {
    	unsafe { (self.functions.fn_draw)(self, coords) }
    }
    pub fn measure(&mut self, w: u16, h: u16) -> (u16, u16, bool) {
    	unsafe { (self.functions.fn_measure)(self, w, h) }
    }*/
}

pub trait UiDrawable {
	fn draw(&mut self, coords: Option<(i32, i32)>);
    fn measure(&mut self, w: u16, h: u16) -> (u16, u16, bool);
}
<commit_msg>AsRef/AsMut for development types<commit_after>pub mod layout;

use super::{types, ids};

pub struct UiMemberFunctions {
    pub fn_member_id: unsafe fn(&UiMemberCommon) -> &'static str,
    pub fn_is_control: unsafe fn(&UiMemberCommon) -> Option<&UiControlCommon>,
    pub fn_is_control_mut: unsafe fn(&mut UiMemberCommon) -> Option<&mut UiControlCommon>,
    pub fn_size: unsafe fn(&UiMemberCommon) -> (u16, u16),
    /*pub fn_draw: unsafe fn(&mut UiMemberCommon, coords: Option<(i32, i32)>),
    pub fn_measure: unsafe fn(&mut UiMemberCommon, w: u16, h: u16) -> (u16, u16, bool),*/
}

#[repr(C)]
pub struct UiControlCommon {
    pub member_base: UiMemberCommon,
    pub layout: layout::LayoutBase,
}

#[repr(C)]
pub struct UiMemberCommon {
    pub id: ids::Id,
    pub visibility: types::Visibility,

	functions: UiMemberFunctions,
}

impl UiMemberCommon {
    pub fn with_params(visibility: types::Visibility, functions: UiMemberFunctions) -> UiMemberCommon {
        UiMemberCommon {
            id: ids::Id::next(),
            visibility: visibility,
            functions: functions,
        }
    }

    pub fn member_id(&self) -> &'static str {
    	unsafe { (self.functions.fn_member_id)(self) }
    }

    pub fn is_control(&self) -> Option<&UiControlCommon> {
    	unsafe { (self.functions.fn_is_control)(self) }
    }
    pub fn is_control_mut(&mut self) -> Option<&mut UiControlCommon> {
    	unsafe { (self.functions.fn_is_control_mut)(self) }
    }
    pub fn size(&self) -> (u16, u16) {
    	unsafe { (self.functions.fn_size)(self) }
    }
    /*pub fn draw(&mut self, coords: Option<(i32, i32)>) {
    	unsafe { (self.functions.fn_draw)(self, coords) }
    }
    pub fn measure(&mut self, w: u16, h: u16) -> (u16, u16, bool) {
    	unsafe { (self.functions.fn_measure)(self, w, h) }
    }*/
}

impl AsRef<UiMemberCommon> for types::UiMemberBase {
	fn as_ref(&self) -> &UiMemberCommon {
		unsafe { ::std::mem::transmute(self) }
	}
}
impl AsMut<UiMemberCommon> for types::UiMemberBase {
	fn as_mut(&mut self) -> &mut UiMemberCommon {
		unsafe { ::std::mem::transmute(self) }
	}
}

pub trait UiDrawable {
	fn draw(&mut self, coords: Option<(i32, i32)>);
    fn measure(&mut self, w: u16, h: u16) -> (u16, u16, bool);
}
<|endoftext|>


<commit_before>use std::string::String;

pub struct MessageList {
    messages: Vec<Message>,
}

pub enum MessageType {
    Info,
    Error,
}

pub struct Message {
    text: String,
    ty: MessageType,
}

impl MessageList {

    pub fn new() -> MessageList {
        MessageList { messages: vec![] }
    }

    pub fn info(&mut self, text: &str) {
        self.messages.push(Message { text: String::from_str(text), ty: MessageType::Info });
    }

    pub fn error(&mut self, text: &str) {
        self.messages.push(Message { text: String::from_str(text), ty: MessageType::Error });
    }

}
<commit_msg>Add some convenient messages for Message<commit_after>use std::string::String;
use std::slice::Iter;

pub struct MessageList {
    messages: Vec<Message>,
}

pub enum MessageType {
    Info,
    Error,
}

pub struct Message {
    text: String,
    ty: MessageType,
}

impl Message {
    pub fn text(&self) -> &str {
        &self.text
    }
}

impl MessageList {

    pub fn new() -> MessageList {
        MessageList { messages: vec![] }
    }

    pub fn info(&mut self, text: &str) {
        self.messages.push(Message { text: String::from_str(text), ty: MessageType::Info });
    }

    pub fn error(&mut self, text: &str) {
        self.messages.push(Message { text: String::from_str(text), ty: MessageType::Error });
    }

    pub fn items(&self) -> Iter<Message> {
        self.messages.iter()
    }

}
<|endoftext|>


<commit_before>use super::{ASTNode, SymbolTable};

use std::rc::Rc;
use std::borrow::Borrow;
use std::hash::Hash;

// pub type STCell<'a> = Rc<RefCell<SymbolTable<'a>>>;

pub struct Annotated<'a, T> where T: ASTNode {
    node: T, scope: Rc<SymbolTable<'a>>
}

impl<'a, T> Annotated<'a, T> where T: ASTNode {

    /// Get the type signature associated with the given name.
    ///
    /// This returns a borrowed reference to the type signature
    /// associated with that name in the current scope. The argument
    /// can be any type `Q` such that `String: Borrow<Q>` (i.e.
    /// you can pass an `&str` to this function).
    pub fn get_type<Q: ?Sized>(&self, name: &Q) -> Option<&Type>
    where String: Borrow<Q>, Q: Hash + Eq {
        self.scope.get(name)
    }

    /// Check if the given name is defined in this scope.
    ///
    /// The argument can be any type `Q` such that `String: Borrow<Q>`
    /// (i.e. you can pass an `&str` to this function).
    pub fn is_defined_here<Q: ?Sized>(&self, name: &Q) -> bool
    where String: Borrow<Q>, Q: Hash + Eq {
        self.scope.contains_key(name)
    }

}

#[derive(Debug, Clone)]
pub enum Type { /// Reference types
                Ref(Reference)
                /// Primitive types
              , Prim(Primitive)
                /// An algebraic data type.
                ///
                /// Represented as a vector of variants.
              , Algebraic(Vec<Type>)
                /// A function.
                ///
                /// Represented as a vector of parameters and a return type.
              , Function { params: Vec<Type>
                         , rt: Rc<Type> }
                /// A unique symbol type (`'symbol` syntax)
              , Symbol(String)
              }

/// Reference types (pointers)
///
/// TODO: how will lifetime analysis actually work?
#[derive(Debug, Clone)]
pub enum Reference { /// A reference borrowed from another scope.
                     ///
                     /// Semantically similar to Rust's `&`-pointers.
                     ///
                     /// TODO: should this track where it was borrowed from?
                     /// (can we even perform this analysis at this stage?)
                     Borrowed(Rc<Type>)
                     /// A moved reference from another scope
                     ///
                     /// TODO: should this track where it was moved from?
                     /// (can we even perform this analysis at this stage?)
                   , Moved(Rc<Type>)
                     /// A unique (i.e. boxed) reference.
                   , Unique(Rc<Type>)
                     /// A raw (unsafe) reference.
                     ///
                     /// Unfortunately we have to have this because of
                     /// reasons (i.e, FFI).
                   , Raw(Rc<Type>)
                   }

/// Language primitive types
///
/// TODO: add some form of provable-refinement (i.e. we know that some value
/// is not just a bool at compile time but that it's true/false, or we know
/// some value is not just a number but the number 1382, or whatever).
#[derive(Debug, Clone, Copy)]
pub enum Primitive { Int
                   , Uint
                   , Byte
                   , Char
                   , Str
                   , Bool
                   , Float
                   // TODO: finish
                   }
<commit_msg>Apparently the rustdoc parser hates Haskell comma style. Oops<commit_after>use super::{ASTNode, SymbolTable};

use std::rc::Rc;
use std::borrow::Borrow;
use std::hash::Hash;

// pub type STCell<'a> = Rc<RefCell<SymbolTable<'a>>>;

pub struct Annotated<'a, T> where T: ASTNode {
    node: T, scope: Rc<SymbolTable<'a>>
}

impl<'a, T> Annotated<'a, T> where T: ASTNode {

    /// Get the type signature associated with the given name.
    ///
    /// This returns a borrowed reference to the type signature
    /// associated with that name in the current scope. The argument
    /// can be any type `Q` such that `String: Borrow<Q>` (i.e.
    /// you can pass an `&str` to this function).
    pub fn get_type<Q: ?Sized>(&self, name: &Q) -> Option<&Type>
    where String: Borrow<Q>, Q: Hash + Eq {
        self.scope.get(name)
    }

    /// Check if the given name is defined in this scope.
    ///
    /// The argument can be any type `Q` such that `String: Borrow<Q>`
    /// (i.e. you can pass an `&str` to this function).
    pub fn is_defined_here<Q: ?Sized>(&self, name: &Q) -> bool
    where String: Borrow<Q>, Q: Hash + Eq {
        self.scope.contains_key(name)
    }

}

#[derive(Debug, Clone)]
pub enum Type {
    /// Reference types
    Ref(Reference),
    /// Primitive types
    Prim(Primitive),
    /// An algebraic data type.
    ///
    /// Represented as a vector of variants.
    Algebraic(Vec<Type>),
    /// A function.
    ///
    /// Represented as a vector of parameters and a return type.
    Function { params: Vec<Type>
             , rt: Rc<Type> },
    /// A unique symbol type (`'symbol` syntax)
    Symbol(String)
}

/// Reference types (pointers)
///
/// TODO: how will lifetime analysis actually work?
#[derive(Debug, Clone)]
pub enum Reference {
    /// A reference borrowed from another scope.
    ///
    /// Semantically similar to Rust's `&`-pointers.
    ///
    /// TODO: should this track where it was borrowed from?
    /// (can we even perform this analysis at this stage?)
    Borrowed(Rc<Type>),
    /// A moved reference from another scope
    ///
    /// TODO: should this track where it was moved from?
    /// (can we even perform this analysis at this stage?)
    Moved(Rc<Type>),
    /// A unique (i.e. boxed) reference.
    Unique(Rc<Type>),
    /// A raw (unsafe) reference.
    ///
    /// Unfortunately we have to have this because of
    /// reasons (i.e, FFI).
    Raw(Rc<Type>)
}

/// Language primitive types
///
/// TODO: add some form of provable-refinement (i.e. we know that some value
/// is not just a bool at compile time but that it's true/false, or we know
/// some value is not just a number but the number 1382, or whatever).
#[derive(Debug, Clone, Copy)]
pub enum Primitive { Int
                   , Uint
                   , Byte
                   , Char
                   , Str
                   , Bool
                   , Float
                   // TODO: finish
                   }
<|endoftext|>


<commit_before>use seed::prelude::*;
use crate::Msg;

pub mod mersenne_utils {
    extern crate num_bigint;
    extern crate num_traits;

    use num_traits::{Pow,Num};
    use num_bigint::{BigInt,ToBigInt};

    pub fn mersennes_discovery_dates(n:usize) -> String {
        let mersennes_discovery_dates:Vec<Vec<&str>> = vec![
            //TODO: Complete this list all the way upto 50
            //TODO: We could include download links etc
            vec![""],//faux zero entry to make things easier when reading this vector
            vec!["500BC"],
            vec!["500BC"],
            vec!["275BC"],
            vec!["275BC"],
            vec!["1456"],
            vec!["1588"],
            vec!["1588"],
            vec!["1772"],
            vec!["1883"],
            vec!["1911"],
            vec!["1914"],
            vec!["1876"],
            vec!["30-Jan-1952"],
            vec!["30-Jan-1952"],
            vec!["26-Jun-1952"],
            vec!["7-Oct-1952"],
            vec!["9-Oct-1952"],
            vec!["8-Sep-1957"],
            vec!["3-Nov-1961"],
            vec!["3-Nov-1961"],
            vec!["11-May-1963"],
            vec!["16-May-1963"],
            vec!["2-Jun-1963"],
            vec!["4-Mar-1971"],
            vec!["30-Oct-1978"],
            vec!["9-Feb-1979"],
            vec!["8-Apr-1979"],
            vec!["25-Sep-1982"],
            vec!["28-Jan-1988"],
            vec!["20-Sep-1983"],
            vec!["6-Sep-1985"],
            vec!["19-Feb-1992"],
            vec!["10-Jan-1994"],
            vec!["3-Sep-1996"],
            vec!["12-Nov-1996"],
            vec!["24-Aug-1997"],
            vec!["27-Jan-1998"],
            vec!["1-Jun-1999"],
            vec!["14-Nov-2001"],
            vec!["17-Nov-2003"],
            vec!["28-May-2004"],
            vec!["26-Feb-2005"],
            vec!["15-Dec-2005"],
            vec!["4-Sep-2006"],
            vec!["23-Aug-2008"],
            vec!["06-Sep-2009"],
            vec!["12-Apr-2008"],
            vec!["25-Jan-2013"],
            vec!["07-Jan-2016"],
            vec!["26-Dec-2017"],
        ];

        mersennes_discovery_dates[n][0].to_owned()
    }

    pub fn mersennes() -> Vec<Vec<usize>> {
        vec![
            //vec![p,digits]
            vec![0,     0],//faux zero entry to make things easier when reading this vector
            vec![2,     1],
            vec![3,     1],
            vec![5,     2],
            vec![7,     3],
            vec![13,    4],
            vec![17,    6],
            vec![19,    6],
            vec![31,   10],
            vec![61,   19],
            vec![89,   27],
            vec![107,  33],
            vec![127,  39],
            vec![521,  157],
            vec![607,  183],
            vec![1279, 386],
            vec![2203, 664],
            vec![2281, 687],
            vec![3217, 969],
            vec![4253,1281],
            vec![4423,1332],
            vec![9689,2917],
            vec![9941,2993],
            vec![11213,3376],
            vec![19937,6002],
            vec![21701,6533],
            vec![23209,6987],
            vec![44497,13395],
            vec![86243,25962],
            vec![110503,33265],
            vec![132049,39751],
            vec![216091,65050],
            vec![756839,227832],
            vec![859433,258716],
            vec![1257787,378632],
            vec![1398269,420921],
            vec![2976221,895832],
            vec![3021377,909526],
            vec![6972593,2098960],
            vec![13466917,4053946],
            vec![20996011,6320430],
            vec![24036583,7235733],
            vec![25964951,7816230],
            vec![30402457,9152052],
            vec![32582657,9808358],
            vec![37156667,11185272],
            vec![42643801,12837064],
            vec![43112609,12978189],
            vec![57885161,17425170],
            vec![74207281,22338618],
            vec![77232917,23249425],
        ]
    }

    pub fn nth_mersenne_prime (candidate:&str) -> u64 {
        let big_candidate:BigInt = num_bigint::BigInt::from_str_radix(&candidate, 10).unwrap();
        let mersennes:Vec<Vec<usize>> = mersennes();

        let mut answer:u64 = 0;
        let big_two:BigInt = 2.to_bigint().unwrap();
        for n in 1..mersennes.len() {
            let mprime:BigInt = big_two.pow(mersennes[n][0]) - 1;
            if big_candidate == mprime {
                answer = n as u64;
                break
            } else if big_candidate < mprime {
                break
            }
        }

        answer
    }
}

pub fn render() -> seed::dom_types::Node<Msg> {
    let mut html = vec![];

    let mersennes = mersenne_utils::mersennes();

    for n in 1..mersennes.len() {
        let download_txt:String = vec!["https://static.bigprimes.net/archive/mersenne/M",&n.to_string(),".txt"].into_iter().collect();
        let download_zip:String = vec!["https://static.bigprimes.net/archive/mersenne/M",&n.to_string(),".zip"].into_iter().collect();
        html.push(
            tr![
                td![n.to_string()],
                td!["2",sup![mersennes[n][0].to_string()],"-1"],
                td![mersennes[n][1].to_string()],
                td![mersenne_utils::mersennes_discovery_dates(n)],
                if n >= 30 {a![attrs!{At::Href => download_zip},"ZIP"]} else {a![attrs!{At::Href => download_txt},"TXT"]}
            ]
        );
    }

    html.reverse();

    div![
        h1!["The Mersenne Numbers"],
        br![],
        br![],
        br![],
        table![
            attrs!{At::Class => "mersennetable text"},
            tbody![
                tr![
                    td![
                        b!["No."]
                    ],
                    td![
                        b!["Prime"]
                    ],
                    td![
                        b!["Digits"]
                    ],
                    td![
                        b!["Discovered"]
                    ],
                    td![
                        b!["Download"]
                    ]
                ],
                html
            ]
        ]
    ]
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn mersennes_discovery_dates_test() {
        assert_eq!(mersenne_utils::mersennes_discovery_dates(0), "");
        assert_eq!(mersenne_utils::mersennes_discovery_dates(50), "26-Dec-2017");
    }

    #[test]
    fn nth_mersenne_prime_test() {
        assert_eq!(mersenne_utils::nth_mersenne_prime("127"), 4);
        assert_eq!(mersenne_utils::nth_mersenne_prime("9"), 0);
    }

    #[test]
    fn mersenne_test() {
        let mersennes:Vec<Vec<usize>> = mersenne_utils::mersennes();
        assert_eq!(mersennes[0][0], 0);
        assert_eq!(mersennes[0][1], 0);

        assert_eq!(mersennes[2][0], 3);
        assert_eq!(mersennes[2][1], 1);
    }
}<commit_msg>Line endings and white space<commit_after>use seed::prelude::*;
use crate::Msg;

pub mod mersenne_utils {
    extern crate num_bigint;
    extern crate num_traits;

    use num_traits::{Pow,Num};
    use num_bigint::{BigInt,ToBigInt};

    pub fn mersennes_discovery_dates(n:usize) -> String {
        let mersennes_discovery_dates:Vec<Vec<&str>> = vec![
            //TODO: Complete this list all the way upto 50
            //TODO: We could include download links etc
            vec![""],//faux zero entry to make things easier when reading this vector
            vec!["500BC"],
            vec!["500BC"],
            vec!["275BC"],
            vec!["275BC"],
            vec!["1456"],
            vec!["1588"],
            vec!["1588"],
            vec!["1772"],
            vec!["1883"],
            vec!["1911"],
            vec!["1914"],
            vec!["1876"],
            vec!["30-Jan-1952"],
            vec!["30-Jan-1952"],
            vec!["26-Jun-1952"],
            vec!["7-Oct-1952"],
            vec!["9-Oct-1952"],
            vec!["8-Sep-1957"],
            vec!["3-Nov-1961"],
            vec!["3-Nov-1961"],
            vec!["11-May-1963"],
            vec!["16-May-1963"],
            vec!["2-Jun-1963"],
            vec!["4-Mar-1971"],
            vec!["30-Oct-1978"],
            vec!["9-Feb-1979"],
            vec!["8-Apr-1979"],
            vec!["25-Sep-1982"],
            vec!["28-Jan-1988"],
            vec!["20-Sep-1983"],
            vec!["6-Sep-1985"],
            vec!["19-Feb-1992"],
            vec!["10-Jan-1994"],
            vec!["3-Sep-1996"],
            vec!["12-Nov-1996"],
            vec!["24-Aug-1997"],
            vec!["27-Jan-1998"],
            vec!["1-Jun-1999"],
            vec!["14-Nov-2001"],
            vec!["17-Nov-2003"],
            vec!["28-May-2004"],
            vec!["26-Feb-2005"],
            vec!["15-Dec-2005"],
            vec!["4-Sep-2006"],
            vec!["23-Aug-2008"],
            vec!["06-Sep-2009"],
            vec!["12-Apr-2008"],
            vec!["25-Jan-2013"],
            vec!["07-Jan-2016"],
            vec!["26-Dec-2017"],
        ];

        mersennes_discovery_dates[n][0].to_owned()
    }

    pub fn mersennes() -> Vec<Vec<usize>> {
        vec![
            //vec![p,digits]
            vec![0,     0],//faux zero entry to make things easier when reading this vector
            vec![2,     1],
            vec![3,     1],
            vec![5,     2],
            vec![7,     3],
            vec![13,    4],
            vec![17,    6],
            vec![19,    6],
            vec![31,   10],
            vec![61,   19],
            vec![89,   27],
            vec![107,  33],
            vec![127,  39],
            vec![521,  157],
            vec![607,  183],
            vec![1279, 386],
            vec![2203, 664],
            vec![2281, 687],
            vec![3217, 969],
            vec![4253,1281],
            vec![4423,1332],
            vec![9689,2917],
            vec![9941,2993],
            vec![11213,3376],
            vec![19937,6002],
            vec![21701,6533],
            vec![23209,6987],
            vec![44497,13395],
            vec![86243,25962],
            vec![110503,33265],
            vec![132049,39751],
            vec![216091,65050],
            vec![756839,227832],
            vec![859433,258716],
            vec![1257787,378632],
            vec![1398269,420921],
            vec![2976221,895832],
            vec![3021377,909526],
            vec![6972593,2098960],
            vec![13466917,4053946],
            vec![20996011,6320430],
            vec![24036583,7235733],
            vec![25964951,7816230],
            vec![30402457,9152052],
            vec![32582657,9808358],
            vec![37156667,11185272],
            vec![42643801,12837064],
            vec![43112609,12978189],
            vec![57885161,17425170],
            vec![74207281,22338618],
            vec![77232917,23249425],
        ]
    }

    pub fn nth_mersenne_prime (candidate:&str) -> u64 {
        let big_candidate:BigInt = num_bigint::BigInt::from_str_radix(&candidate, 10).unwrap();
        let mersennes:Vec<Vec<usize>> = mersennes();

        let mut answer:u64 = 0;
        let big_two:BigInt = 2.to_bigint().unwrap();
        for n in 1..mersennes.len() {
            let mprime:BigInt = big_two.pow(mersennes[n][0]) - 1;
            if big_candidate == mprime {
                answer = n as u64;
                break
            } else if big_candidate < mprime {
                break
            }
        }

        answer
    }
}

pub fn render() -> seed::dom_types::Node<Msg> {
    let mut html = vec![];

    let mersennes = mersenne_utils::mersennes();

    for n in 1..mersennes.len() {
        let download_txt:String = vec!["https://static.bigprimes.net/archive/mersenne/M",&n.to_string(),".txt"].into_iter().collect();
        let download_zip:String = vec!["https://static.bigprimes.net/archive/mersenne/M",&n.to_string(),".zip"].into_iter().collect();
        html.push(
            tr![
                td![n.to_string()],
                td!["2",sup![mersennes[n][0].to_string()],"-1"],
                td![mersennes[n][1].to_string()],
                td![mersenne_utils::mersennes_discovery_dates(n)],
                if n >= 30 {a![attrs!{At::Href => download_zip},"ZIP"]} else {a![attrs!{At::Href => download_txt},"TXT"]}
            ]
        );
    }

    html.reverse();

    div![
        h1!["The Mersenne Numbers"],
        br![],
        br![],
        br![],
        table![
            attrs!{At::Class => "mersennetable text"},
            tbody![
                tr![
                    td![
                        b!["No."]
                    ],
                    td![
                        b!["Prime"]
                    ],
                    td![
                        b!["Digits"]
                    ],
                    td![
                        b!["Discovered"]
                    ],
                    td![
                        b!["Download"]
                    ]
                ],
                html
            ]
        ]
    ]
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn mersennes_discovery_dates_test() {
        assert_eq!(mersenne_utils::mersennes_discovery_dates(0), "");
        assert_eq!(mersenne_utils::mersennes_discovery_dates(50), "26-Dec-2017");
    }

    #[test]
    fn nth_mersenne_prime_test() {
        assert_eq!(mersenne_utils::nth_mersenne_prime("127"), 4);
        assert_eq!(mersenne_utils::nth_mersenne_prime("9"), 0);
    }

    #[test]
    fn mersenne_test() {
        let mersennes:Vec<Vec<usize>> = mersenne_utils::mersennes();
        assert_eq!(mersennes[0][0], 0);
        assert_eq!(mersennes[0][1], 0);

        assert_eq!(mersennes[2][0], 3);
        assert_eq!(mersennes[2][1], 1);
    }
}<|endoftext|>


<commit_before>use seed::prelude::*;
use crate::Msg;

pub mod mersenne_utils {
    extern crate num_bigint;
    extern crate num_traits;

    use num_traits::{Pow,Num};
    use num_bigint::{BigInt,ToBigInt};

    pub fn mersennes_discovery_dates(n:usize) -> String {
        let mersennes_discovery_dates:Vec<Vec<&str>> = vec![
            //TODO: Complete this list all the way upto 50
            //TODO: We could include download links etc
            vec![""],//faux zero entry to make things easier when reading this vector
            vec!["500BC"],
            vec!["500BC"],
            vec!["275BC"],
            vec!["275BC"],
            vec!["1456"],
            vec!["1588"],
            vec!["1588"],
            vec!["1772"],
            vec!["1883"],
            vec!["1911"],
            vec!["1914"],
            vec!["1876"],
            vec!["30-Jan-1952"],
            vec!["30-Jan-1952"],
            vec!["26-Jun-1952"],
            vec!["7-Oct-1952"],
            vec!["9-Oct-1952"],
            vec!["8-Sep-1957"],
            vec!["3-Nov-1961"],
            vec!["3-Nov-1961"],
            vec!["11-May-1963"],
            vec!["16-May-1963"],
            vec!["2-Jun-1963"],
            vec!["4-Mar-1971"],
            vec!["30-Oct-1978"],
            vec!["9-Feb-1979"],
            vec!["8-Apr-1979"],
            vec!["25-Sep-1982"],
            vec!["28-Jan-1988"],
            vec!["20-Sep-1983"],
            vec!["6-Sep-1985"],
            vec!["19-Feb-1992"],
            vec!["10-Jan-1994"],
            vec!["3-Sep-1996"],
            vec!["12-Nov-1996"],
            vec!["24-Aug-1997"],
            vec!["27-Jan-1998"],
            vec!["1-Jun-1999"],
            vec!["14-Nov-2001"],
            vec!["17-Nov-2003"],
            vec!["28-May-2004"],
            vec!["26-Feb-2005"],
            vec!["15-Dec-2005"],
            vec!["4-Sep-2006"],
            vec!["23-Aug-2008"],
            vec!["06-Sep-2009"],
            vec!["12-Apr-2008"],
            vec!["25-Jan-2013"],
            vec!["07-Jan-2016"],
            vec!["26-Dec-2017"],
        ];

        mersennes_discovery_dates[n][0].to_owned()
    }

    pub fn mersennes() -> Vec<Vec<usize>> {
        vec![
            //TODO: Complete this list all the way upto 50
            //vec![p,digits]
            vec![0,      0],//faux zero entry to make things easier when reading this vector
            vec![2,     1],
            vec![3,     1],
            vec![5,     2],
            vec![7,     3],
            vec![13,    4],
            vec![17,    6],
            vec![19,    6],
            vec![31,   10],
            vec![61,   19],
            vec![89,   27],
            vec![107,  33],
            vec![127,  39],
            vec![521,  157],
            vec![607,  183],
            vec![1279, 386],
            vec![2203, 664],
            vec![2281, 687],
            vec![3217, 969],
            vec![4253,1281],
            vec![4423,1332],
            vec![9689,2917],
            vec![9941,2993],
            vec![11213,3376],
            vec![19937,6002],
            vec![21701,6533],
            vec![23209,6987],
            vec![44497,13395],
            vec![86243,25962],
            vec![110503,33265],
            vec![132049,39751],
            vec![216091,65050],
            vec![756839,227832],
            vec![859433,258716],
            vec![1257787,378632],
            vec![1398269,420921],
            vec![2976221,895832],
            vec![3021377,909526],
            vec![6972593,2098960],
            vec![13466917,4053946],
            vec![20996011,6320430],
            vec![24036583,7235733],
            vec![25964951,7816230],
            vec![30402457,9152052],
            vec![32582657,9808358],
            vec![37156667,11185272],
            vec![42643801,12837064],
            vec![43112609,12978189],
            vec![57885161,17425170],
            vec![74207281,22338618],
            vec![77232917,23249425],
        ]
    }

    pub fn nth_mersenne_prime (candidate:&str) -> u64 {
        let big_candidate:BigInt = num_bigint::BigInt::from_str_radix(&candidate, 10).unwrap();
        let mersennes:Vec<Vec<usize>> = mersennes();

        let mut answer:u64 = 0;
        let big_two:BigInt = 2.to_bigint().unwrap();
        for n in 1..mersennes.len() {
            let mprime:BigInt = big_two.pow(mersennes[n][0]) - 1;
            if big_candidate == mprime {
                answer = n as u64;
                break
            } else if big_candidate < mprime {
                break
            }
        }

        answer
    }
}

pub fn render() -> seed::dom_types::Node<Msg> {
    let mut html = vec![];

    let mersennes = mersenne_utils::mersennes();

    for n in 1..mersennes.len() {
        let download_txt:String = vec!["https://static.bigprimes.net/archive/mersenne/M",&n.to_string(),".txt"].into_iter().collect();
        let download_zip:String = vec!["https://static.bigprimes.net/archive/mersenne/M",&n.to_string(),".zip"].into_iter().collect();
        html.push(
            tr![
                td![n.to_string()],
                td!["2",sup![mersennes[n][0].to_string()],"-1"],
                td![mersennes[n][1].to_string()],
                td![mersenne_utils::mersennes_discovery_dates(n)],
                if n >= 30 {a![attrs!{At::Href => download_zip},"ZIP"]} else {a![attrs!{At::Href => download_txt},"TXT"]}
            ]
        );
    }

    html.reverse();

    div![
        h1!["The Mersenne Numbers"],
        br![],
        br![],
        br![],
        table![
            attrs!{At::Class => "mersennetable text"},
            tbody![
                tr![
                    td![
                        b!["No."]
                    ],
                    td![
                        b!["Prime"]
                    ],
                    td![
                        b!["Digits"]
                    ],
                    td![
                        b!["Discovered"]
                    ],
                    td![
                        b!["Download"]
                    ]
                ],
                html
            ]
        ]
    ]
}<commit_msg>Removed completed todo, for the 50 mersennes<commit_after>use seed::prelude::*;
use crate::Msg;

pub mod mersenne_utils {
    extern crate num_bigint;
    extern crate num_traits;

    use num_traits::{Pow,Num};
    use num_bigint::{BigInt,ToBigInt};

    pub fn mersennes_discovery_dates(n:usize) -> String {
        let mersennes_discovery_dates:Vec<Vec<&str>> = vec![
            //TODO: Complete this list all the way upto 50
            //TODO: We could include download links etc
            vec![""],//faux zero entry to make things easier when reading this vector
            vec!["500BC"],
            vec!["500BC"],
            vec!["275BC"],
            vec!["275BC"],
            vec!["1456"],
            vec!["1588"],
            vec!["1588"],
            vec!["1772"],
            vec!["1883"],
            vec!["1911"],
            vec!["1914"],
            vec!["1876"],
            vec!["30-Jan-1952"],
            vec!["30-Jan-1952"],
            vec!["26-Jun-1952"],
            vec!["7-Oct-1952"],
            vec!["9-Oct-1952"],
            vec!["8-Sep-1957"],
            vec!["3-Nov-1961"],
            vec!["3-Nov-1961"],
            vec!["11-May-1963"],
            vec!["16-May-1963"],
            vec!["2-Jun-1963"],
            vec!["4-Mar-1971"],
            vec!["30-Oct-1978"],
            vec!["9-Feb-1979"],
            vec!["8-Apr-1979"],
            vec!["25-Sep-1982"],
            vec!["28-Jan-1988"],
            vec!["20-Sep-1983"],
            vec!["6-Sep-1985"],
            vec!["19-Feb-1992"],
            vec!["10-Jan-1994"],
            vec!["3-Sep-1996"],
            vec!["12-Nov-1996"],
            vec!["24-Aug-1997"],
            vec!["27-Jan-1998"],
            vec!["1-Jun-1999"],
            vec!["14-Nov-2001"],
            vec!["17-Nov-2003"],
            vec!["28-May-2004"],
            vec!["26-Feb-2005"],
            vec!["15-Dec-2005"],
            vec!["4-Sep-2006"],
            vec!["23-Aug-2008"],
            vec!["06-Sep-2009"],
            vec!["12-Apr-2008"],
            vec!["25-Jan-2013"],
            vec!["07-Jan-2016"],
            vec!["26-Dec-2017"],
        ];

        mersennes_discovery_dates[n][0].to_owned()
    }

    pub fn mersennes() -> Vec<Vec<usize>> {
        vec![
            //vec![p,digits]
            vec![0,     0],//faux zero entry to make things easier when reading this vector
            vec![2,     1],
            vec![3,     1],
            vec![5,     2],
            vec![7,     3],
            vec![13,    4],
            vec![17,    6],
            vec![19,    6],
            vec![31,   10],
            vec![61,   19],
            vec![89,   27],
            vec![107,  33],
            vec![127,  39],
            vec![521,  157],
            vec![607,  183],
            vec![1279, 386],
            vec![2203, 664],
            vec![2281, 687],
            vec![3217, 969],
            vec![4253,1281],
            vec![4423,1332],
            vec![9689,2917],
            vec![9941,2993],
            vec![11213,3376],
            vec![19937,6002],
            vec![21701,6533],
            vec![23209,6987],
            vec![44497,13395],
            vec![86243,25962],
            vec![110503,33265],
            vec![132049,39751],
            vec![216091,65050],
            vec![756839,227832],
            vec![859433,258716],
            vec![1257787,378632],
            vec![1398269,420921],
            vec![2976221,895832],
            vec![3021377,909526],
            vec![6972593,2098960],
            vec![13466917,4053946],
            vec![20996011,6320430],
            vec![24036583,7235733],
            vec![25964951,7816230],
            vec![30402457,9152052],
            vec![32582657,9808358],
            vec![37156667,11185272],
            vec![42643801,12837064],
            vec![43112609,12978189],
            vec![57885161,17425170],
            vec![74207281,22338618],
            vec![77232917,23249425],
        ]
    }

    pub fn nth_mersenne_prime (candidate:&str) -> u64 {
        let big_candidate:BigInt = num_bigint::BigInt::from_str_radix(&candidate, 10).unwrap();
        let mersennes:Vec<Vec<usize>> = mersennes();

        let mut answer:u64 = 0;
        let big_two:BigInt = 2.to_bigint().unwrap();
        for n in 1..mersennes.len() {
            let mprime:BigInt = big_two.pow(mersennes[n][0]) - 1;
            if big_candidate == mprime {
                answer = n as u64;
                break
            } else if big_candidate < mprime {
                break
            }
        }

        answer
    }
}

pub fn render() -> seed::dom_types::Node<Msg> {
    let mut html = vec![];

    let mersennes = mersenne_utils::mersennes();

    for n in 1..mersennes.len() {
        let download_txt:String = vec!["https://static.bigprimes.net/archive/mersenne/M",&n.to_string(),".txt"].into_iter().collect();
        let download_zip:String = vec!["https://static.bigprimes.net/archive/mersenne/M",&n.to_string(),".zip"].into_iter().collect();
        html.push(
            tr![
                td![n.to_string()],
                td!["2",sup![mersennes[n][0].to_string()],"-1"],
                td![mersennes[n][1].to_string()],
                td![mersenne_utils::mersennes_discovery_dates(n)],
                if n >= 30 {a![attrs!{At::Href => download_zip},"ZIP"]} else {a![attrs!{At::Href => download_txt},"TXT"]}
            ]
        );
    }

    html.reverse();

    div![
        h1!["The Mersenne Numbers"],
        br![],
        br![],
        br![],
        table![
            attrs!{At::Class => "mersennetable text"},
            tbody![
                tr![
                    td![
                        b!["No."]
                    ],
                    td![
                        b!["Prime"]
                    ],
                    td![
                        b!["Digits"]
                    ],
                    td![
                        b!["Discovered"]
                    ],
                    td![
                        b!["Download"]
                    ]
                ],
                html
            ]
        ]
    ]
}<|endoftext|>


<commit_before>use super::{Result, Specifier, SpecifierClass};
use std::rc::Rc;

pub fn spec(s: &str) -> Result<Rc<Specifier>> {
    Specifier::from_str(s)
}

impl Specifier {
    fn from_str(s: &str) -> Result<Rc<Specifier>> {
        #[cfg(not(any(target_os = "linux", target_os = "android")))] {
            if s.starts_with("abstract") {
                warn!("Abstract-namespaced UNIX sockets are unlikely to be supported here");
            }
        }

        macro_rules! my {
            ($x:expr) => {
                for pre in $x.get_prefixes() {
                    if s.starts_with(pre) {
                        let rest = &s[pre.len()..];
                        return $x.construct(s, rest);
                    }
                }
            }
        }
        list_of_all_specifier_classes!(my);

        if s == "inetd-ws:" {
            return spec("ws-l:inetd:")
        } else if s.starts_with("l-ws-unix:") {
            return spec(&format!("ws-l:unix-l:{}", &s[10..]))
        } else if s.starts_with("l-ws-abstract:") {
            return spec(&format!("ws-l:abstract-l::{}", &s[14..]))
        }

        if s.starts_with("open:") {
            return Err("There is no `open:` specifier. Consider `open-async:` or `readfile:` or `writefile:` or `appendfile:`")?;
        }

        #[cfg(not(unix))] {
            if s.starts_with("unix") || s.starts_with("abstract") {
                    Err("`unix*:` or `abstract*:` are not supported in this Websocat build")?
            }
        }

        #[cfg(not(feature = "tokio-process"))] {
            if s.starts_with("sh-c:") {
                Err("`sh-c:` is not supported in this Websocat build")?
            } else if s.starts_with("exec:") {
                Err("`exec:` is not supported in this Websocat build")?
            }
        }

        error!("Invalid specifier string `{}`. See --long-help for the list of specifiers", s);
        Err("Wrong specifier")?
    }
}
<commit_msg>Refuse to silently degrade wss:// to ws://<commit_after>use super::{Result, Specifier, SpecifierClass};
use std::rc::Rc;

pub fn spec(s: &str) -> Result<Rc<Specifier>> {
    Specifier::from_str(s)
}

impl Specifier {
    fn from_str(s: &str) -> Result<Rc<Specifier>> {
        #[cfg(not(feature="ssl"))] {
            if s.starts_with("wss://") {
                Err("SSL is not compiled in. Use ws:// or get/make another Websocat build.")?
            }
        }

        #[cfg(not(any(target_os = "linux", target_os = "android")))] {
            if s.starts_with("abstract") {
                warn!("Abstract-namespaced UNIX sockets are unlikely to be supported here");
            }
        }

        macro_rules! my {
            ($x:expr) => {
                for pre in $x.get_prefixes() {
                    if s.starts_with(pre) {
                        let rest = &s[pre.len()..];
                        return $x.construct(s, rest);
                    }
                }
            }
        }
        list_of_all_specifier_classes!(my);

        if s == "inetd-ws:" {
            return spec("ws-l:inetd:")
        } else if s.starts_with("l-ws-unix:") {
            return spec(&format!("ws-l:unix-l:{}", &s[10..]))
        } else if s.starts_with("l-ws-abstract:") {
            return spec(&format!("ws-l:abstract-l::{}", &s[14..]))
        }

        if s.starts_with("open:") {
            return Err("There is no `open:` specifier. Consider `open-async:` or `readfile:` or `writefile:` or `appendfile:`")?;
        }

        #[cfg(not(unix))] {
            if s.starts_with("unix") || s.starts_with("abstract") {
                    Err("`unix*:` or `abstract*:` are not supported in this Websocat build")?
            }
        }

        #[cfg(not(feature = "tokio-process"))] {
            if s.starts_with("sh-c:") {
                Err("`sh-c:` is not supported in this Websocat build")?
            } else if s.starts_with("exec:") {
                Err("`exec:` is not supported in this Websocat build")?
            }
        }

        error!("Invalid specifier string `{}`. See --long-help for the list of specifiers", s);
        Err("Wrong specifier")?
    }
}
<|endoftext|>