<commit_before>#![allow(dead_code)]
#![allow(unused_variables)]
#[macro_use]
extern crate lazy_static;
extern crate ctrlc;
mod html;

use std::cell::RefCell;
use std::rc::Rc;
use std::time::Instant;
use std::collections::BTreeMap;
use std::fs::File;
use std::marker::PhantomData;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Mutex, Arc};

pub type SpanPtr = RefCell<Span>;
thread_local!(static THREAD_FRAME: RefCell<ThreadFrame> = RefCell::new(ThreadFrame::new()));

lazy_static!{
    static ref SETTED_NAME: Mutex<Option<String>> = Mutex::new(None);
    static ref INTERRUPTED_TICKS: Arc<AtomicUsize> = Arc::new(AtomicUsize::new(0));

}

pub struct ThreadFrame {
    epoch: Instant,
    root: Rc<SpanPtr>,
    events: Vec<Event>,
    dumped_time: usize,
}

struct Event {
    name: &'static str,
    start_ns: u64,
    span: Rc<SpanPtr>,
}

#[derive(Clone)]
pub struct Span {
    value: u64,
    count: u64,
    children: BTreeMap<&'static str, Rc<SpanPtr>>
}

impl Event {
    fn new(name:&'static str, timestamp: u64, span: Rc<SpanPtr>) -> Event {
        Event {
            name: name,
            start_ns: timestamp,
            span: span
        }
    }
}

impl ThreadFrame {

    fn new() -> ThreadFrame {
        let root = Span::new();
        let epoch = Instant::now();
        ThreadFrame {
            epoch: epoch,
            root: root.clone(),
            events: vec![Event::new("Self", ns_since_epoch(epoch), root)],
            dumped_time: 0,
        }
    }

    fn root(&self) -> &SpanPtr {
        &self.root
    }

    fn time_since_start(&self) -> u64 {
        ns_since_epoch(self.epoch)
    }

    fn start_span(&mut self, name: &'static str) {
        let timestamp = ns_since_epoch(self.epoch);
        let span = Span::sub_span(&self.events[self.events.len()-1].span, name);
        self.events.push(Event::new(name, timestamp, span));
    }

    fn end_span(&mut self) {
        let new_time = INTERRUPTED_TICKS.load(Ordering::SeqCst);
        if self.dumped_time < new_time {
            let name: String = SETTED_NAME.lock().unwrap().clone()
                                .expect("Profiler: received interrupt without setted name.");
            File::create(&name)
                    .and_then(|ref mut  file| dump_html(file, &self) )
                    .expect("could not write profiler data");
            self.dumped_time = new_time;
        };

        let timestamp = ns_since_epoch(self.epoch);
        let event = self.events.pop().expect("ThreadFrame::end_span() called events.pop() without a currently running span!");
        let current = event.span;
        // dump self span
        {
            let mut aspan = current.borrow_mut();
            aspan.value += timestamp - event.start_ns;
            aspan.count += 1;
        }
    }

}

fn ns_since_epoch(epoch: Instant) -> u64 {
    let elapsed = epoch.elapsed();
    elapsed.as_secs() * 1000_000_000 + elapsed.subsec_nanos() as u64
}

impl Span {

    fn new() -> Rc<SpanPtr> {
        Rc::new(RefCell::new(Span {
            value: 0,
            count: 0,
            children: BTreeMap::new()
        }))
    }

    fn sub_span(this: &Rc<SpanPtr>, name: &'static str) -> Rc<SpanPtr> {
        let mut parent = this.borrow_mut();
        let  aspan = parent.children.entry(name)
                                     .or_insert_with(|| Span::new());
        aspan.clone()
    }
}

#[cfg(not(feature="nomock"))]
pub fn start(name: &'static str) {

}

#[cfg(not(feature="nomock"))]
pub fn end() {

}

#[cfg(feature="nomock")]
pub fn start(name: &'static str) {
    THREAD_FRAME.with(|thread| thread.borrow_mut().start_span(name));
}

#[cfg(feature="nomock")]
pub fn end() {
    THREAD_FRAME.with(|thread| thread.borrow_mut().end_span());
}

fn spans() -> Rc<SpanPtr> {
    THREAD_FRAME.with(|library| {
        let library = library.borrow();

        let root = library.root.clone();
        root.borrow_mut().value = ns_since_epoch(library.epoch) - library.events[0].start_ns;
        root
    })
}

#[macro_export]
macro_rules! profiler_span{
    ($name:expr, $val:expr) => {
        {
            let _p = $crate::ProfilerSpan::new($name);
            let r = $val;
            drop(_p);
            r
        }
    }
}

#[macro_export]
macro_rules! profiler_next_span{
    ($name:expr) => {
            $crate::end();
            $crate::start($name);
    }
}

pub struct ProfilerSpan<'a> {
    name: &'static str,
    _phantom: PhantomData<&'a ()>
}

impl<'a> Drop for ProfilerSpan<'a> {
    fn drop(&mut self) {
        end();
    }
}

impl<'scope> ProfilerSpan<'scope> {

    pub fn new(name: &'static str) -> ProfilerSpan<'static> {
        start(name);
        ProfilerSpan {
            name: name,
            _phantom:PhantomData
        }
    }

    pub fn next_span(& mut self, name: &'static str) {
        end();
        self.name = name;
        start(self.name);
    }

    pub fn sub_span<'smaller>(&'smaller mut self, name: &'static str) -> ProfilerSpan<'smaller>
    where 'scope: 'smaller {
        ProfilerSpan::new(name)
    }
}

#[cfg(not(feature="nomock"))]
pub fn init_handler(file: String) {
}

#[cfg(feature="nomock")]
pub fn init_handler(file: String) {
    use std::time::{SystemTime, UNIX_EPOCH};

    *SETTED_NAME.lock().unwrap() = Some(file);

    let r = INTERRUPTED_TICKS.clone();
    ::ctrlc::set_handler(move || {
        let secs = SystemTime::now()
                            .duration_since(UNIX_EPOCH)
                            .unwrap().as_secs() as usize;
        r.store(secs, Ordering::SeqCst);
    }).expect("Error setting Ctrl-C handler");
}

pub use html::dump_html;
<commit_msg>make dump pub<commit_after>#![allow(dead_code)]
#![allow(unused_variables)]
#[macro_use]
extern crate lazy_static;
extern crate ctrlc;
pub mod html;

use std::cell::RefCell;
use std::rc::Rc;
use std::time::Instant;
use std::collections::BTreeMap;
use std::fs::File;
use std::marker::PhantomData;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Mutex, Arc};

pub type SpanPtr = RefCell<Span>;
thread_local!(static THREAD_FRAME: RefCell<ThreadFrame> = RefCell::new(ThreadFrame::new()));

lazy_static!{
    static ref SETTED_NAME: Mutex<Option<String>> = Mutex::new(None);
    static ref INTERRUPTED_TICKS: Arc<AtomicUsize> = Arc::new(AtomicUsize::new(0));

}

pub struct ThreadFrame {
    epoch: Instant,
    root: Rc<SpanPtr>,
    events: Vec<Event>,
    dumped_time: usize,
}

struct Event {
    name: &'static str,
    start_ns: u64,
    span: Rc<SpanPtr>,
}

#[derive(Clone)]
pub struct Span {
    value: u64,
    count: u64,
    children: BTreeMap<&'static str, Rc<SpanPtr>>
}

impl Event {
    fn new(name:&'static str, timestamp: u64, span: Rc<SpanPtr>) -> Event {
        Event {
            name: name,
            start_ns: timestamp,
            span: span
        }
    }
}

impl ThreadFrame {

    fn new() -> ThreadFrame {
        let root = Span::new();
        let epoch = Instant::now();
        ThreadFrame {
            epoch: epoch,
            root: root.clone(),
            events: vec![Event::new("Self", ns_since_epoch(epoch), root)],
            dumped_time: 0,
        }
    }

    fn root(&self) -> &SpanPtr {
        &self.root
    }

    fn time_since_start(&self) -> u64 {
        ns_since_epoch(self.epoch)
    }

    fn start_span(&mut self, name: &'static str) {
        let timestamp = ns_since_epoch(self.epoch);
        let span = Span::sub_span(&self.events[self.events.len()-1].span, name);
        self.events.push(Event::new(name, timestamp, span));
    }

    fn end_span(&mut self) {
        let new_time = INTERRUPTED_TICKS.load(Ordering::SeqCst);
        if self.dumped_time < new_time {
            let name: String = SETTED_NAME.lock().unwrap().clone()
                                .expect("Profiler: received interrupt without setted name.");
            File::create(&name)
                    .and_then(|ref mut  file| dump_html(file, &self) )
                    .expect("could not write profiler data");
            self.dumped_time = new_time;
        };

        let timestamp = ns_since_epoch(self.epoch);
        let event = self.events.pop().expect("ThreadFrame::end_span() called events.pop() without a currently running span!");
        let current = event.span;
        // dump self span
        {
            let mut aspan = current.borrow_mut();
            aspan.value += timestamp - event.start_ns;
            aspan.count += 1;
        }
    }

}

fn ns_since_epoch(epoch: Instant) -> u64 {
    let elapsed = epoch.elapsed();
    elapsed.as_secs() * 1000_000_000 + elapsed.subsec_nanos() as u64
}

impl Span {

    fn new() -> Rc<SpanPtr> {
        Rc::new(RefCell::new(Span {
            value: 0,
            count: 0,
            children: BTreeMap::new()
        }))
    }

    fn sub_span(this: &Rc<SpanPtr>, name: &'static str) -> Rc<SpanPtr> {
        let mut parent = this.borrow_mut();
        let  aspan = parent.children.entry(name)
                                     .or_insert_with(|| Span::new());
        aspan.clone()
    }
}

#[cfg(not(feature="nomock"))]
pub fn start(name: &'static str) {

}

#[cfg(not(feature="nomock"))]
pub fn end() {

}

#[cfg(feature="nomock")]
pub fn start(name: &'static str) {
    THREAD_FRAME.with(|thread| thread.borrow_mut().start_span(name));
}

#[cfg(feature="nomock")]
pub fn end() {
    THREAD_FRAME.with(|thread| thread.borrow_mut().end_span());
}

fn spans() -> Rc<SpanPtr> {
    THREAD_FRAME.with(|library| {
        let library = library.borrow();

        let root = library.root.clone();
        root.borrow_mut().value = ns_since_epoch(library.epoch) - library.events[0].start_ns;
        root
    })
}

#[macro_export]
macro_rules! profiler_span{
    ($name:expr, $val:expr) => {
        {
            let _p = $crate::ProfilerSpan::new($name);
            let r = $val;
            drop(_p);
            r
        }
    }
}

#[macro_export]
macro_rules! profiler_next_span{
    ($name:expr) => {
            $crate::end();
            $crate::start($name);
    }
}

pub struct ProfilerSpan<'a> {
    name: &'static str,
    _phantom: PhantomData<&'a ()>
}

impl<'a> Drop for ProfilerSpan<'a> {
    fn drop(&mut self) {
        end();
    }
}

impl<'scope> ProfilerSpan<'scope> {

    pub fn new(name: &'static str) -> ProfilerSpan<'static> {
        start(name);
        ProfilerSpan {
            name: name,
            _phantom:PhantomData
        }
    }

    pub fn next_span(& mut self, name: &'static str) {
        end();
        self.name = name;
        start(self.name);
    }

    pub fn sub_span<'smaller>(&'smaller mut self, name: &'static str) -> ProfilerSpan<'smaller>
    where 'scope: 'smaller {
        ProfilerSpan::new(name)
    }
}

#[cfg(not(feature="nomock"))]
pub fn init_handler(file: String) {
}

#[cfg(feature="nomock")]
pub fn init_handler(file: String) {
    use std::time::{SystemTime, UNIX_EPOCH};

    *SETTED_NAME.lock().unwrap() = Some(file);

    let r = INTERRUPTED_TICKS.clone();
    ::ctrlc::set_handler(move || {
        let secs = SystemTime::now()
                            .duration_since(UNIX_EPOCH)
                            .unwrap().as_secs() as usize;
        r.store(secs, Ordering::SeqCst);
    }).expect("Error setting Ctrl-C handler");
}

pub use html::dump_html;
<|endoftext|>


<commit_before>// Mangled symbol arrangements:
//
//   (a) One-off internal symbol.
//          pattern:  {CXXBRIDGE} $ {NAME}
//          examples:
//             - cxxbridge1$exception
//          defining characteristics:
//             - 2 segments
//             - starts with cxxbridge
//
//   (b) Behavior on a builtin binding without generic parameter.
//          pattern:  {CXXBRIDGE} $ {TYPE} $ {NAME}
//          examples:
//             - cxxbridge1$string$len
//          defining characteristics:
//             - 3 segments
//             - starts with cxxbridge
//
//   (c) Behavior on a builtin binding with generic parameter.
//          pattern:  {CXXBRIDGE} $ {TYPE} $ {PARAM...} $ {NAME}
//          examples:
//             - cxxbridge1$box$org$rust$Struct$alloc
//             - cxxbridge1$unique_ptr$std$vector$u8$drop
//          defining characteristics:
//             - 4+ segments
//             - starts with cxxbridge
//
//   (d) User-defined extern function.
//          pattern:  {NAMESPACE...} $ {CXXBRIDGE} $ {NAME}
//          examples:
//             - cxxbridge1$new_client
//             - org$rust$cxxbridge1$new_client
//          defining characteristics:
//             - cxxbridge is second from end
//          FIXME: conflict with (a) if they collide with one of our one-off symbol names in the global namespace
//
//   (e) User-defined extern member function.
//          pattern:  {NAMESPACE...} $ {CXXBRIDGE} $ {TYPE} $ {NAME}
//          examples:
//             - org$cxxbridge1$Struct$get
//          defining characteristics:
//             - cxxbridge is third from end
//          FIXME: conflict with (b) if e.g. user binds a type in global namespace that collides with our builtin type names
//
//   (f) Operator overload.
//          pattern:  {NAMESPACE...} $ {CXXBRIDGE} $ {TYPE} $ operator $ {NAME}
//          examples:
//             - org$rust$cxxbridge1$Struct$operator$eq
//          defining characteristics:
//             - second segment from end is `operator` (not possible in type or namespace names)
//
//   (g) Closure trampoline.
//          pattern:  {NAMESPACE...} $ {CXXBRIDGE} $ {TYPE?} $ {NAME} $ {ARGUMENT} $ {DIRECTION}
//          examples:
//             - org$rust$cxxbridge1$Struct$invoke$f$0
//          defining characteristics:
//             - last symbol is `0` (C half) or `1` (Rust half) which are not legal identifiers on their own

use crate::syntax::symbol::{self, Symbol};
use crate::syntax::{ExternFn, Pair, Types};

const CXXBRIDGE: &str = "cxxbridge1";

macro_rules! join {
    ($($segment:expr),+ $(,)?) => {
        symbol::join(&[$(&$segment),+])
    };
}

pub fn extern_fn(efn: &ExternFn, types: &Types) -> Symbol {
    match &efn.receiver {
        Some(receiver) => {
            let receiver_ident = types.resolve(&receiver.ty);
            join!(
                efn.name.namespace,
                CXXBRIDGE,
                receiver_ident.name.cxx,
                efn.name.rust,
            )
        }
        None => join!(efn.name.namespace, CXXBRIDGE, efn.name.rust),
    }
}

pub fn operator(receiver: &Pair, operator: &'static str) -> Symbol {
    join!(
        receiver.namespace,
        CXXBRIDGE,
        receiver.cxx,
        "operator",
        operator,
    )
}

// The C half of a function pointer trampoline.
pub fn c_trampoline(efn: &ExternFn, var: &Pair, types: &Types) -> Symbol {
    join!(extern_fn(efn, types), var.rust, 0)
}

// The Rust half of a function pointer trampoline.
pub fn r_trampoline(efn: &ExternFn, var: &Pair, types: &Types) -> Symbol {
    join!(extern_fn(efn, types), var.rust, 1)
}
<commit_msg>Document the arrangements of preprocessor variables<commit_after>// Mangled symbol arrangements:
//
//   (a) One-off internal symbol.
//          pattern:  {CXXBRIDGE} $ {NAME}
//          examples:
//             - cxxbridge1$exception
//          defining characteristics:
//             - 2 segments
//             - starts with cxxbridge
//
//   (b) Behavior on a builtin binding without generic parameter.
//          pattern:  {CXXBRIDGE} $ {TYPE} $ {NAME}
//          examples:
//             - cxxbridge1$string$len
//          defining characteristics:
//             - 3 segments
//             - starts with cxxbridge
//
//   (c) Behavior on a builtin binding with generic parameter.
//          pattern:  {CXXBRIDGE} $ {TYPE} $ {PARAM...} $ {NAME}
//          examples:
//             - cxxbridge1$box$org$rust$Struct$alloc
//             - cxxbridge1$unique_ptr$std$vector$u8$drop
//          defining characteristics:
//             - 4+ segments
//             - starts with cxxbridge
//
//   (d) User-defined extern function.
//          pattern:  {NAMESPACE...} $ {CXXBRIDGE} $ {NAME}
//          examples:
//             - cxxbridge1$new_client
//             - org$rust$cxxbridge1$new_client
//          defining characteristics:
//             - cxxbridge is second from end
//          FIXME: conflict with (a) if they collide with one of our one-off symbol names in the global namespace
//
//   (e) User-defined extern member function.
//          pattern:  {NAMESPACE...} $ {CXXBRIDGE} $ {TYPE} $ {NAME}
//          examples:
//             - org$cxxbridge1$Struct$get
//          defining characteristics:
//             - cxxbridge is third from end
//          FIXME: conflict with (b) if e.g. user binds a type in global namespace that collides with our builtin type names
//
//   (f) Operator overload.
//          pattern:  {NAMESPACE...} $ {CXXBRIDGE} $ {TYPE} $ operator $ {NAME}
//          examples:
//             - org$rust$cxxbridge1$Struct$operator$eq
//          defining characteristics:
//             - second segment from end is `operator` (not possible in type or namespace names)
//
//   (g) Closure trampoline.
//          pattern:  {NAMESPACE...} $ {CXXBRIDGE} $ {TYPE?} $ {NAME} $ {ARGUMENT} $ {DIRECTION}
//          examples:
//             - org$rust$cxxbridge1$Struct$invoke$f$0
//          defining characteristics:
//             - last symbol is `0` (C half) or `1` (Rust half) which are not legal identifiers on their own
//
//
// Mangled preprocessor variable arrangements:
//
//   (A) One-off internal variable.
//          pattern:  {CXXBRIDGE} _ {NAME}
//          examples:
//             - CXXBRIDGE1_PANIC
//             - CXXBRIDGE1_RUST_STRING
//          defining characteristics:
//             - NAME does not begin with STRUCT or ENUM
//
//   (B) Guard around user-defined type.
//          pattern:  {CXXBRIDGE} _ {STRUCT or ENUM} _ {NAMESPACE...} $ {TYPE}
//          examples:
//             - CXXBRIDGE1_STRUCT_org$rust$Struct
//             - CXXBRIDGE1_ENUM_Enabled

use crate::syntax::symbol::{self, Symbol};
use crate::syntax::{ExternFn, Pair, Types};

const CXXBRIDGE: &str = "cxxbridge1";

macro_rules! join {
    ($($segment:expr),+ $(,)?) => {
        symbol::join(&[$(&$segment),+])
    };
}

pub fn extern_fn(efn: &ExternFn, types: &Types) -> Symbol {
    match &efn.receiver {
        Some(receiver) => {
            let receiver_ident = types.resolve(&receiver.ty);
            join!(
                efn.name.namespace,
                CXXBRIDGE,
                receiver_ident.name.cxx,
                efn.name.rust,
            )
        }
        None => join!(efn.name.namespace, CXXBRIDGE, efn.name.rust),
    }
}

pub fn operator(receiver: &Pair, operator: &'static str) -> Symbol {
    join!(
        receiver.namespace,
        CXXBRIDGE,
        receiver.cxx,
        "operator",
        operator,
    )
}

// The C half of a function pointer trampoline.
pub fn c_trampoline(efn: &ExternFn, var: &Pair, types: &Types) -> Symbol {
    join!(extern_fn(efn, types), var.rust, 0)
}

// The Rust half of a function pointer trampoline.
pub fn r_trampoline(efn: &ExternFn, var: &Pair, types: &Types) -> Symbol {
    join!(extern_fn(efn, types), var.rust, 1)
}
<|endoftext|>


<commit_before>extern crate bindgen;
extern crate gcc;

use std::env;
use std::path::PathBuf;

fn main() {

    gcc::Config::new()
        .cpp(true)
        .define("NDEBUG", Some("1"))
        .file("clingo/libgringo/src/control.cc")
        .file("clingo/libgringo/src/term.cc")
        .file("clingo/libgringo/src/symbol.cc")
        .file("clingo/libgringo/src/primes.cc")
        .file("clingo/libgringo/src/backend.cc")
        .file("clingo/libgringo/src/lua.cc")
        .file("clingo/libgringo/src/scripts.cc")
        .file("clingo/libgringo/src/python.cc")
        .file("clingo/libgringo/src/terms.cc")
        .file("clingo/libgringo/src/ground/statements.cc")
        .file("clingo/libgringo/src/ground/literals.cc")
        .file("clingo/libgringo/src/ground/instantiation.cc")
        .file("clingo/libgringo/src/input/groundtermparser.cc")
        .file("generated/input/nongroundgrammar/grammar.cc")
        .file("generated/input/groundtermgrammar/grammar.cc")
        .file("clingo/libgringo/src/input/nongroundparser.cc")
        .file("clingo/libgringo/src/input/aggregate.cc")
        .file("clingo/libgringo/src/input/aggregates.cc")
        .file("clingo/libgringo/src/input/program.cc")
        .file("clingo/libgringo/src/ground/program.cc")
        .file("clingo/libgringo/src/input/programbuilder.cc")
        .file("clingo/libgringo/src/input/literals.cc")
        .file("clingo/libgringo/src/input/statement.cc")
        .file("clingo/libgringo/src/input/literal.cc")
        .file("clingo/libgringo/src/input/theory.cc")
        .file("clingo/libgringo/src/output/statements.cc")
        .file("clingo/libgringo/src/output/literals.cc")
        .file("clingo/libgringo/src/output/aggregates.cc")
        .file("clingo/libgringo/src/output/output.cc")
        .file("clingo/libgringo/src/output/statement.cc")
        .file("clingo/libgringo/src/output/literal.cc")
        .file("clingo/libgringo/src/output/theory.cc")
        .include("clingo/libgringo")
        .include("generated")
        .include("clingo/liblp")
        .include("clingo/libreify")
        .compile("libgringo.a");

    gcc::Config::new()
        .cpp(true)
        .define("NDEBUG", Some("1"))
        .file("clingo/libprogram_opts/src/application.cpp")
        .file("clingo/libprogram_opts/src/alarm.cpp")
        .file("clingo/libprogram_opts/src/program_options.cpp")
        .file("clingo/libprogram_opts/src/string_convert.cpp")
        .file("clingo/libprogram_opts/src/value_store.cpp")
        .include("clingo/libprogram_opts")
        .compile("libprogram_opts.a");

    gcc::Config::new()
        .cpp(true)
        .define("NDEBUG", Some("1"))
        .file("clingo/libreify/src/program.cc")
        .include("clingo/libreify")
        .include("clingo/liblp")
        .include("clingo/libgringo")
        .compile("libreify.a");

    gcc::Config::new()
        .cpp(true)
        .define("NDEBUG", Some("1"))
        .file("clingo/liblp/src/aspif.cpp")
        .file("clingo/liblp/src/clingo.cpp")
        .file("clingo/liblp/src/theory_data.cpp")
        .file("clingo/liblp/src/smodels.cpp")
        .file("clingo/liblp/src/convert.cpp")
        .file("clingo/liblp/src/rule_utils.cpp")
        .file("clingo/liblp/src/match_basic_types.cpp")
        .file("clingo/liblp/src/aspif_text.cpp")
        .include("clingo/liblp")
        .compile("liblp.a");

    gcc::Config::new()
        .cpp(true)
        .define("NDEBUG", Some("1"))
        .define("WITH_THREADS", Some("0"))
        .file("clingo/libclingo/src/clingocontrol.cc")
        .include("clingo/libclingo")
        .include("clingo/libgringo")
        .include("clingo/liblp")
        .include("clingo/libclasp")
        .include("clingo/libprogram_opts")
        .compile("libclingo.a");

    gcc::Config::new()
        .cpp(true)
        .define("NDEBUG", Some("1"))
        .define("WITH_THREADS", Some("0"))
        .file("clingo/libclasp/src/parallel_solve.cpp")
        .file("clingo/libclasp/src/solver_types.cpp")
        .file("clingo/libclasp/src/solver_strategies.cpp")
        .file("clingo/libclasp/src/clause.cpp")
        .file("clingo/libclasp/src/logic_program.cpp")
        .file("clingo/libclasp/src/clasp_facade.cpp")
        .file("clingo/libclasp/src/cb_enumerator.cpp")
        .file("clingo/libclasp/src/minimize_constraint.cpp")
        .file("clingo/libclasp/src/clingo.cpp")
        .file("clingo/libclasp/src/shared_context.cpp")
        .file("clingo/libclasp/src/dependency_graph.cpp")
        .file("clingo/libclasp/src/logic_program_types.cpp")
        .file("clingo/libclasp/src/asp_preprocessor.cpp")
        .file("clingo/libclasp/src/clasp_options.cpp")
        .file("clingo/libclasp/src/heuristics.cpp")
        .file("clingo/libclasp/src/timer.cpp")
        .file("clingo/libclasp/src/lookahead.cpp")
        .file("clingo/libclasp/src/constraint.cpp")
        .file("clingo/libclasp/src/unfounded_check.cpp")
        .file("clingo/libclasp/src/solver.cpp")
        .file("clingo/libclasp/src/model_enumerators.cpp")
        .file("clingo/libclasp/src/clasp_output.cpp")
        .file("clingo/libclasp/src/parser.cpp")
        .file("clingo/libclasp/src/solve_algorithms.cpp")
        .file("clingo/libclasp/src/enumerator.cpp")
        .file("clingo/libclasp/src/program_builder.cpp")
        .file("clingo/libclasp/src/satelite.cpp")
        .file("clingo/libclasp/src/statistics.cpp")
        .file("clingo/libclasp/src/weight_constraint.cpp")
        .include("clingo/libclasp")
        .include("clingo/libclingo")
        .include("clingo/liblp")
        .include("clingo/libprogram_opts")
        .compile("libclasp.a");

    println!("cargo:rustc-link-lib=clingo");

    let out_dir = env::var("OUT_DIR").unwrap();

    let bindings = bindgen::builder()
        .no_unstable_rust()
        .header("clingo/libgringo/clingo.h")
        .use_core()
        .generate()
        .expect("Unable to generate bindings");

    let out_path = PathBuf::from(out_dir);

    bindings.write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");

}
<commit_msg>automatically checkout clingo from github<commit_after>use std::env;
use std::path::PathBuf;
use std::process::Command;
extern crate bindgen;
extern crate gcc;

fn main() {

    Command::new("git")
        .args(&["clone", "https://github.com/potassco/clingo.git"])
        .status()
        .unwrap();

    Command::new("git")
        .args(&["checkout", "tags/v5.0.0"])
        .status()
        .unwrap();

    gcc::Config::new()
        .cpp(true)
        .define("NDEBUG", Some("1"))
        .file("clingo/libgringo/src/control.cc")
        .file("clingo/libgringo/src/term.cc")
        .file("clingo/libgringo/src/symbol.cc")
        .file("clingo/libgringo/src/primes.cc")
        .file("clingo/libgringo/src/backend.cc")
        .file("clingo/libgringo/src/lua.cc")
        .file("clingo/libgringo/src/scripts.cc")
        .file("clingo/libgringo/src/python.cc")
        .file("clingo/libgringo/src/terms.cc")
        .file("clingo/libgringo/src/ground/statements.cc")
        .file("clingo/libgringo/src/ground/literals.cc")
        .file("clingo/libgringo/src/ground/instantiation.cc")
        .file("clingo/libgringo/src/input/groundtermparser.cc")
        .file("generated/input/nongroundgrammar/grammar.cc")
        .file("generated/input/groundtermgrammar/grammar.cc")
        .file("clingo/libgringo/src/input/nongroundparser.cc")
        .file("clingo/libgringo/src/input/aggregate.cc")
        .file("clingo/libgringo/src/input/aggregates.cc")
        .file("clingo/libgringo/src/input/program.cc")
        .file("clingo/libgringo/src/ground/program.cc")
        .file("clingo/libgringo/src/input/programbuilder.cc")
        .file("clingo/libgringo/src/input/literals.cc")
        .file("clingo/libgringo/src/input/statement.cc")
        .file("clingo/libgringo/src/input/literal.cc")
        .file("clingo/libgringo/src/input/theory.cc")
        .file("clingo/libgringo/src/output/statements.cc")
        .file("clingo/libgringo/src/output/literals.cc")
        .file("clingo/libgringo/src/output/aggregates.cc")
        .file("clingo/libgringo/src/output/output.cc")
        .file("clingo/libgringo/src/output/statement.cc")
        .file("clingo/libgringo/src/output/literal.cc")
        .file("clingo/libgringo/src/output/theory.cc")
        .include("clingo/libgringo")
        .include("generated")
        .include("clingo/liblp")
        .include("clingo/libreify")
        .compile("libgringo.a");

    gcc::Config::new()
        .cpp(true)
        .define("NDEBUG", Some("1"))
        .file("clingo/libprogram_opts/src/application.cpp")
        .file("clingo/libprogram_opts/src/alarm.cpp")
        .file("clingo/libprogram_opts/src/program_options.cpp")
        .file("clingo/libprogram_opts/src/string_convert.cpp")
        .file("clingo/libprogram_opts/src/value_store.cpp")
        .include("clingo/libprogram_opts")
        .compile("libprogram_opts.a");

    gcc::Config::new()
        .cpp(true)
        .define("NDEBUG", Some("1"))
        .file("clingo/libreify/src/program.cc")
        .include("clingo/libreify")
        .include("clingo/liblp")
        .include("clingo/libgringo")
        .compile("libreify.a");

    gcc::Config::new()
        .cpp(true)
        .define("NDEBUG", Some("1"))
        .file("clingo/liblp/src/aspif.cpp")
        .file("clingo/liblp/src/clingo.cpp")
        .file("clingo/liblp/src/theory_data.cpp")
        .file("clingo/liblp/src/smodels.cpp")
        .file("clingo/liblp/src/convert.cpp")
        .file("clingo/liblp/src/rule_utils.cpp")
        .file("clingo/liblp/src/match_basic_types.cpp")
        .file("clingo/liblp/src/aspif_text.cpp")
        .include("clingo/liblp")
        .compile("liblp.a");

    gcc::Config::new()
        .cpp(true)
        .define("NDEBUG", Some("1"))
        .define("WITH_THREADS", Some("0"))
        .file("clingo/libclingo/src/clingocontrol.cc")
        .include("clingo/libclingo")
        .include("clingo/libgringo")
        .include("clingo/liblp")
        .include("clingo/libclasp")
        .include("clingo/libprogram_opts")
        .compile("libclingo.a");

    gcc::Config::new()
        .cpp(true)
        .define("NDEBUG", Some("1"))
        .define("WITH_THREADS", Some("0"))
        .file("clingo/libclasp/src/parallel_solve.cpp")
        .file("clingo/libclasp/src/solver_types.cpp")
        .file("clingo/libclasp/src/solver_strategies.cpp")
        .file("clingo/libclasp/src/clause.cpp")
        .file("clingo/libclasp/src/logic_program.cpp")
        .file("clingo/libclasp/src/clasp_facade.cpp")
        .file("clingo/libclasp/src/cb_enumerator.cpp")
        .file("clingo/libclasp/src/minimize_constraint.cpp")
        .file("clingo/libclasp/src/clingo.cpp")
        .file("clingo/libclasp/src/shared_context.cpp")
        .file("clingo/libclasp/src/dependency_graph.cpp")
        .file("clingo/libclasp/src/logic_program_types.cpp")
        .file("clingo/libclasp/src/asp_preprocessor.cpp")
        .file("clingo/libclasp/src/clasp_options.cpp")
        .file("clingo/libclasp/src/heuristics.cpp")
        .file("clingo/libclasp/src/timer.cpp")
        .file("clingo/libclasp/src/lookahead.cpp")
        .file("clingo/libclasp/src/constraint.cpp")
        .file("clingo/libclasp/src/unfounded_check.cpp")
        .file("clingo/libclasp/src/solver.cpp")
        .file("clingo/libclasp/src/model_enumerators.cpp")
        .file("clingo/libclasp/src/clasp_output.cpp")
        .file("clingo/libclasp/src/parser.cpp")
        .file("clingo/libclasp/src/solve_algorithms.cpp")
        .file("clingo/libclasp/src/enumerator.cpp")
        .file("clingo/libclasp/src/program_builder.cpp")
        .file("clingo/libclasp/src/satelite.cpp")
        .file("clingo/libclasp/src/statistics.cpp")
        .file("clingo/libclasp/src/weight_constraint.cpp")
        .include("clingo/libclasp")
        .include("clingo/libclingo")
        .include("clingo/liblp")
        .include("clingo/libprogram_opts")
        .compile("libclasp.a");

    println!("cargo:rustc-link-lib=clingo");

    let out_dir = env::var("OUT_DIR").unwrap();

    let bindings = bindgen::builder()
        .no_unstable_rust()
        .header("clingo/libgringo/clingo.h")
        .use_core()
        .generate()
        .expect("Unable to generate bindings");

    let out_path = PathBuf::from(out_dir);

    bindings.write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");

}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2020, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

#![allow(clippy::print_literal)]
#![allow(clippy::unused_io_amount)]

use rustc_version::{version, Version};
#[allow(unused_imports)]
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::exit;

#[allow(dead_code)]
fn rerun_dir<P: AsRef<Path>>(dir: P) {
  for entry in fs::read_dir(dir).unwrap() {
    let entry = entry.unwrap();
    let path = entry.path();
    println!("cargo:rerun-if-changed={}", path.to_string_lossy());

    if path.is_dir() {
      rerun_dir(path);
    }
  }
}

#[allow(dead_code)]
fn hash_changed(
  files: &[&str], out_dir: &str, config: &Path,
) -> Option<([u8; 8], PathBuf)> {
  use std::collections::hash_map::DefaultHasher;
  use std::hash::Hasher;
  use std::io::Read;

  let mut hasher = DefaultHasher::new();

  let paths = files.iter().map(Path::new).chain(std::iter::once(config));

  for path in paths {
    if let Ok(mut f) = std::fs::File::open(path) {
      let mut buf = Vec::new();
      f.read_to_end(&mut buf).unwrap();

      hasher.write(&buf);
    } else {
      panic!("Cannot open {}", path.display());
    }
  }

  let hash = hasher.finish().to_be_bytes();

  let hash_path = Path::new(&out_dir).join("asm.hash");

  if let Ok(old_hash) = std::fs::read(&hash_path) {
    if old_hash == hash {
      return None;
    }
  }

  Some((hash, hash_path))
}

#[cfg(feature = "asm")]
fn build_nasm_files() {
  use std::fs::File;
  use std::io::Write;
  let out_dir = env::var("OUT_DIR").unwrap();

  let dest_path = Path::new(&out_dir).join("config.asm");
  let mut config_file = File::create(&dest_path).unwrap();
  config_file.write(b"	%define private_prefix rav1e\n").unwrap();
  config_file.write(b"	%define ARCH_X86_32 0\n").unwrap();
  config_file.write(b" %define ARCH_X86_64 1\n").unwrap();
  config_file.write(b"	%define PIC 1\n").unwrap();
  config_file.write(b" %define STACK_ALIGNMENT 16\n").unwrap();
  config_file.write(b" %define HAVE_AVX512ICL 1\n").unwrap();
  if env::var("CARGO_CFG_TARGET_OS").unwrap() == "macos" {
    config_file.write(b" %define PREFIX 1\n").unwrap();
  }

  let asm_files = &[
    "src/x86/ipred.asm",
    "src/x86/ipred_ssse3.asm",
    "src/x86/itx.asm",
    "src/x86/itx_ssse3.asm",
    "src/x86/mc_avx2.asm",
    "src/x86/mc_avx512.asm",
    "src/x86/mc_sse.asm",
    "src/x86/me.asm",
    "src/x86/sad_sse2.asm",
    "src/x86/sad_avx.asm",
    "src/x86/satd.asm",
    "src/x86/sse.asm",
    "src/x86/cdef.asm",
    "src/x86/tables.asm",
  ];

  if let Some((hash, hash_path)) =
    hash_changed(asm_files, &out_dir, &dest_path)
  {
    let mut config_include_arg = String::from("-I");
    config_include_arg.push_str(&out_dir);
    config_include_arg.push('/');
    nasm_rs::compile_library_args(
      "rav1easm",
      asm_files,
      &[&config_include_arg, "-Isrc/"],
    )
    .expect(
      "NASM build failed. Make sure you have nasm installed. https://nasm.us",
    );
    std::fs::write(hash_path, &hash[..]).unwrap();
  } else {
    println!("cargo:rustc-link-search={}", out_dir);
  }
  println!("cargo:rustc-link-lib=static=rav1easm");
  rerun_dir("src/x86");
  rerun_dir("src/ext/x86");
}

#[cfg(feature = "asm")]
fn build_asm_files() {
  use std::fs::File;
  use std::io::Write;
  let out_dir = env::var("OUT_DIR").unwrap();

  let dest_path = Path::new(&out_dir).join("config.h");
  let mut config_file = File::create(&dest_path).unwrap();
  config_file.write(b" #define PRIVATE_PREFIX rav1e_\n").unwrap();
  config_file.write(b" #define ARCH_AARCH64 1\n").unwrap();
  config_file.write(b" #define ARCH_ARM 0\n").unwrap();
  config_file.write(b" #define CONFIG_LOG 1 \n").unwrap();
  config_file.write(b" #define HAVE_ASM 1\n").unwrap();
  config_file.sync_all().unwrap();

  let asm_files = &[
    "src/arm/64/cdef.S",
    "src/arm/64/cdef16.S",
    "src/arm/64/mc.S",
    "src/arm/64/mc16.S",
    "src/arm/64/itx.S",
    "src/arm/64/itx16.S",
    "src/arm/64/ipred.S",
    "src/arm/64/ipred16.S",
    "src/arm/64/sad.S",
    "src/arm/tables.S",
  ];

  if let Some((hash, hash_path)) =
    hash_changed(asm_files, &out_dir, &dest_path)
  {
    cc::Build::new()
      .files(asm_files)
      .include(".")
      .include(&out_dir)
      .compile("rav1e-aarch64");

    std::fs::write(hash_path, &hash[..]).unwrap();
  } else {
    println!("cargo:rustc-link-search={}", out_dir);
    println!("cargo:rustc-link-lib=static=rav1e-aarch64");
  }
  rerun_dir("src/arm");
}

fn rustc_version_check() {
  // This should match the version in the CI
  const REQUIRED_VERSION: &str = "1.43.1";
  if version().unwrap() < Version::parse(REQUIRED_VERSION).unwrap() {
    eprintln!("rav1e requires rustc >= {}.", REQUIRED_VERSION);
    exit(1);
  }
}

#[cfg(feature = "asm")]
fn is_nasm_new_enough(
  min_version: Option<(u8, u8, u8)>, nasm_path: &Path,
) -> Result<(), String> {
  match get_output(std::process::Command::new(nasm_path).arg("-v")) {
    Ok(version) => {
      if version.contains("NASM version 0.") {
        Err(version)
      } else if let Some((major, minor, micro)) = min_version {
        let ver = parse_nasm_version(&version)?;
        eprintln!("{:?} {:?} {:?}", min_version, version, ver);
        if major > ver.0
          || (major == ver.0 && minor > ver.1)
          || (major == ver.0 && minor == ver.1 && micro > ver.2)
        {
          Err(version)
        } else {
          Ok(())
        }
      } else {
        Ok(())
      }
    }
    Err(err) => Err(err),
  }
}

#[cfg(feature = "asm")]
fn parse_nasm_version(version_string: &str) -> Result<(u8, u8, u8), String> {
  // Rust regex lib doesn't support empty expressions in alterations,
  // so workaround the other way
  let regex1 =
    regex::Regex::new(r"(?:NASM version )?(\d+)\.(\d+)\.(\d+)").unwrap();
  if let Some(captures) = regex1.captures(version_string) {
    Ok((
      captures[1].parse().expect("Invalid version component"),
      captures[2].parse().expect("Invalid version component"),
      captures[3].parse().expect("Invalid version component"),
    ))
  } else {
    let regex2 = regex::Regex::new(r"(?:NASM version )?(\d+)\.(\d+)").unwrap();
    let captures = regex2
      .captures(version_string)
      .ok_or_else(|| "Unable to parse NASM version string".to_string())?;
    Ok((
      captures[1].parse().expect("Invalid version component"),
      captures[2].parse().expect("Invalid version component"),
      0,
    ))
  }
}

#[test]
fn test_parse_nasm_version() {
  let ver_str = "NASM version 2.14.02 compiled on Jan 22 2019";
  assert_eq!((2, 14, 2), parse_nasm_version(ver_str));
  let ver_str = "NASM version 2.14 compiled on Jan 22 2019";
  assert_eq!((2, 14, 0), parse_nasm_version(ver_str));
}

#[cfg(feature = "asm")]
fn nasm_version_check() -> std::path::PathBuf {
  let nasm_path = std::path::PathBuf::from("nasm");
  match is_nasm_new_enough(Some((2, 14, 0)), &nasm_path) {
    Ok(_) => nasm_path,
    Err(version) => {
      panic!("This version of NASM is too old: {}", version);
    }
  }
}

#[cfg(feature = "asm")]
fn get_output(cmd: &mut std::process::Command) -> Result<String, String> {
  let out = cmd.output().map_err(|e| e.to_string())?;
  if out.status.success() {
    Ok(String::from_utf8_lossy(&out.stdout).to_string())
  } else {
    Err(String::from_utf8_lossy(&out.stderr).to_string())
  }
}

#[allow(unused_variables)]
fn main() {
  rustc_version_check();

  let arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
  let os = env::var("CARGO_CFG_TARGET_OS").unwrap();
  // let env = env::var("CARGO_CFG_TARGET_ENV").unwrap();

  #[cfg(feature = "asm")]
  {
    if arch == "x86_64" {
      println!("cargo:rustc-cfg={}", "nasm_x86_64");
      nasm_version_check();
      build_nasm_files()
    }
    if arch == "aarch64" {
      println!("cargo:rustc-cfg={}", "asm_neon");
      build_asm_files()
    }
  }

  if os == "windows" && cfg!(feature = "decode_test") {
    panic!("Unsupported feature on this platform!");
  }

  vergen::generate_cargo_keys(vergen::ConstantsFlags::all())
    .expect("Unable to generate the cargo keys!");

  println!("cargo:rustc-env=PROFILE={}", env::var("PROFILE").unwrap());
}
<commit_msg>Support apple-silicon<commit_after>// Copyright (c) 2017-2020, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

#![allow(clippy::print_literal)]
#![allow(clippy::unused_io_amount)]

use rustc_version::{version, Version};
#[allow(unused_imports)]
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::exit;

#[allow(dead_code)]
fn rerun_dir<P: AsRef<Path>>(dir: P) {
  for entry in fs::read_dir(dir).unwrap() {
    let entry = entry.unwrap();
    let path = entry.path();
    println!("cargo:rerun-if-changed={}", path.to_string_lossy());

    if path.is_dir() {
      rerun_dir(path);
    }
  }
}

#[allow(dead_code)]
fn hash_changed(
  files: &[&str], out_dir: &str, config: &Path,
) -> Option<([u8; 8], PathBuf)> {
  use std::collections::hash_map::DefaultHasher;
  use std::hash::Hasher;
  use std::io::Read;

  let mut hasher = DefaultHasher::new();

  let paths = files.iter().map(Path::new).chain(std::iter::once(config));

  for path in paths {
    if let Ok(mut f) = std::fs::File::open(path) {
      let mut buf = Vec::new();
      f.read_to_end(&mut buf).unwrap();

      hasher.write(&buf);
    } else {
      panic!("Cannot open {}", path.display());
    }
  }

  let hash = hasher.finish().to_be_bytes();

  let hash_path = Path::new(&out_dir).join("asm.hash");

  if let Ok(old_hash) = std::fs::read(&hash_path) {
    if old_hash == hash {
      return None;
    }
  }

  Some((hash, hash_path))
}

#[cfg(feature = "asm")]
fn build_nasm_files() {
  use std::fs::File;
  use std::io::Write;
  let out_dir = env::var("OUT_DIR").unwrap();

  let dest_path = Path::new(&out_dir).join("config.asm");
  let mut config_file = File::create(&dest_path).unwrap();
  config_file.write(b"	%define private_prefix rav1e\n").unwrap();
  config_file.write(b"	%define ARCH_X86_32 0\n").unwrap();
  config_file.write(b" %define ARCH_X86_64 1\n").unwrap();
  config_file.write(b"	%define PIC 1\n").unwrap();
  config_file.write(b" %define STACK_ALIGNMENT 16\n").unwrap();
  config_file.write(b" %define HAVE_AVX512ICL 1\n").unwrap();
  if env::var("CARGO_CFG_TARGET_OS").unwrap() == "macos" {
    config_file.write(b" %define PREFIX 1\n").unwrap();
  }

  let asm_files = &[
    "src/x86/ipred.asm",
    "src/x86/ipred_ssse3.asm",
    "src/x86/itx.asm",
    "src/x86/itx_ssse3.asm",
    "src/x86/mc_avx2.asm",
    "src/x86/mc_avx512.asm",
    "src/x86/mc_sse.asm",
    "src/x86/me.asm",
    "src/x86/sad_sse2.asm",
    "src/x86/sad_avx.asm",
    "src/x86/satd.asm",
    "src/x86/sse.asm",
    "src/x86/cdef.asm",
    "src/x86/tables.asm",
  ];

  if let Some((hash, hash_path)) =
    hash_changed(asm_files, &out_dir, &dest_path)
  {
    let mut config_include_arg = String::from("-I");
    config_include_arg.push_str(&out_dir);
    config_include_arg.push('/');
    nasm_rs::compile_library_args(
      "rav1easm",
      asm_files,
      &[&config_include_arg, "-Isrc/"],
    )
    .expect(
      "NASM build failed. Make sure you have nasm installed. https://nasm.us",
    );
    std::fs::write(hash_path, &hash[..]).unwrap();
  } else {
    println!("cargo:rustc-link-search={}", out_dir);
  }
  println!("cargo:rustc-link-lib=static=rav1easm");
  rerun_dir("src/x86");
  rerun_dir("src/ext/x86");
}

#[cfg(feature = "asm")]
fn build_asm_files() {
  use std::fs::File;
  use std::io::Write;
  let out_dir = env::var("OUT_DIR").unwrap();

  let dest_path = Path::new(&out_dir).join("config.h");
  let mut config_file = File::create(&dest_path).unwrap();
  if env::var("CARGO_CFG_TARGET_OS").unwrap() == "macos" {
    config_file.write(b" #define PREFIX 1\n").unwrap();
  }
  config_file.write(b" #define PRIVATE_PREFIX rav1e_\n").unwrap();
  config_file.write(b" #define ARCH_AARCH64 1\n").unwrap();
  config_file.write(b" #define ARCH_ARM 0\n").unwrap();
  config_file.write(b" #define CONFIG_LOG 1 \n").unwrap();
  config_file.write(b" #define HAVE_ASM 1\n").unwrap();
  config_file.sync_all().unwrap();

  let asm_files = &[
    "src/arm/64/cdef.S",
    "src/arm/64/cdef16.S",
    "src/arm/64/mc.S",
    "src/arm/64/mc16.S",
    "src/arm/64/itx.S",
    "src/arm/64/itx16.S",
    "src/arm/64/ipred.S",
    "src/arm/64/ipred16.S",
    "src/arm/64/sad.S",
    "src/arm/tables.S",
  ];

  if let Some((hash, hash_path)) =
    hash_changed(asm_files, &out_dir, &dest_path)
  {
    cc::Build::new()
      .files(asm_files)
      .include(".")
      .include(&out_dir)
      .compile("rav1e-aarch64");

    std::fs::write(hash_path, &hash[..]).unwrap();
  } else {
    println!("cargo:rustc-link-search={}", out_dir);
    println!("cargo:rustc-link-lib=static=rav1e-aarch64");
  }
  rerun_dir("src/arm");
}

fn rustc_version_check() {
  // This should match the version in the CI
  const REQUIRED_VERSION: &str = "1.43.1";
  if version().unwrap() < Version::parse(REQUIRED_VERSION).unwrap() {
    eprintln!("rav1e requires rustc >= {}.", REQUIRED_VERSION);
    exit(1);
  }
}

#[cfg(feature = "asm")]
fn is_nasm_new_enough(
  min_version: Option<(u8, u8, u8)>, nasm_path: &Path,
) -> Result<(), String> {
  match get_output(std::process::Command::new(nasm_path).arg("-v")) {
    Ok(version) => {
      if version.contains("NASM version 0.") {
        Err(version)
      } else if let Some((major, minor, micro)) = min_version {
        let ver = parse_nasm_version(&version)?;
        eprintln!("{:?} {:?} {:?}", min_version, version, ver);
        if major > ver.0
          || (major == ver.0 && minor > ver.1)
          || (major == ver.0 && minor == ver.1 && micro > ver.2)
        {
          Err(version)
        } else {
          Ok(())
        }
      } else {
        Ok(())
      }
    }
    Err(err) => Err(err),
  }
}

#[cfg(feature = "asm")]
fn parse_nasm_version(version_string: &str) -> Result<(u8, u8, u8), String> {
  // Rust regex lib doesn't support empty expressions in alterations,
  // so workaround the other way
  let regex1 =
    regex::Regex::new(r"(?:NASM version )?(\d+)\.(\d+)\.(\d+)").unwrap();
  if let Some(captures) = regex1.captures(version_string) {
    Ok((
      captures[1].parse().expect("Invalid version component"),
      captures[2].parse().expect("Invalid version component"),
      captures[3].parse().expect("Invalid version component"),
    ))
  } else {
    let regex2 = regex::Regex::new(r"(?:NASM version )?(\d+)\.(\d+)").unwrap();
    let captures = regex2
      .captures(version_string)
      .ok_or_else(|| "Unable to parse NASM version string".to_string())?;
    Ok((
      captures[1].parse().expect("Invalid version component"),
      captures[2].parse().expect("Invalid version component"),
      0,
    ))
  }
}

#[test]
fn test_parse_nasm_version() {
  let ver_str = "NASM version 2.14.02 compiled on Jan 22 2019";
  assert_eq!((2, 14, 2), parse_nasm_version(ver_str));
  let ver_str = "NASM version 2.14 compiled on Jan 22 2019";
  assert_eq!((2, 14, 0), parse_nasm_version(ver_str));
}

#[cfg(feature = "asm")]
fn nasm_version_check() -> std::path::PathBuf {
  let nasm_path = std::path::PathBuf::from("nasm");
  match is_nasm_new_enough(Some((2, 14, 0)), &nasm_path) {
    Ok(_) => nasm_path,
    Err(version) => {
      panic!("This version of NASM is too old: {}", version);
    }
  }
}

#[cfg(feature = "asm")]
fn get_output(cmd: &mut std::process::Command) -> Result<String, String> {
  let out = cmd.output().map_err(|e| e.to_string())?;
  if out.status.success() {
    Ok(String::from_utf8_lossy(&out.stdout).to_string())
  } else {
    Err(String::from_utf8_lossy(&out.stderr).to_string())
  }
}

#[allow(unused_variables)]
fn main() {
  rustc_version_check();

  let arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
  let os = env::var("CARGO_CFG_TARGET_OS").unwrap();
  // let env = env::var("CARGO_CFG_TARGET_ENV").unwrap();

  #[cfg(feature = "asm")]
  {
    if arch == "x86_64" {
      println!("cargo:rustc-cfg={}", "nasm_x86_64");
      nasm_version_check();
      build_nasm_files()
    }
    if arch == "aarch64" {
      println!("cargo:rustc-cfg={}", "asm_neon");
      build_asm_files()
    }
  }

  if os == "windows" && cfg!(feature = "decode_test") {
    panic!("Unsupported feature on this platform!");
  }

  vergen::generate_cargo_keys(vergen::ConstantsFlags::all())
    .expect("Unable to generate the cargo keys!");

  println!("cargo:rustc-env=PROFILE={}", env::var("PROFILE").unwrap());
}
<|endoftext|>


<commit_before>extern crate gcc;

#[cfg(windows)]
fn opencv_include() -> String {
    if let Ok(dir) = std::env::var("OPENCV_DIR") {
        format!("{}\\include", dir)
    } else {
        eprint!("%OPENCV_DIR% is not set properly.");
        std::process::exit(0x0100);
    }
}

#[cfg(windows)]
fn opencv_link() {
    if let Ok(dir) = std::env::var("OPENCV_LIB") {
        if let Ok(mut files) = std::fs::read_dir(&dir) {
            let opencv_world_entry = files
                .filter_map(|entry| entry.ok())
                .find(|entry| {
                    let file_name = entry.file_name().to_string_lossy().into_owned();
                    file_name.starts_with("opencv_world") && !file_name.ends_with("d.lib")
                });
            if let Some(opencv_world) = opencv_world_entry {
                let opencv_world = opencv_world.file_name();
                let opencv_world = std::path::Path::new(&opencv_world);
                println!("cargo:rustc-link-search=native={}", dir);
                println!("cargo:rustc-link-lib={}", opencv_world.file_stem().unwrap().to_string_lossy());
                return;
            }
        }
        eprint!("Cannot find opencv_world file in provided %OPENCV_DIR%");
        std::process::exit(0x0100);
    } else {
        eprint!("%OPENCV_DIR% is not set properly.");
        std::process::exit(0x0100);
    }
}

#[cfg(unix)]
fn opencv_include() -> &'static str {
    "/usr/local/include"
}

#[cfg(unix)]
fn opencv_link() {
    println!("cargo:rustc-link-search=native=/usr/local/lib");
    println!("cargo:rustc-link-lib=opencv_core");
    println!("cargo:rustc-link-lib=opencv_imgcodecs");
    println!("cargo:rustc-link-lib=opencv_imgproc");
    println!("cargo:rustc-link-lib=opencv_highgui");
    println!("cargo:rustc-link-lib=opencv_videoio");
    println!("cargo:rustc-link-lib=opencv_objdetect");
    println!("cargo:rustc-link-lib=opencv_video");

    if cfg!(feature = "gpu") {
        println!("cargo:rustc-link-lib=opencv_cudaobjdetect");
    }
}

fn main() {
    let mut opencv_config = gcc::Build::new();
    opencv_config
        .cpp(true)
        .file("native/opencv-wrapper.cc")
        .file("native/utils.cc")
        .include("native")
        .include(opencv_include())
        .flag("--std=c++11");

    if cfg!(feature = "gpu") {
        opencv_config.file("native/opencv-gpu.cc");
    }

    opencv_config.compile("libopencv-wrapper.a");
    opencv_link();
}
<commit_msg>Review fix<commit_after>extern crate gcc;

#[cfg(windows)]
fn opencv_include() -> String {
    if let Ok(dir) = std::env::var("OPENCV_DIR") {
        format!("{}\\include", dir)
    } else {
        eprint!("%OPENCV_DIR% is not set properly.");
        std::process::exit(0x0100);
    }
}

#[cfg(windows)]
fn opencv_link() {
    if let Ok(dir) = std::env::var("OPENCV_LIB") {
        if let Ok(mut files) = std::fs::read_dir(&dir) {
            let opencv_world_entry = files
                .filter_map(|entry| entry.ok())
                .find(|entry| {
                    let file_name = entry.file_name().to_string_lossy().into_owned();
                    file_name.starts_with("opencv_world") && !file_name.ends_with("d.lib")
                });
            if let Some(opencv_world) = opencv_world_entry {
                let opencv_world = opencv_world.path();
                println!("cargo:rustc-link-search=native={}", dir);
                println!("cargo:rustc-link-lib={}", opencv_world.file_stem().unwrap().to_string_lossy());
                return;
            }
        }
        eprint!("Cannot find opencv_world file in provided %OPENCV_DIR%");
        std::process::exit(0x0100);
    } else {
        eprint!("%OPENCV_DIR% is not set properly.");
        std::process::exit(0x0100);
    }
}

#[cfg(unix)]
fn opencv_include() -> &'static str {
    "/usr/local/include"
}

#[cfg(unix)]
fn opencv_link() {
    println!("cargo:rustc-link-search=native=/usr/local/lib");
    println!("cargo:rustc-link-lib=opencv_core");
    println!("cargo:rustc-link-lib=opencv_imgcodecs");
    println!("cargo:rustc-link-lib=opencv_imgproc");
    println!("cargo:rustc-link-lib=opencv_highgui");
    println!("cargo:rustc-link-lib=opencv_videoio");
    println!("cargo:rustc-link-lib=opencv_objdetect");
    println!("cargo:rustc-link-lib=opencv_video");

    if cfg!(feature = "gpu") {
        println!("cargo:rustc-link-lib=opencv_cudaobjdetect");
    }
}

fn main() {
    let mut opencv_config = gcc::Build::new();
    opencv_config
        .cpp(true)
        .file("native/opencv-wrapper.cc")
        .file("native/utils.cc")
        .include("native")
        .include(opencv_include())
        .flag("--std=c++11");

    if cfg!(feature = "gpu") {
        opencv_config.file("native/opencv-gpu.cc");
    }

    opencv_config.compile("libopencv-wrapper.a");
    opencv_link();
}
<|endoftext|>


<commit_before>// Copyright 2019 The CryptoCorrosion Contributors
// Copyright 2020 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The ChaCha random number generator.

use ppv_lite86::{dispatch, dispatch_light128};

#[cfg(feature = "rustcrypto_api")] pub use stream_cipher::generic_array;

pub use ppv_lite86::Machine;
use ppv_lite86::{vec128_storage, ArithOps, BitOps32, LaneWords4, MultiLane, StoreBytes, Vec4};

pub(crate) const BLOCK: usize = 64;
pub(crate) const BLOCK64: u64 = BLOCK as u64;
const LOG2_BUFBLOCKS: u64 = 2;
const BUFBLOCKS: u64 = 1 << LOG2_BUFBLOCKS;
pub(crate) const BUFSZ64: u64 = BLOCK64 * BUFBLOCKS;
pub(crate) const BUFSZ: usize = BUFSZ64 as usize;

#[derive(Clone)]
pub struct ChaCha {
    pub(crate) b: vec128_storage,
    pub(crate) c: vec128_storage,
    pub(crate) d: vec128_storage,
}

#[derive(Clone)]
pub struct State<V> {
    pub(crate) a: V,
    pub(crate) b: V,
    pub(crate) c: V,
    pub(crate) d: V,
}

#[inline(always)]
pub(crate) fn round<V: ArithOps + BitOps32>(mut x: State<V>) -> State<V> {
    x.a += x.b;
    x.d = (x.d ^ x.a).rotate_each_word_right16();
    x.c += x.d;
    x.b = (x.b ^ x.c).rotate_each_word_right20();
    x.a += x.b;
    x.d = (x.d ^ x.a).rotate_each_word_right24();
    x.c += x.d;
    x.b = (x.b ^ x.c).rotate_each_word_right25();
    x
}

#[inline(always)]
pub(crate) fn diagonalize<V: LaneWords4>(mut x: State<V>) -> State<V> {
    x.b = x.b.shuffle_lane_words3012();
    x.c = x.c.shuffle_lane_words2301();
    x.d = x.d.shuffle_lane_words1230();
    x
}
#[inline(always)]
pub(crate) fn undiagonalize<V: LaneWords4>(mut x: State<V>) -> State<V> {
    x.b = x.b.shuffle_lane_words1230();
    x.c = x.c.shuffle_lane_words2301();
    x.d = x.d.shuffle_lane_words3012();
    x
}

impl ChaCha {
    #[inline(always)]
    pub fn new(key: &[u8; 32], nonce: &[u8]) -> Self {
        init_chacha(key, nonce)
    }

    #[inline(always)]
    fn pos64<M: Machine>(&self, m: M) -> u64 {
        let d: M::u32x4 = m.unpack(self.d);
        ((d.extract(1) as u64) << 32) | d.extract(0) as u64
    }

    /// Produce 4 blocks of output, advancing the state
    #[inline(always)]
    pub fn refill4(&mut self, drounds: u32, out: &mut [u8; BUFSZ]) {
        refill_wide(self, drounds, out)
    }

    #[inline(always)]
    pub fn set_stream_param(&mut self, param: u32, value: u64) {
        set_stream_param(self, param, value)
    }

    #[inline(always)]
    pub fn get_stream_param(&self, param: u32) -> u64 {
        get_stream_param(self, param)
    }
}

#[inline(always)]
fn refill_wide_impl<Mach: Machine>(
    m: Mach, state: &mut ChaCha, drounds: u32, out: &mut [u8; BUFSZ],
) {
    let k = m.vec([0x6170_7865, 0x3320_646e, 0x7962_2d32, 0x6b20_6574]);
    let mut pos = state.pos64(m);
    let d0: Mach::u32x4 = m.unpack(state.d);
    pos += 1;
    let d1 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0);
    pos += 1;
    let d2 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0);
    pos += 1;
    let d3 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0);

    let b = m.unpack(state.b);
    let c = m.unpack(state.c);
    let mut x = State {
        a: Mach::u32x4x4::from_lanes([k, k, k, k]),
        b: Mach::u32x4x4::from_lanes([b, b, b, b]),
        c: Mach::u32x4x4::from_lanes([c, c, c, c]),
        d: m.unpack(Mach::u32x4x4::from_lanes([d0, d1, d2, d3]).into()),
    };
    for _ in 0..drounds {
        x = round(x);
        x = undiagonalize(round(diagonalize(x)));
    }
    let mut pos = state.pos64(m);
    let d0: Mach::u32x4 = m.unpack(state.d);
    pos += 1;
    let d1 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0);
    pos += 1;
    let d2 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0);
    pos += 1;
    let d3 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0);
    pos += 1;
    let d4 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0);

    let (a, b, c, d) = (
        x.a.to_lanes(),
        x.b.to_lanes(),
        x.c.to_lanes(),
        x.d.to_lanes(),
    );
    let sb = m.unpack(state.b);
    let sc = m.unpack(state.c);
    let sd = [m.unpack(state.d), d1, d2, d3];
    state.d = d4.into();
    let mut words = out.chunks_exact_mut(16);
    for ((((&a, &b), &c), &d), &sd) in a.iter().zip(&b).zip(&c).zip(&d).zip(&sd) {
        (a + k).write_le(words.next().unwrap());
        (b + sb).write_le(words.next().unwrap());
        (c + sc).write_le(words.next().unwrap());
        (d + sd).write_le(words.next().unwrap());
    }
}

dispatch!(m, Mach, {
    fn refill_wide(state: &mut ChaCha, drounds: u32, out: &mut [u8; BUFSZ]) {
        refill_wide_impl(m, state, drounds, out);
    }
});

// Single-block, rounds-only; shared by try_apply_keystream for tails shorter than BUFSZ
// and XChaCha's setup step.
dispatch!(m, Mach, {
    fn refill_narrow_rounds(state: &mut ChaCha, drounds: u32) -> State<vec128_storage> {
        let k: Mach::u32x4 = m.vec([0x6170_7865, 0x3320_646e, 0x7962_2d32, 0x6b20_6574]);
        let mut x = State {
            a: k,
            b: m.unpack(state.b),
            c: m.unpack(state.c),
            d: m.unpack(state.d),
        };
        for _ in 0..drounds {
            x = round(x);
            x = undiagonalize(round(diagonalize(x)));
        }
        State {
            a: x.a.into(),
            b: x.b.into(),
            c: x.c.into(),
            d: x.d.into(),
        }
    }
});

dispatch_light128!(m, Mach, {
    fn set_stream_param(state: &mut ChaCha, param: u32, value: u64) {
        let d: Mach::u32x4 = m.unpack(state.d);
        state.d = d
            .insert((value >> 32) as u32, (param << 1) | 1)
            .insert(value as u32, param << 1)
            .into();
    }
});

dispatch_light128!(m, Mach, {
    fn get_stream_param(state: &ChaCha, param: u32) -> u64 {
        let d: Mach::u32x4 = m.unpack(state.d);
        ((d.extract((param << 1) | 1) as u64) << 32) | d.extract(param << 1) as u64
    }
});

fn read_u32le(xs: &[u8]) -> u32 {
    assert_eq!(xs.len(), 4);
    u32::from(xs[0]) | (u32::from(xs[1]) << 8) | (u32::from(xs[2]) << 16) | (u32::from(xs[3]) << 24)
}

dispatch_light128!(m, Mach, {
    fn init_chacha(key: &[u8; 32], nonce: &[u8]) -> ChaCha {
        let ctr_nonce = [
            0,
            if nonce.len() == 12 {
                read_u32le(&nonce[0..4])
            } else {
                0
            },
            read_u32le(&nonce[nonce.len() - 8..nonce.len() - 4]),
            read_u32le(&nonce[nonce.len() - 4..]),
        ];
        let key0: Mach::u32x4 = m.read_le(&key[..16]);
        let key1: Mach::u32x4 = m.read_le(&key[16..]);
        ChaCha {
            b: key0.into(),
            c: key1.into(),
            d: ctr_nonce.into(),
        }
    }
});

dispatch_light128!(m, Mach, {
    fn init_chacha_x(key: &[u8; 32], nonce: &[u8; 24], rounds: u32) -> ChaCha {
        let key0: Mach::u32x4 = m.read_le(&key[..16]);
        let key1: Mach::u32x4 = m.read_le(&key[16..]);
        let nonce0: Mach::u32x4 = m.read_le(&nonce[..16]);
        let mut state = ChaCha {
            b: key0.into(),
            c: key1.into(),
            d: nonce0.into(),
        };
        let x = refill_narrow_rounds(&mut state, rounds);
        let ctr_nonce1 = [0, 0, read_u32le(&nonce[16..20]), read_u32le(&nonce[20..24])];
        state.b = x.a;
        state.c = x.d;
        state.d = ctr_nonce1.into();
        state
    }
});
<commit_msg>rand_chacha: remove another line of dead code<commit_after>// Copyright 2019 The CryptoCorrosion Contributors
// Copyright 2020 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The ChaCha random number generator.

use ppv_lite86::{dispatch, dispatch_light128};

pub use ppv_lite86::Machine;
use ppv_lite86::{vec128_storage, ArithOps, BitOps32, LaneWords4, MultiLane, StoreBytes, Vec4};

pub(crate) const BLOCK: usize = 64;
pub(crate) const BLOCK64: u64 = BLOCK as u64;
const LOG2_BUFBLOCKS: u64 = 2;
const BUFBLOCKS: u64 = 1 << LOG2_BUFBLOCKS;
pub(crate) const BUFSZ64: u64 = BLOCK64 * BUFBLOCKS;
pub(crate) const BUFSZ: usize = BUFSZ64 as usize;

#[derive(Clone)]
pub struct ChaCha {
    pub(crate) b: vec128_storage,
    pub(crate) c: vec128_storage,
    pub(crate) d: vec128_storage,
}

#[derive(Clone)]
pub struct State<V> {
    pub(crate) a: V,
    pub(crate) b: V,
    pub(crate) c: V,
    pub(crate) d: V,
}

#[inline(always)]
pub(crate) fn round<V: ArithOps + BitOps32>(mut x: State<V>) -> State<V> {
    x.a += x.b;
    x.d = (x.d ^ x.a).rotate_each_word_right16();
    x.c += x.d;
    x.b = (x.b ^ x.c).rotate_each_word_right20();
    x.a += x.b;
    x.d = (x.d ^ x.a).rotate_each_word_right24();
    x.c += x.d;
    x.b = (x.b ^ x.c).rotate_each_word_right25();
    x
}

#[inline(always)]
pub(crate) fn diagonalize<V: LaneWords4>(mut x: State<V>) -> State<V> {
    x.b = x.b.shuffle_lane_words3012();
    x.c = x.c.shuffle_lane_words2301();
    x.d = x.d.shuffle_lane_words1230();
    x
}
#[inline(always)]
pub(crate) fn undiagonalize<V: LaneWords4>(mut x: State<V>) -> State<V> {
    x.b = x.b.shuffle_lane_words1230();
    x.c = x.c.shuffle_lane_words2301();
    x.d = x.d.shuffle_lane_words3012();
    x
}

impl ChaCha {
    #[inline(always)]
    pub fn new(key: &[u8; 32], nonce: &[u8]) -> Self {
        init_chacha(key, nonce)
    }

    #[inline(always)]
    fn pos64<M: Machine>(&self, m: M) -> u64 {
        let d: M::u32x4 = m.unpack(self.d);
        ((d.extract(1) as u64) << 32) | d.extract(0) as u64
    }

    /// Produce 4 blocks of output, advancing the state
    #[inline(always)]
    pub fn refill4(&mut self, drounds: u32, out: &mut [u8; BUFSZ]) {
        refill_wide(self, drounds, out)
    }

    #[inline(always)]
    pub fn set_stream_param(&mut self, param: u32, value: u64) {
        set_stream_param(self, param, value)
    }

    #[inline(always)]
    pub fn get_stream_param(&self, param: u32) -> u64 {
        get_stream_param(self, param)
    }
}

#[inline(always)]
fn refill_wide_impl<Mach: Machine>(
    m: Mach, state: &mut ChaCha, drounds: u32, out: &mut [u8; BUFSZ],
) {
    let k = m.vec([0x6170_7865, 0x3320_646e, 0x7962_2d32, 0x6b20_6574]);
    let mut pos = state.pos64(m);
    let d0: Mach::u32x4 = m.unpack(state.d);
    pos += 1;
    let d1 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0);
    pos += 1;
    let d2 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0);
    pos += 1;
    let d3 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0);

    let b = m.unpack(state.b);
    let c = m.unpack(state.c);
    let mut x = State {
        a: Mach::u32x4x4::from_lanes([k, k, k, k]),
        b: Mach::u32x4x4::from_lanes([b, b, b, b]),
        c: Mach::u32x4x4::from_lanes([c, c, c, c]),
        d: m.unpack(Mach::u32x4x4::from_lanes([d0, d1, d2, d3]).into()),
    };
    for _ in 0..drounds {
        x = round(x);
        x = undiagonalize(round(diagonalize(x)));
    }
    let mut pos = state.pos64(m);
    let d0: Mach::u32x4 = m.unpack(state.d);
    pos += 1;
    let d1 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0);
    pos += 1;
    let d2 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0);
    pos += 1;
    let d3 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0);
    pos += 1;
    let d4 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0);

    let (a, b, c, d) = (
        x.a.to_lanes(),
        x.b.to_lanes(),
        x.c.to_lanes(),
        x.d.to_lanes(),
    );
    let sb = m.unpack(state.b);
    let sc = m.unpack(state.c);
    let sd = [m.unpack(state.d), d1, d2, d3];
    state.d = d4.into();
    let mut words = out.chunks_exact_mut(16);
    for ((((&a, &b), &c), &d), &sd) in a.iter().zip(&b).zip(&c).zip(&d).zip(&sd) {
        (a + k).write_le(words.next().unwrap());
        (b + sb).write_le(words.next().unwrap());
        (c + sc).write_le(words.next().unwrap());
        (d + sd).write_le(words.next().unwrap());
    }
}

dispatch!(m, Mach, {
    fn refill_wide(state: &mut ChaCha, drounds: u32, out: &mut [u8; BUFSZ]) {
        refill_wide_impl(m, state, drounds, out);
    }
});

// Single-block, rounds-only; shared by try_apply_keystream for tails shorter than BUFSZ
// and XChaCha's setup step.
dispatch!(m, Mach, {
    fn refill_narrow_rounds(state: &mut ChaCha, drounds: u32) -> State<vec128_storage> {
        let k: Mach::u32x4 = m.vec([0x6170_7865, 0x3320_646e, 0x7962_2d32, 0x6b20_6574]);
        let mut x = State {
            a: k,
            b: m.unpack(state.b),
            c: m.unpack(state.c),
            d: m.unpack(state.d),
        };
        for _ in 0..drounds {
            x = round(x);
            x = undiagonalize(round(diagonalize(x)));
        }
        State {
            a: x.a.into(),
            b: x.b.into(),
            c: x.c.into(),
            d: x.d.into(),
        }
    }
});

dispatch_light128!(m, Mach, {
    fn set_stream_param(state: &mut ChaCha, param: u32, value: u64) {
        let d: Mach::u32x4 = m.unpack(state.d);
        state.d = d
            .insert((value >> 32) as u32, (param << 1) | 1)
            .insert(value as u32, param << 1)
            .into();
    }
});

dispatch_light128!(m, Mach, {
    fn get_stream_param(state: &ChaCha, param: u32) -> u64 {
        let d: Mach::u32x4 = m.unpack(state.d);
        ((d.extract((param << 1) | 1) as u64) << 32) | d.extract(param << 1) as u64
    }
});

fn read_u32le(xs: &[u8]) -> u32 {
    assert_eq!(xs.len(), 4);
    u32::from(xs[0]) | (u32::from(xs[1]) << 8) | (u32::from(xs[2]) << 16) | (u32::from(xs[3]) << 24)
}

dispatch_light128!(m, Mach, {
    fn init_chacha(key: &[u8; 32], nonce: &[u8]) -> ChaCha {
        let ctr_nonce = [
            0,
            if nonce.len() == 12 {
                read_u32le(&nonce[0..4])
            } else {
                0
            },
            read_u32le(&nonce[nonce.len() - 8..nonce.len() - 4]),
            read_u32le(&nonce[nonce.len() - 4..]),
        ];
        let key0: Mach::u32x4 = m.read_le(&key[..16]);
        let key1: Mach::u32x4 = m.read_le(&key[16..]);
        ChaCha {
            b: key0.into(),
            c: key1.into(),
            d: ctr_nonce.into(),
        }
    }
});

dispatch_light128!(m, Mach, {
    fn init_chacha_x(key: &[u8; 32], nonce: &[u8; 24], rounds: u32) -> ChaCha {
        let key0: Mach::u32x4 = m.read_le(&key[..16]);
        let key1: Mach::u32x4 = m.read_le(&key[16..]);
        let nonce0: Mach::u32x4 = m.read_le(&nonce[..16]);
        let mut state = ChaCha {
            b: key0.into(),
            c: key1.into(),
            d: nonce0.into(),
        };
        let x = refill_narrow_rounds(&mut state, rounds);
        let ctr_nonce1 = [0, 0, read_u32le(&nonce[16..20]), read_u32le(&nonce[20..24])];
        state.b = x.a;
        state.c = x.d;
        state.d = ctr_nonce1.into();
        state
    }
});
<|endoftext|>


<commit_before>// Copyright © 2017-2018 Mozilla Foundation
//
// This program is made available under an ISC-style license.  See the
// accompanying file LICENSE for details.

use callbacks::cubeb_device_changed_callback;
use channel::cubeb_channel_layout;
use device::cubeb_device;
use format::cubeb_sample_format;
use std::{fmt, mem};
use std::os::raw::{c_float, c_int, c_uint, c_void};

cubeb_enum! {
    pub enum cubeb_stream_prefs {
        CUBEB_STREAM_PREF_NONE     = 0x00,
        CUBEB_STREAM_PREF_LOOPBACK = 0x01,
    }
}

cubeb_enum! {
    pub enum cubeb_state {
        CUBEB_STATE_STARTED,
        CUBEB_STATE_STOPPED,
        CUBEB_STATE_DRAINED,
        CUBEB_STATE_ERROR,
    }
}

pub enum cubeb_stream {}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct cubeb_stream_params {
    pub format: cubeb_sample_format,
    pub rate: c_uint,
    pub channels: c_uint,
    pub layout: cubeb_channel_layout,
    pub prefs: cubeb_stream_prefs,
}

impl Default for cubeb_stream_params {
    fn default() -> Self {
        unsafe { mem::zeroed() }
    }
}

// Explicit Debug impl to work around bug in ctest
impl fmt::Debug for cubeb_stream_params {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("cubeb_stream_params")
            .field("format", &self.format)
            .field("rate", &self.rate)
            .field("channels", &self.channels)
            .field("layout", &self.layout)
            .field("prefs", &self.prefs)
            .finish()
    }
}

extern "C" {
    pub fn cubeb_stream_destroy(stream: *mut cubeb_stream);
    pub fn cubeb_stream_start(stream: *mut cubeb_stream) -> c_int;
    pub fn cubeb_stream_stop(stream: *mut cubeb_stream) -> c_int;
    pub fn cubeb_stream_reset_default_device(stream: *mut cubeb_stream) -> c_int;
    pub fn cubeb_stream_get_position(stream: *mut cubeb_stream, position: *mut u64) -> c_int;
    pub fn cubeb_stream_get_latency(stream: *mut cubeb_stream, latency: *mut c_uint) -> c_int;
    pub fn cubeb_stream_set_volume(stream: *mut cubeb_stream, volume: c_float) -> c_int;
    pub fn cubeb_stream_set_panning(stream: *mut cubeb_stream, panning: c_float) -> c_int;
    pub fn cubeb_stream_get_current_device(
        stream: *mut cubeb_stream,
        device: *mut *mut cubeb_device,
    ) -> c_int;
    pub fn cubeb_stream_device_destroy(
        stream: *mut cubeb_stream,
        devices: *mut cubeb_device,
    ) -> c_int;
    pub fn cubeb_stream_register_device_changed_callback(
        stream: *mut cubeb_stream,
        device_changed_callback: cubeb_device_changed_callback,
    ) -> c_int;
    pub fn cubeb_stream_user_ptr(stream: *mut cubeb_stream) -> *mut c_void;
}
<commit_msg>Add missing enum export from ffi.<commit_after>// Copyright © 2017-2018 Mozilla Foundation
//
// This program is made available under an ISC-style license.  See the
// accompanying file LICENSE for details.

use callbacks::cubeb_device_changed_callback;
use channel::cubeb_channel_layout;
use device::cubeb_device;
use format::cubeb_sample_format;
use std::{fmt, mem};
use std::os::raw::{c_float, c_int, c_uint, c_void};

cubeb_enum! {
    pub enum cubeb_stream_prefs {
        CUBEB_STREAM_PREF_NONE     = 0x00,
        CUBEB_STREAM_PREF_LOOPBACK = 0x01,
        CUBEB_STREAM_PREF_VOICE = 0x04,
    }
}

cubeb_enum! {
    pub enum cubeb_state {
        CUBEB_STATE_STARTED,
        CUBEB_STATE_STOPPED,
        CUBEB_STATE_DRAINED,
        CUBEB_STATE_ERROR,
    }
}

pub enum cubeb_stream {}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct cubeb_stream_params {
    pub format: cubeb_sample_format,
    pub rate: c_uint,
    pub channels: c_uint,
    pub layout: cubeb_channel_layout,
    pub prefs: cubeb_stream_prefs,
}

impl Default for cubeb_stream_params {
    fn default() -> Self {
        unsafe { mem::zeroed() }
    }
}

// Explicit Debug impl to work around bug in ctest
impl fmt::Debug for cubeb_stream_params {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("cubeb_stream_params")
            .field("format", &self.format)
            .field("rate", &self.rate)
            .field("channels", &self.channels)
            .field("layout", &self.layout)
            .field("prefs", &self.prefs)
            .finish()
    }
}

extern "C" {
    pub fn cubeb_stream_destroy(stream: *mut cubeb_stream);
    pub fn cubeb_stream_start(stream: *mut cubeb_stream) -> c_int;
    pub fn cubeb_stream_stop(stream: *mut cubeb_stream) -> c_int;
    pub fn cubeb_stream_reset_default_device(stream: *mut cubeb_stream) -> c_int;
    pub fn cubeb_stream_get_position(stream: *mut cubeb_stream, position: *mut u64) -> c_int;
    pub fn cubeb_stream_get_latency(stream: *mut cubeb_stream, latency: *mut c_uint) -> c_int;
    pub fn cubeb_stream_set_volume(stream: *mut cubeb_stream, volume: c_float) -> c_int;
    pub fn cubeb_stream_set_panning(stream: *mut cubeb_stream, panning: c_float) -> c_int;
    pub fn cubeb_stream_get_current_device(
        stream: *mut cubeb_stream,
        device: *mut *mut cubeb_device,
    ) -> c_int;
    pub fn cubeb_stream_device_destroy(
        stream: *mut cubeb_stream,
        devices: *mut cubeb_device,
    ) -> c_int;
    pub fn cubeb_stream_register_device_changed_callback(
        stream: *mut cubeb_stream,
        device_changed_callback: cubeb_device_changed_callback,
    ) -> c_int;
    pub fn cubeb_stream_user_ptr(stream: *mut cubeb_stream) -> *mut c_void;
}
<|endoftext|>


<commit_before>#![allow(unused)]

use interpreter::command::ExpressionOutput;
use std::time::Instant;
use std::fs::File;
use std::io::Read;
use interpreter::ast::*;
use interpreter::{Ident, DebugInfo};
use interpreter::Memory;

macro_rules! register_builtin(
    ($memory:ident, $name:ident, $($arg:ident),+) => (
        $memory.insert(
            Ident(concat!("$", stringify!($name)).to_string()),
            Expr::new(
                Node::Function(Box::new(Function {
                    name: Ident(concat!("$", stringify!($name)).to_string()),
                    args: vec![$(Ident(concat!("$", stringify!($arg)).to_string()))+],
                    body: vec![
                        Expr::new(Node::Builtin(Builtin($name)), DebugInfo::new(concat!("$", stringify!($name)), 0)),
                    ],
                })),
                DebugInfo::new(concat!("$", stringify!($name)), 0),
            ),
        );
    )
);

pub fn register_builtins(memory: &mut Memory) {
    register_builtin!(memory, exit, exitCode);
    register_builtin!(memory, echo, val);
    register_builtin!(memory, panic, msg);
    register_builtin!(memory, type_of, val);
    register_builtin!(memory, len, array);
    register_builtin!(memory, string, val);
    register_builtin!(memory, int, val);
    register_builtin!(memory, float, val);
    register_builtin!(memory, boolean, val);
}

pub fn exit(memory: &mut Memory) -> Result<Expr, String> {
    let code = match Ident("$exitCode".to_string()).run(&mut DebugInfo::none(), memory)?.node {
        Node::Int(int) => int,
        _ => 0,
    };

    ::std::process::exit(code as i32);
}

pub fn string(memory: &mut Memory) -> Result<Expr, String> {
    let val = Ident("$val".to_string()).run(&mut DebugInfo::none(), memory)?;
    let str_val = match val.node {
        Node::Int(int) => int.to_string(),
        Node::Float(float) => float.to_string(),
        Node::Str(ref str_val) => str_val.clone(),
        Node::Bool(bool_val) => bool_val.to_string(),
        _ => {
            Err(
                val.debug.to_string() + ", which cannot be converted into a string",
            )?
        }
    };

    Ok(Expr::new(Node::Str(str_val), DebugInfo::none()))
}

pub fn int(memory: &mut Memory) -> Result<Expr, String> {
    let val = Ident("$val".to_string()).run(&mut DebugInfo::none(), memory)?;
    let int_val = match val.node {
        Node::Int(int) => int,
        Node::Float(float) => float as i64,
        Node::Str(ref str_val) => {
            str_val.parse().map_err(|_| {
                val.debug.to_string() + " with value " + str_val + " cannot be converted to an int."
            })?
        }
        Node::Bool(bool_val) => if bool_val { 1 } else { 0 },
        _ => {
            Err(
                val.debug.to_string() + ", which cannot be converted into an int",
            )?
        }
    };

    Ok(Expr::new(Node::Int(int_val), DebugInfo::none()))
}

pub fn float(memory: &mut Memory) -> Result<Expr, String> {
    let val = Ident("$val".to_string()).run(&mut DebugInfo::none(), memory)?;
    let float_val = match val.node {
        Node::Int(int) => int as f64,
        Node::Float(float) => float,
        Node::Str(ref str_val) => {
            str_val.parse().map_err(|_| {
                val.debug.to_string() + " with value " + str_val +
                    " cannot be converted to a float."
            })?
        }
        Node::Bool(bool_val) => if bool_val { 1.0 } else { 0.0 },
        _ => {
            Err(
                val.debug.to_string() + ", which cannot be converted into a float",
            )?
        }
    };

    Ok(Expr::new(Node::Float(float_val), DebugInfo::none()))
}

pub fn boolean(memory: &mut Memory) -> Result<Expr, String> {
    let val = Ident("$val".to_string()).run(&mut DebugInfo::none(), memory)?;
    let bool_val = match val.node {
        Node::Str(ref str_val) => {
            str_val.to_lowercase().parse().map_err(|_| {
                val.debug.to_string() + " with value " + str_val +
                    " cannot be converted to a boolean."
            })?
        }
        Node::Bool(bool_val) => bool_val,
        _ => {
            Err(
                val.debug.to_string() + ", which cannot be converted into a boolean",
            )?
        }
    };

    Ok(Expr::new(Node::Bool(bool_val), DebugInfo::none()))
}

pub fn echo(memory: &mut Memory) -> Result<Expr, String> {
    let val = Ident("$val".to_string()).run(&mut DebugInfo::none(), memory)?;
    let str_val = match val.node {
        Node::Int(int) => int.to_string(),
        Node::Float(float) => float.to_string(),
        Node::Str(ref str_val) => str_val.clone(),
        Node::Bool(bool_val) => bool_val.to_string(),
        ref node => format!("{:#?}", node),
    };

    println!("{}", str_val);

    Ok(Expr::new(Node::Noop, DebugInfo::none()))
}

pub fn panic(memory: &mut Memory) -> Result<Expr, String> {
    let val = Ident("$msg".to_string()).run(&mut DebugInfo::none(), memory)?;
    let str_val = match val.node {
        Node::Str(ref str_val) => str_val.clone(),
        ref node => format!("{:#?}", node),
    };

    Err(format!("script panicked with error message \"{}\"", str_val))
}

pub fn type_of(memory: &mut Memory) -> Result<Expr, String> {
    let val = Ident("$val".to_string()).run(&mut DebugInfo::none(), memory)?;
    let str_val = match val.node {
        Node::Int(_) => "int".to_string(),
        Node::Float(_) => "float".to_string(),
        Node::Str(_) => "string".to_string(),
        Node::Bool(_) => "boolean".to_string(),
        Node::Array(_) => "array".to_string(),
        Node::Function(_) => "function".to_string(),
        ref node => format!("{:#?}", node),
    };

    Ok(Expr::new(Node::Str(str_val), DebugInfo::none()))
}

pub fn len(memory: &mut Memory) -> Result<Expr, String> {
    let val = Ident("$array".to_string()).run(&mut DebugInfo::none(), memory)?;
    let arr_len = match val.node {
        Node::Array(ref arr) => arr.len(),
        _ => {
            Err(
                val.debug.to_string() + ", which does not have a length",
            )?
        }
    };

    Ok(Expr::new(Node::Int(arr_len as i64), DebugInfo::none()))
}

// pub fn echo(buffer: &str, args: Vec<&str>) -> Result<ExpressionOutput, String> {
//     let output = args.join(" ");
//     Ok(ExpressionOutput {
//         command: buffer.to_string(),
//         stdout: output.clone(),
//         stderr: "".to_string(),
//         interleaved: output,
//         started: Instant::now(),
//         completed: Instant::now(),
//     })
// }

// pub fn cat(buffer: &str, args: Vec<&str>) -> Result<ExpressionOutput, String> {
//     let mut output = String::new();
//     for file in args {
//         File::open(file)
//             .and_then(|mut file| file.read_to_string(&mut output))
//             .map_err(|err| format!("Error reading {}: {}", file, err))?;
//     }
//     Ok(ExpressionOutput {
//         command: buffer.to_string(),
//         stdout: output.clone(),
//         stderr: "".to_string(),
//         interleaved: output,
//         started: Instant::now(),
//         completed: Instant::now(),
//     })
// }
<commit_msg>add array 'push' builtin<commit_after>#![allow(unused)]

use interpreter::command::ExpressionOutput;
use std::time::Instant;
use std::fs::File;
use std::io::Read;
use interpreter::ast::*;
use interpreter::{Ident, DebugInfo};
use interpreter::Memory;

macro_rules! register_builtin(
    ($memory:ident, $name:ident, $($arg:ident),+) => (
        $memory.insert(
            Ident(concat!("$", stringify!($name)).to_string()),
            Expr::new(
                Node::Function(Box::new(Function {
                    name: Ident(concat!("$", stringify!($name)).to_string()),
                    args: vec![$(Ident(concat!("$", stringify!($arg)).to_string()),)+],
                    body: vec![
                        Expr::new(Node::Builtin(Builtin($name)), DebugInfo::new(concat!("$", stringify!($name)), 0)),
                    ],
                })),
                DebugInfo::new(concat!("$", stringify!($name)), 0),
            ),
        );
    )
);

pub fn register_builtins(memory: &mut Memory) {
    register_builtin!(memory, exit, exitCode);
    register_builtin!(memory, echo, val);
    register_builtin!(memory, panic, msg);
    register_builtin!(memory, type_of, val);
    register_builtin!(memory, len, array);
    register_builtin!(memory, string, val);
    register_builtin!(memory, int, val);
    register_builtin!(memory, float, val);
    register_builtin!(memory, boolean, val);
    register_builtin!(memory, push, array, val);
}

pub fn exit(memory: &mut Memory) -> Result<Expr, String> {
    let code = match Ident("$exitCode".to_string()).run(&mut DebugInfo::none(), memory)?.node {
        Node::Int(int) => int,
        _ => 0,
    };

    ::std::process::exit(code as i32);
}

pub fn string(memory: &mut Memory) -> Result<Expr, String> {
    let val = Ident("$val".to_string()).run(&mut DebugInfo::none(), memory)?;
    let str_val = match val.node {
        Node::Int(int) => int.to_string(),
        Node::Float(float) => float.to_string(),
        Node::Str(ref str_val) => str_val.clone(),
        Node::Bool(bool_val) => bool_val.to_string(),
        _ => {
            Err(
                val.debug.to_string() + ", which cannot be converted into a string",
            )?
        }
    };

    Ok(Expr::new(Node::Str(str_val), DebugInfo::none()))
}

pub fn int(memory: &mut Memory) -> Result<Expr, String> {
    let val = Ident("$val".to_string()).run(&mut DebugInfo::none(), memory)?;
    let int_val = match val.node {
        Node::Int(int) => int,
        Node::Float(float) => float as i64,
        Node::Str(ref str_val) => {
            str_val.parse().map_err(|_| {
                val.debug.to_string() + " with value " + str_val + " cannot be converted to an int."
            })?
        }
        Node::Bool(bool_val) => if bool_val { 1 } else { 0 },
        _ => {
            Err(
                val.debug.to_string() + ", which cannot be converted into an int",
            )?
        }
    };

    Ok(Expr::new(Node::Int(int_val), DebugInfo::none()))
}

pub fn float(memory: &mut Memory) -> Result<Expr, String> {
    let val = Ident("$val".to_string()).run(&mut DebugInfo::none(), memory)?;
    let float_val = match val.node {
        Node::Int(int) => int as f64,
        Node::Float(float) => float,
        Node::Str(ref str_val) => {
            str_val.parse().map_err(|_| {
                val.debug.to_string() + " with value " + str_val +
                    " cannot be converted to a float."
            })?
        }
        Node::Bool(bool_val) => if bool_val { 1.0 } else { 0.0 },
        _ => {
            Err(
                val.debug.to_string() + ", which cannot be converted into a float",
            )?
        }
    };

    Ok(Expr::new(Node::Float(float_val), DebugInfo::none()))
}

pub fn boolean(memory: &mut Memory) -> Result<Expr, String> {
    let val = Ident("$val".to_string()).run(&mut DebugInfo::none(), memory)?;
    let bool_val = match val.node {
        Node::Str(ref str_val) => {
            str_val.to_lowercase().parse().map_err(|_| {
                val.debug.to_string() + " with value " + str_val +
                    " cannot be converted to a boolean."
            })?
        }
        Node::Bool(bool_val) => bool_val,
        _ => {
            Err(
                val.debug.to_string() + ", which cannot be converted into a boolean",
            )?
        }
    };

    Ok(Expr::new(Node::Bool(bool_val), DebugInfo::none()))
}

pub fn echo(memory: &mut Memory) -> Result<Expr, String> {
    let val = Ident("$val".to_string()).run(&mut DebugInfo::none(), memory)?;
    let str_val = match val.node {
        Node::Int(int) => int.to_string(),
        Node::Float(float) => float.to_string(),
        Node::Str(ref str_val) => str_val.clone(),
        Node::Bool(bool_val) => bool_val.to_string(),
        ref node => format!("{:#?}", node),
    };

    println!("{}", str_val);

    Ok(Expr::new(Node::Noop, DebugInfo::none()))
}

pub fn panic(memory: &mut Memory) -> Result<Expr, String> {
    let val = Ident("$msg".to_string()).run(&mut DebugInfo::none(), memory)?;
    let str_val = match val.node {
        Node::Str(ref str_val) => str_val.clone(),
        ref node => format!("{:#?}", node),
    };

    Err(format!("script panicked with error message \"{}\"", str_val))
}

pub fn type_of(memory: &mut Memory) -> Result<Expr, String> {
    let val = Ident("$val".to_string()).run(&mut DebugInfo::none(), memory)?;
    let str_val = match val.node {
        Node::Int(_) => "int".to_string(),
        Node::Float(_) => "float".to_string(),
        Node::Str(_) => "string".to_string(),
        Node::Bool(_) => "boolean".to_string(),
        Node::Array(_) => "array".to_string(),
        Node::Function(_) => "function".to_string(),
        ref node => format!("{:#?}", node),
    };

    Ok(Expr::new(Node::Str(str_val), DebugInfo::none()))
}

pub fn len(memory: &mut Memory) -> Result<Expr, String> {
    let val = Ident("$array".to_string()).run(&mut DebugInfo::none(), memory)?;
    let arr_len = match val.node {
        Node::Array(ref arr) => arr.len(),
        _ => {
            Err(
                val.debug.to_string() + ", which does not have a length",
            )?
        }
    };

    Ok(Expr::new(Node::Int(arr_len as i64), DebugInfo::none()))
}

pub fn push(memory: &mut Memory) -> Result<Expr, String> {
    let mut val = Ident("$val".to_string()).run(&mut DebugInfo::none(), memory)?;
    let mut arr = Ident("$array".to_string()).run(&mut DebugInfo::none(), memory)?;
    match arr.node {
        Node::Array(ref mut arr) => arr.push(val),
        _ => {
            Err(
                arr.debug.to_string() + ", which is not an array",
            )?
        }
    };

    Ok(arr)
}

// pub fn echo(buffer: &str, args: Vec<&str>) -> Result<ExpressionOutput, String> {
//     let output = args.join(" ");
//     Ok(ExpressionOutput {
//         command: buffer.to_string(),
//         stdout: output.clone(),
//         stderr: "".to_string(),
//         interleaved: output,
//         started: Instant::now(),
//         completed: Instant::now(),
//     })
// }

// pub fn cat(buffer: &str, args: Vec<&str>) -> Result<ExpressionOutput, String> {
//     let mut output = String::new();
//     for file in args {
//         File::open(file)
//             .and_then(|mut file| file.read_to_string(&mut output))
//             .map_err(|err| format!("Error reading {}: {}", file, err))?;
//     }
//     Ok(ExpressionOutput {
//         command: buffer.to_string(),
//         stdout: output.clone(),
//         stderr: "".to_string(),
//         interleaved: output,
//         started: Instant::now(),
//         completed: Instant::now(),
//     })
// }
<|endoftext|>


<commit_before>use parser_combinators::primitives::{Stream, State, Parser};
use parser_combinators::{ParseResult, parser};
use parser_combinators::combinator::{optional, ParserExt, sep_by, many};

use super::Block;
use super::token::{Token, ParseToken};
use super::token::TokenType as Tok;
use super::token::lift;
use util::join;

#[derive(Debug, Clone)]
pub struct Selector {
    pub element: Option<String>,
    pub classes: Vec<String>,
    // TODO(tailhook) implement other selectors
}

#[derive(Debug, Clone)]
pub struct Rule {
    pub selectors: Vec<Selector>,
    pub properties: Vec<(String, String)>,
}

#[derive(Debug, Clone)]
pub struct Param {
    pub name: String,
    pub default_value: Option<String>,
}

fn param<'a, I: Stream<Item=Token<'a>>>(input: State<I>)
    -> ParseResult<Param, I>
{
    lift(Tok::Ident).and(optional(lift(Tok::Equals).with(lift(Tok::String))))
            .map(|((_, name, _), opt)| Param {
                name: String::from(name),
                default_value: opt.map(|x| String::from(x.1)),
            })
    .parse_state(input)
}

fn dash_name<'a, I: Stream<Item=Token<'a>>>(input: State<I>)
    -> ParseResult<String, I>
{
    sep_by::<Vec<_>, _, _>(
        lift(Tok::Ident).or(lift(Tok::Number)),
        lift(Tok::Dash),
    ).map(|names| join(names.into_iter().map(|(_, val, _)| val), "-"))
    .parse_state(input)
}

fn property_value<'a, I: Stream<Item=Token<'a>>>(input: State<I>)
    -> ParseResult<String, I>
{
    // TODO(tailhook) add numbers slashes and other things
    many::<Vec<_>, _>(
        sep_by::<Vec<_>, _, _>(lift(Tok::Ident).or(lift(Tok::Number)),
              lift(Tok::Dash),
        ).map(|names| join(names.into_iter().map(|(_, val, _)| val), "-"))
    ).map(|names| join(names.into_iter(), " "))
    .parse_state(input)
}

fn selector<'a, I: Stream<Item=Token<'a>>>(input: State<I>)
    -> ParseResult<Selector, I>
{
    optional(lift(Tok::Ident).map(ParseToken::into_string))
        .and(many::<Vec<_>, _>(lift(Tok::Dot).with(parser(dash_name))))
    .map(|(element, classes)| Selector {
        element: element,
        classes: classes,
    })
    .parse_state(input)
}

fn rule<'a, I: Stream<Item=Token<'a>>>(input: State<I>)
    -> ParseResult<Rule, I>
{
    sep_by::<Vec<_>, _, _>(
            parser(selector),
            lift(Tok::Comma),
        ).skip(lift(Tok::Newline))
    .and(optional(
        lift(Tok::Indent)
        .with(many::<Vec<_>, _>(
            parser(dash_name)
            .skip(lift(Tok::Colon))
            .and(optional(parser(property_value)))
            .skip(lift(Tok::Newline))
            )
        ).skip(lift(Tok::Dedent))
    ))
    .map(|(selectors, properties)| {
        Rule {
            selectors: selectors,
            properties: properties.unwrap_or(vec!())
                .into_iter()
                .map(|(key, val)| (key, val.unwrap_or(String::new())))
                //.map(|key| (key.clone(), key))
                .collect(),
        }
    })
    .parse_state(input)
}

pub fn block<'a, I: Stream<Item=Token<'a>>>(input: State<I>)
    -> ParseResult<Block, I>
{
    optional(lift(Tok::OpenParen)
        .with(sep_by::<Vec<_>, _, _>(parser(param), lift(Tok::Comma)))
        .skip(lift(Tok::CloseParen)))
        .skip(lift(Tok::Colon))
        .skip(lift(Tok::Newline))
        .and(optional(
            lift(Tok::Indent)
            .with(many::<Vec<_>, _>(parser(rule)))
            .skip(lift(Tok::Dedent))
        ))
        .map(|(opt_params, opt_rules)| {
            Block::Css(
                opt_params.unwrap_or(vec!()),
                opt_rules.unwrap_or(vec!()),
            )
        })
        .parse_state(input)
}
<commit_msg>Fix cyclic CSS parser<commit_after>use parser_combinators::primitives::{Stream, State, Parser};
use parser_combinators::{ParseResult, parser};
use parser_combinators::combinator::{optional, ParserExt, sep_by, many};

use super::Block;
use super::token::{Token, ParseToken};
use super::token::TokenType as Tok;
use super::token::lift;
use util::join;

#[derive(Debug, Clone)]
pub struct Selector {
    pub element: Option<String>,
    pub classes: Vec<String>,
    // TODO(tailhook) implement other selectors
}

#[derive(Debug, Clone)]
pub struct Rule {
    pub selectors: Vec<Selector>,
    pub properties: Vec<(String, String)>,
}

#[derive(Debug, Clone)]
pub struct Param {
    pub name: String,
    pub default_value: Option<String>,
}

fn param<'a, I: Stream<Item=Token<'a>>>(input: State<I>)
    -> ParseResult<Param, I>
{
    lift(Tok::Ident).and(optional(lift(Tok::Equals).with(lift(Tok::String))))
            .map(|((_, name, _), opt)| Param {
                name: String::from(name),
                default_value: opt.map(|x| String::from(x.1)),
            })
    .parse_state(input)
}

fn dash_name<'a, I: Stream<Item=Token<'a>>>(input: State<I>)
    -> ParseResult<String, I>
{
    sep_by::<Vec<_>, _, _>(
        lift(Tok::Ident).or(lift(Tok::Number)),
        lift(Tok::Dash),
    ).map(|names| join(names.into_iter().map(|(_, val, _)| val), "-"))
    .parse_state(input)
}

fn property_value<'a, I: Stream<Item=Token<'a>>>(input: State<I>)
    -> ParseResult<String, I>
{
    // TODO(tailhook) add numbers slashes and other things
    many::<Vec<_>, _>(
        lift(Tok::Ident).or(lift(Tok::Number))
        .and(many::<Vec<_>, _>(
              lift(Tok::Dash).with(lift(Tok::Ident).or(lift(Tok::Number))))
        ).map(|(prefix, names)|
            join(vec![prefix].into_iter().chain(names.into_iter())
                 .map(|(_, val, _)| val), "-"))
    ).map(|names| join(names.into_iter(), " "))
    .parse_state(input)
}

fn selector<'a, I: Stream<Item=Token<'a>>>(input: State<I>)
    -> ParseResult<Selector, I>
{
    optional(lift(Tok::Ident).map(ParseToken::into_string))
        .and(many::<Vec<_>, _>(lift(Tok::Dot).with(parser(dash_name))))
    .map(|(element, classes)| Selector {
        element: element,
        classes: classes,
    })
    .parse_state(input)
}

fn rule<'a, I: Stream<Item=Token<'a>>>(input: State<I>)
    -> ParseResult<Rule, I>
{
    sep_by::<Vec<_>, _, _>(
            parser(selector),
            lift(Tok::Comma),
        ).skip(lift(Tok::Newline))
    .and(optional(
        lift(Tok::Indent)
        .with(many::<Vec<_>, _>(
            parser(dash_name)
            .skip(lift(Tok::Colon))
            .and(optional(parser(property_value)))
            .skip(lift(Tok::Newline))
            )
        ).skip(lift(Tok::Dedent))
    ))
    .map(|(selectors, properties)| {
        Rule {
            selectors: selectors,
            properties: properties.unwrap_or(vec!())
                .into_iter()
                .map(|(key, val)| (key, val.unwrap_or(String::new())))
                //.map(|key| (key.clone(), key))
                .collect(),
        }
    })
    .parse_state(input)
}

pub fn block<'a, I: Stream<Item=Token<'a>>>(input: State<I>)
    -> ParseResult<Block, I>
{
    optional(lift(Tok::OpenParen)
        .with(sep_by::<Vec<_>, _, _>(parser(param), lift(Tok::Comma)))
        .skip(lift(Tok::CloseParen)))
        .skip(lift(Tok::Colon))
        .skip(lift(Tok::Newline))
        .and(optional(
            lift(Tok::Indent)
            .with(many::<Vec<_>, _>(parser(rule)))
            .skip(lift(Tok::Dedent))
        ))
        .map(|(opt_params, opt_rules)| {
            Block::Css(
                opt_params.unwrap_or(vec!()),
                opt_rules.unwrap_or(vec!()),
            )
        })
        .parse_state(input)
}
<|endoftext|>