<commit_before>// Adapton uses memoization under the covers, which needs an efficient
// mechanism to search for function pointers and compare them for
// equality.
//
// Meanwhile, Rust does not provide Eq and Hash implementations for
// trait Fn.  So, to identify Rust functions as values that we can
// hash and compare, we need to bundle additional static information
// along with the function pointer as use this data as a proxy for the
// function itself.  The idea is that this information uniquely
// identifies the function pointer (i.e., two distinct functions will
// always have two distinct identities).
//
use std::hash::{Hash,Hasher,SipHasher};
//use std::rc::Rc;
//use std::mem::replace;

#[derive(PartialEq,Eq,Clone,Hash,Debug)]
pub struct ProgPt {
    // Symbolic identity, in Rust semantics:
    pub symbol:&'static str, // via stringify!(...)
    // module:Rc<String>, // via module!()

    // Location in local filesystem:
    pub file:&'static str,   // via file!()
    pub line:u32,        // via line!()
    pub column:u32,      // via column!()
}

pub fn my_hash<T>(obj: T) -> u64
    where T: Hash
{
    let mut hasher = SipHasher::new();
    obj.hash(&mut hasher);
    hasher.finish()
}

#[macro_export]
macro_rules! prog_pt {
    ($symbol:ident) => {{
        ProgPt{
            symbol:stringify!($symbol),
            file:file!(),
            line:line!(),
            column:column!(),
        }
    }}
}

#[macro_export]
macro_rules! thunk {
    ( $st:expr , $nm:expr =>> $f:ident :: < $( $ty:ty ),* > , $( $lab:ident : $arg:expr ),* ) => {{
        ($st).thunk
            (ArtIdChoice::Nominal($nm),
             prog_pt!(f),
             Rc::new(Box::new(
                 |st, args, _|{
                     let ($( $lab ),*) = args ;
                     $f :: < $( $ty ),* >( st, $( $lab ),* )
                 })),
             ( $( $arg ),* ),
             ()
             )
    }}
    ;
    ( $st:expr , $nm:expr =>> $f:ident , $( $lab:ident : $arg:expr ),* ) => {{
        ($st).thunk
            (ArtIdChoice::Nominal($nm),
             prog_pt!(f),
             Rc::new(Box::new(
                 |st, args, _|{
                     let ($( $lab ),*) = args ;
                     $f ( st, $( $lab ),* )
                 })),
             ( $( $arg ),* ),
             ()
             )
    }}
    ;
    ( $st:expr , $f:ident :: < $( $ty:ty ),* > , $( $lab:ident : $arg:expr ),* ) => {{
        ($st).thunk
            (ArtIdChoice::Structural,
             prog_pt!(f),
             Rc::new(Box::new(
                 |st, args, _|{
                     let ($( $lab ),*) = args ;
                     $f :: < $( $ty ),* >( st, $( $lab ),* )
                 })),
             ( $( $arg ),* ),
             ()
             )
    }}
    ;
    ( $st:expr , $f:path , $( $lab:ident : $arg:expr ),* ) => {{
        ($st).thunk
            (ArtIdChoice::Structural,
             prog_pt!(f),
             Rc::new(Box::new(
                 |st, args, _|{
                     let ($( $lab ),*) = args ;
                     $f ( st, $( $lab ),* () )
                 })),
             ( $( $arg ),* ),
             ()
             )
    }}
    ;
}

#[macro_export]
macro_rules! memo {
    ( $st:expr , $nm:expr =>> $f:ident :: < $( $ty:ty ),* > , $( $lab:ident : $arg:expr ),* ) => {{
        let t = ($st).thunk
            (ArtIdChoice::Nominal($nm),
             prog_pt!(f),
             Rc::new(Box::new(
                 |st, args, _|{
                     let ($( $lab ),*) = args ;
                     $f :: < $( $ty ),* >( st, $( $lab ),* )
                 })),
             ( $( $arg ),*, ),
             ()
             );
        ($st).force(&t)
    }}
    ;
    ( $st:expr , $nm:expr =>> $f:path , $( $lab:ident : $arg:expr ),* ) => {{
        let t = ($st).thunk
            (ArtIdChoice::Nominal($nm),
             prog_pt!(f),
             Rc::new(Box::new(
                 |st, args, _|{
                     let ($( $lab ),*) = args ;
                     $f ( st, $( $lab ),* )
                 })),
             ( $( $arg ),* ),
             ()
             );
        ($st).force(&t)
    }}
    ;
    ( $st:expr , $f:ident :: < $( $ty:ty ),* > , $( $lab:ident : $arg:expr ),* ) => {{
        let t = ($st).thunk
            (ArtIdChoice::Structural,
             prog_pt!(f),
             Rc::new(Box::new(
                 |st, args, _|{
                     let ($( $lab ),*) = args ;
                     $f :: < $( $ty ),* >( st, $( $lab ),* )
                 })),
             ( $( $arg ),* ),
             ()
             );
        ($st).force(&t)
    }}
    ;
    ( $st:expr , $f:path , $( $lab:ident : $arg:expr ),* ) => {{
        let t = ($st).thunk
            (ArtIdChoice::Structural,
             prog_pt!(f),
             Rc::new(Box::new(
                 |st, args, _|{
                     let ($( $lab ),*) = args ;
                     $f ( st, $( $lab ),* )
                 })),
             ( $( $arg ),* ),
             ()
             );
        ($st).force(&t)
    }}
    ;
    ( $st:expr , $nm:expr =>> $f:path , $( $lab1:ident : $arg1:expr ),* ;; $( $lab2:ident : $arg2:expr ),* ) => {{
        let t = ($st).thunk
            (ArtIdChoice::Nominal($nm),
             prog_pt!(f),
             Rc::new(Box::new(
                 |st, args1, args2|{
                     let ($( $lab1 ),*) = args1 ;
                     let ($( $lab2 ),*) = args2 ;
                     $f ( st, $( $lab1 ),* , $( $lab2 ),* )
                 })),
             ( $( $arg1 ),* ),
             ( $( $arg2 ),* ),
             );
        ($st).force(&t)
    }}
    ;
}

// https://doc.rust-lang.org/book/macros.html
//
// macro_rules! o_O {
//     (
//         $(
//             $x:expr; [ $( $y:expr ),* ]
//          );*
//     ) => {
//         &[ $($( $x + $y ),*),* ]
//     }
// }
//
// fn main() {
//     let a: &[i32]
//         = o_O!(10; [1, 2, 3];
//                20; [4, 5, 6]);
//
//     assert_eq!(a, [11, 12, 13, 24, 25, 26]);
// }

// TODO: Need to gensym a variable for each argument below:
//
// macro_rules! thunk {
//     ( $f:ident , $st:expr , $( $arg:expr ),* ) => {
//         let fval = Rc::new(Box::new(
//             |st, args|{
//                 let ($( $arg ),*) = args ;
//                 f( st, $( $arg ),* )
//             })) ;
//         ($st).thunk (ArtId::Eager, prog_pt!(f), fval, $( $arg ),* )
//     }}
<commit_msg>simplified prog_pt; it's just a symbol; more reuse in fib<commit_after>// Adapton uses memoization under the covers, which needs an efficient
// mechanism to search for function pointers and compare them for
// equality.
//
// Meanwhile, Rust does not provide Eq and Hash implementations for
// trait Fn.  So, to identify Rust functions as values that we can
// hash and compare, we need to bundle additional static information
// along with the function pointer as use this data as a proxy for the
// function itself.  The idea is that this information uniquely
// identifies the function pointer (i.e., two distinct functions will
// always have two distinct identities).
//
use std::hash::{Hash,Hasher,SipHasher};
//use std::rc::Rc;
//use std::mem::replace;

#[derive(PartialEq,Eq,Clone,Hash,Debug)]
pub struct ProgPt {
    // Symbolic identity, in Rust semantics:
    pub symbol:&'static str, // via stringify!(...)
    // module:Rc<String>, // via module!()

    // Location in local filesystem:
    //pub file:&'static str,   // via file!()
    //pub line:u32,        // via line!()
    //pub column:u32,      // via column!()
}

pub fn my_hash<T>(obj: T) -> u64
    where T: Hash
{
    let mut hasher = SipHasher::new();
    obj.hash(&mut hasher);
    hasher.finish()
}

#[macro_export]
macro_rules! prog_pt {
    ($symbol:ident) => {{
        ProgPt{
            symbol:stringify!($symbol),
            //file:file!(),
            //line:line!(),
            //column:column!(),
        }
    }}
}

#[macro_export]
macro_rules! thunk {
    ( $st:expr , $nm:expr =>> $f:ident :: < $( $ty:ty ),* > , $( $lab:ident : $arg:expr ),* ) => {{
        ($st).thunk
            (ArtIdChoice::Nominal($nm),
             prog_pt!(f),
             Rc::new(Box::new(
                 |st, args, _|{
                     let ($( $lab ),*, ) = args ;
                     $f :: < $( $ty ),* >( st, $( $lab ),* )
                 })),
             ( $( $arg ),* ),
             ()
             )
    }}
    ;
    ( $st:expr , $nm:expr =>> $f:ident , $( $lab:ident : $arg:expr ),* ) => {{
        ($st).thunk
            (ArtIdChoice::Nominal($nm),
             prog_pt!(f),
             Rc::new(Box::new(
                 |st, args, _|{
                     let ($( $lab ),*) = args ;
                     $f ( st, $( $lab ),* )
                 })),
             ( $( $arg ),* ),
             ()
             )
    }}
    ;
    ( $st:expr , $f:ident :: < $( $ty:ty ),* > , $( $lab:ident : $arg:expr ),* ) => {{
        ($st).thunk
            (ArtIdChoice::Structural,
             prog_pt!(f),
             Rc::new(Box::new(
                 |st, args, _|{
                     let ($( $lab ),*) = args ;
                     $f :: < $( $ty ),* >( st, $( $lab ),* )
                 })),
             ( $( $arg ),* ),
             ()
             )
    }}
    ;
    ( $st:expr , $f:path , $( $lab:ident : $arg:expr ),* ) => {{
        ($st).thunk
            (ArtIdChoice::Structural,
             prog_pt!(f),
             Rc::new(Box::new(
                 |st, args, _|{
                     let ($( $lab ),*) = args ;
                     $f ( st, $( $lab ),* () )
                 })),
             ( $( $arg ),* ),
             ()
             )
    }}
    ;
}

#[macro_export]
macro_rules! memo {
    ( $st:expr , $nm:expr =>> $f:ident :: < $( $ty:ty ),* > , $( $lab:ident : $arg:expr ),* ) => {{
        let t = ($st).thunk
            (ArtIdChoice::Nominal($nm),
             prog_pt!(f),
             Rc::new(Box::new(
                 |st, args, _|{
                     let ($( $lab ),*) = args ;
                     $f :: < $( $ty ),* >( st, $( $lab ),* )
                 })),
             ( $( $arg ),*, ),
             ()
             );
        ($st).force(&t)
    }}
    ;
    ( $st:expr , $nm:expr =>> $f:path , $( $lab:ident : $arg:expr ),* ) => {{
        let t = ($st).thunk
            (ArtIdChoice::Nominal($nm),
             prog_pt!(f),
             Rc::new(Box::new(
                 |st, args, _|{
                     let ($( $lab ),*) = args ;
                     $f ( st, $( $lab ),* )
                 })),
             ( $( $arg ),* ),
             ()
             );
        ($st).force(&t)
    }}
    ;
    ( $st:expr , $f:ident :: < $( $ty:ty ),* > , $( $lab:ident : $arg:expr ),* ) => {{
        let t = ($st).thunk
            (ArtIdChoice::Structural,
             prog_pt!(f),
             Rc::new(Box::new(
                 |st, args, _|{
                     let ($( $lab ),*) = args ;
                     $f :: < $( $ty ),* >( st, $( $lab ),* )
                 })),
             ( $( $arg ),* ),
             ()
             );
        ($st).force(&t)
    }}
    ;
    ( $st:expr , $f:path , $( $lab:ident : $arg:expr ),* ) => {{
        let t = ($st).thunk
            (ArtIdChoice::Structural,
             prog_pt!(f),
             Rc::new(Box::new(
                 |st, args, _|{
                     let ($( $lab ),*) = args ;
                     $f ( st, $( $lab ),* )
                 })),
             ( $( $arg ),* ),
             ()
             );
        ($st).force(&t)
    }}
    ;
    ( $st:expr , $nm:expr =>> $f:path , $( $lab1:ident : $arg1:expr ),* ;; $( $lab2:ident : $arg2:expr ),* ) => {{
        let t = ($st).thunk
            (ArtIdChoice::Nominal($nm),
             prog_pt!(f),
             Rc::new(Box::new(
                 |st, args1, args2|{
                     let ($( $lab1 ),*) = args1 ;
                     let ($( $lab2 ),*) = args2 ;
                     $f ( st, $( $lab1 ),* , $( $lab2 ),* )
                 })),
             ( $( $arg1 ),* ),
             ( $( $arg2 ),* ),
             );
        ($st).force(&t)
    }}
    ;
}

// https://doc.rust-lang.org/book/macros.html
//
// macro_rules! o_O {
//     (
//         $(
//             $x:expr; [ $( $y:expr ),* ]
//          );*
//     ) => {
//         &[ $($( $x + $y ),*),* ]
//     }
// }
//
// fn main() {
//     let a: &[i32]
//         = o_O!(10; [1, 2, 3];
//                20; [4, 5, 6]);
//
//     assert_eq!(a, [11, 12, 13, 24, 25, 26]);
// }

// TODO: Need to gensym a variable for each argument below:
//
// macro_rules! thunk {
//     ( $f:ident , $st:expr , $( $arg:expr ),* ) => {
//         let fval = Rc::new(Box::new(
//             |st, args|{
//                 let ($( $arg ),*) = args ;
//                 f( st, $( $arg ),* )
//             })) ;
//         ($st).thunk (ArtId::Eager, prog_pt!(f), fval, $( $arg ),* )
//     }}
<|endoftext|>


<commit_before>use action::Action;
use config;
use context::base::BaseContext;
use dispatcher::Response;
use dispatcher::response::ResponseSender;
use message::{
    Message,
    MessageBuilder
};

use handlebars::{
    Template
};
use std::borrow::Borrow;
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::rc::Rc;
use state::State;

mod error;
mod renderer_context;
#[cfg(test)]
mod test;

pub const CONTEXT_UUID: &'static str = ".context.uuid";
pub const CONTEXT_NAME: &'static str = ".context.name";

pub struct MessageAction {
    sender: Rc<RefCell<Box<ResponseSender<Response>>>>,
    uuid: String,
    name: Option<String>,
    message: Template,
    values: BTreeMap<String, String>
}

impl MessageAction {
    pub fn new(sender: Rc<RefCell<Box<ResponseSender<Response>>>>, action: config::action::MessageAction) -> MessageAction {
        let config::action::MessageAction { uuid, name, message, values } = action;
        MessageAction {
            sender: sender,
            uuid: uuid,
            name: name,
            message: message,
            values: values
        }
    }
}

#[derive(Debug)]
pub struct MessageResponse {
    message: Message,
}

impl MessageResponse {
    pub fn message(&self) -> &Message {
        &self.message
    }
}

impl Action for MessageAction {
    fn execute(&self, _state: &State, _context: &BaseContext) {
        trace!("MessageAction: executed");
        let name = self.name.as_ref().map(|name| name.borrow());
        let mut message = MessageBuilder::new(&self.uuid, "moricka message")
                        .name(name)
                        .values(self.values.clone())
                        .build();
        message.insert(".context.uuid", &_context.uuid().to_hyphenated_string());
        message.insert(".context.len", &_state.messages().len().to_string());
        if let Some(name) = _context.name() {
            message.insert(".context.name", name);
        }
        let response = MessageResponse {
            message: message,
        };
        self.sender.borrow_mut().send_response(Response::Message(response));
    }
}
<commit_msg>action::message: use Handlebars to render messages<commit_after>use action::Action;
use config;
use context::base::BaseContext;
use dispatcher::Response;
use dispatcher::response::ResponseSender;
use message::{
    Message,
    MessageBuilder
};

use handlebars::{
    Context,
    Handlebars,
    Template
};
use std::borrow::Borrow;
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::rc::Rc;
use state::State;
use self::error::Error;
use self::renderer_context::RendererContext;

mod error;
mod renderer_context;
#[cfg(test)]
mod test;

pub const CONTEXT_UUID: &'static str = ".context.uuid";
pub const CONTEXT_NAME: &'static str = ".context.name";

pub struct MessageAction {
    sender: Rc<RefCell<Box<ResponseSender<Response>>>>,
    uuid: String,
    name: Option<String>,
    message: Template,
    values: Handlebars
}

impl MessageAction {
    pub fn new(sender: Rc<RefCell<Box<ResponseSender<Response>>>>, action: config::action::MessageAction) -> MessageAction {
        let config::action::MessageAction { uuid, name, message, values } = action;
        let mut handlebars = Handlebars::new();
        for (name, template) in values.into_iter() {
            handlebars.register_template(&name, template);
        }

        MessageAction {
            sender: sender,
            uuid: uuid,
            name: name,
            message: message,
            values: handlebars
        }
    }

    fn render_value(&self, key: &String, template_context: &Context) -> Result<String, Error> {
        let mut writer = Vec::new();
        {
            try!(self.values.renderw(key, &template_context, &mut writer));
        }
        let string = try!(String::from_utf8(writer));
        Ok(string)
    }

    fn render_values(&self, template_context: &Context) -> Result<BTreeMap<String, String>, Error> {
        let mut rendered_values = BTreeMap::new();
        for (key, _) in self.values.get_templates() {
            let rendered_value = try!(self.render_value(key, &template_context));
            rendered_values.insert(key.to_string(), rendered_value);
        }
        Ok(rendered_values)
    }

    fn render_message(&self, state: &State, context: &BaseContext) -> Result<Message, Error> {
        let template_context = {
            use handlebars::Context;
            let context = RendererContext::new(state, context);
            Context::wraps(&context)
        };

        let rendered_values = try!(self.render_values(&template_context));
        let name = self.name.as_ref().map(|name| name.borrow());
        let message = MessageBuilder::new(&self.uuid, "moricka message")
                        .name(name)
                        .values(rendered_values)
                        .build();
        Ok(message)
    }
}

#[derive(Debug)]
pub struct MessageResponse {
    message: Message,
}

impl MessageResponse {
    pub fn message(&self) -> &Message {
        &self.message
    }
}

impl Action for MessageAction {
    fn execute(&self, _state: &State, _context: &BaseContext) {
        trace!("MessageAction: executed");
        match self.render_message(_state, _context) {
            Ok(mut message) => {
                message.insert(".context.uuid", &_context.uuid().to_hyphenated_string());
                message.insert(".context.len", &_state.messages().len().to_string());
                if let Some(name) = _context.name() {
                    message.insert(".context.name", name);
                }
                let response = MessageResponse {
                    message: message,
                };
                self.sender.borrow_mut().send_response(Response::Message(response));
            },
            Err(error) => {
                error!("{}", error);
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::i32;
use std::iter::repeat;
use std::cmp::max;
use std::collections::Bitv;

use alignment::{Alignment, AlignmentOperation};

#[derive(Copy)]
enum AlignmentType {
    Global,
    Semiglobal,
    Local
}

/// Calculate alignments with a generalized variant of the Smith Waterman algorithm.
/// Complexity: O(n * m) for strings of length m and n.
///
/// # Example
///
/// ```
/// use bio::alignment::pairwise::Aligner;
/// use bio::alignment::AlignmentOperation::{Match, Subst, Ins, Del};
/// let x = b"ACCGTGGAT";
/// let y = b"AAAAACCGTTGAT";
/// let score = |&: a: u8, b: u8| if a == b {1i32} else {-1i32};
/// let mut aligner = Aligner::with_capacity(x.len(), y.len(), -5, -1, score);
/// let alignment = aligner.semiglobal(x, y);
/// assert_eq!(alignment.i, 4);
/// assert_eq!(alignment.j, 0);
/// assert_eq!(alignment.operations, [Match, Match, Match, Match, Match, Subst, Match, Match, Match]);
/// ```
#[allow(non_snake_case)]
pub struct Aligner<F> where F: Fn(u8, u8) -> i32 {
    S: [Vec<i32>; 2],
    I: [Vec<i32>; 2],
    D: [Vec<i32>; 2],
    traceback: Traceback,
    gap_open: i32,
    gap_extend: i32,
    score: F
}

impl<F> Aligner<F> where F: Fn(u8, u8) -> i32 {
    /// Create new aligner instance. The size hints help to
    /// avoid unnecessary memory allocations.
    ///
    /// # Arguments
    ///
    /// * `m` - the expected size of x
    /// * `n` - the expected size of y
    /// * `gap_open` - the score for opening a gap (should be negative)
    /// * `gap_extend` - the score for extending a gap (should be negative)
    /// * `score` - function that returns the score for substitutions
    ///
    pub fn with_capacity(m: usize, n: usize, gap_open: i32, gap_extend: i32, score: F) -> Self {
        let get_vec = |&:| Vec::with_capacity(m + 1);
        Aligner {
            S: [get_vec(), get_vec()],
            I: [get_vec(), get_vec()],
            D: [get_vec(), get_vec()],
            traceback: Traceback::with_capacity(m, n),
            gap_open: gap_open,
            gap_extend: gap_extend,
            score: score
        }
    }

    fn init(&mut self, m: usize, alignment_type: AlignmentType) {
        // set minimum score to -inf, and allow to add gap_extend
        // without overflow
        let min_score = i32::MIN - self.gap_extend;
        for k in 0..2us {
            self.S[k].clear();
            self.I[k].clear();
            self.D[k].clear();
            self.I[k].extend(repeat(min_score).take(m + 1));
            self.D[k].extend(repeat(min_score).take(m + 1));
            match alignment_type {
                AlignmentType::Global => {
                    let ref mut s = self.S[k];
                    let mut score = self.gap_open;
                    for _ in 0..m+1 {
                        s.push(score);
                        score += self.gap_extend;
                    }
                },
                _ => self.S[k].extend(repeat(0).take(m + 1))
            }
        }
    }

    pub fn global(&mut self, x: &[u8], y: &[u8]) -> Alignment {
        self.align(x, y, AlignmentType::Global)
    }

    pub fn semiglobal(&mut self, x: &[u8], y: &[u8]) -> Alignment {
        self.align(x, y, AlignmentType::Semiglobal)
    }

    pub fn local(&mut self, x: &[u8], y: &[u8]) -> Alignment {
        self.align(x, y, AlignmentType::Local)
    }

    fn align(&mut self, x: &[u8], y: &[u8], alignment_type: AlignmentType) -> Alignment {
        let (m, n) = (x.len(), y.len());

        self.init(m, alignment_type);
        self.traceback.init(n, alignment_type);

        let (mut best, mut best_i, mut best_j) = (0, 0, 0);
        let mut col = 0;

        for i in 1..n+1 {
            col = i % 2;
            let prev = 1 - col;

            match alignment_type {
                AlignmentType::Global => {
                    self.S[col][0] = self.gap_open + (i as i32 - 1) * self.gap_extend;
                    self.traceback.del(i, 0);
                },
                _ => {
                    // with local and semiglobal, allow to begin anywhere in y
                    self.S[col][0] = 0;
                }
            }

            let b = y[i - 1];
            let mut score = 0i32;
            for j in 1..m+1 {
                let a = x[j - 1];

                let d_score = max(
                    self.S[prev][j] + self.gap_open,
                    self.D[prev][j] + self.gap_extend
                );
                let i_score = max(
                    self.S[col][j-1] + self.gap_open,
                    self.I[col][j-1] + self.gap_extend
                );
                score = self.S[prev][j-1] + (self.score)(a, b);

                if d_score > score {
                    score = d_score;
                    self.traceback.del(i, j);
                }
                else if i_score > score {
                    score = i_score;
                    self.traceback.ins(i, j);
                }
                else {
                    self.traceback.subst(i, j);
                }

                match alignment_type {
                    AlignmentType::Local => {
                        if score < 0 {
                            self.traceback.start(i, j);
                            score = 0;
                        }
                        else if score > best {
                            best = score;
                            best_i = i;
                            best_j = j;
                        }
                    },
                    _ => ()
                }

                self.S[col][j] = score;
                self.D[col][j] = d_score;
                self.I[col][j] = i_score;
            }

            match alignment_type {
                AlignmentType::Semiglobal => {
                    if score > best {
                        best = score;
                        best_i = i;
                        best_j = m;
                    }
                },
                _ => ()
            }
        }
        match alignment_type {
            AlignmentType::Global => {
                let score = self.S[col][m];
                self.traceback.get_alignment(n, m, x, y, score)
            },
            _ => self.traceback.get_alignment(best_i, best_j, x, y, best)
        }

    }
}

struct Traceback {
    subst: Vec<Bitv>,
    del: Vec<Bitv>,
    ins: Vec<Bitv>
}

impl Traceback {
    fn with_capacity(m: usize, n: usize) -> Self {
        let get_vec = |&:| repeat(Bitv::from_elem(m + 1, false)).take(n + 1).collect::<Vec<Bitv>>();
        Traceback {
            subst: get_vec(),
            del: get_vec(),
            ins: get_vec()
        }
    }

    fn init(&mut self, n: usize, alignment_type: AlignmentType) {
        match alignment_type {
            AlignmentType::Global => {
                for i in 0..n+1 {
                    self.subst[i].set_all();
                    self.subst[i].negate();
                    self.del[i].set_all();
                    self.ins[i].set_all();
                    self.ins[i].negate();
                }
                // set the first cell to start, the rest to deletions
                self.del[0].set(0, false);
            },
            _ => {
                for i in 0..n+1 {
                    self.subst[i].set_all();
                    self.subst[i].negate();
                    self.del[i].set_all();
                    self.del[i].negate();
                    self.ins[i].set_all();
                    self.ins[i].negate();
                }
            }
        }
    }

    fn start(&mut self, i: usize, j: usize) {
        self.subst[i].set(j, false);
        self.del[i].set(j, false);
        self.ins[i].set(j, false);
    }

    fn subst(&mut self, i: usize, j: usize) {
        self.subst[i].set(j, true);
    }

    fn del(&mut self, i: usize, j: usize) {
        self.del[i].set(j, true);
    }

    fn ins(&mut self, i: usize, j: usize) {
        self.ins[i].set(j, true);
    }

    fn is_subst(&self, i: usize, j: usize) -> bool {
        self.subst[i].get(j).unwrap()
    }

    fn is_del(&self, i: usize, j: usize) -> bool {
        self.del[i].get(j).unwrap()
    }

    fn is_ins(&self, i: usize, j: usize) -> bool {
        self.ins[i].get(j).unwrap()
    }

    fn get_alignment(&self, mut i: usize, mut j: usize, x: &[u8], y: &[u8], score: i32) -> Alignment {
        let mut ops = Vec::with_capacity(x.len());

        loop {
            let (ii, jj, op) = if self.is_subst(i, j) {
                let op = if y[i-1] == x[j-1] {
                    AlignmentOperation::Match
                }
                else {
                    AlignmentOperation::Subst
                };
                (i - 1, j - 1, op)
            }
            else if self.is_del(i, j) {
                (i - 1, j, AlignmentOperation::Del)
            }
            else if self.is_ins(i, j) {
                (i, j - 1, AlignmentOperation::Ins)
            } else {
                // reached alignment start
                break;
            };
            ops.push(op);
            i = ii;
            j = jj;
        }

        ops.reverse();
        Alignment { i: i, j: j, operations: ops, score: score}
    }
}

#[cfg(test)]
mod tests {
    use super::Aligner;
    use alignment::AlignmentOperation::{Match, Subst, Del};

    #[test]
    fn test_semiglobal() {
        let x = b"ACCGTGGAT";
        let y = b"AAAAACCGTTGAT";
        let score = |&: a: u8, b: u8| if a == b {1i32} else {-1i32};
        let mut aligner = Aligner::with_capacity(x.len(), y.len(), -5, -1, score);
        let alignment = aligner.semiglobal(x, y);
        assert_eq!(alignment.i, 4);
        assert_eq!(alignment.j, 0);
        assert_eq!(alignment.operations, [Match, Match, Match, Match, Match, Subst, Match, Match, Match]);
    }

    #[test]
    fn test_local() {
        let x = b"ACCGTGGAT";
        let y = b"AAAAACCGTTGAT";
        let score = |&: a: u8, b: u8| if a == b {1i32} else {-1i32};
        let mut aligner = Aligner::with_capacity(x.len(), y.len(), -5, -1, score);
        let alignment = aligner.local(x, y);
        assert_eq!(alignment.i, 4);
        assert_eq!(alignment.j, 0);
        assert_eq!(alignment.operations, [Match, Match, Match, Match, Match, Subst, Match, Match, Match]);
    }

    #[test]
    fn test_global() {
        let x = b"ACCGTGGAT";
        let y = b"AAAAACCGTTGAT";
        let score = |&: a: u8, b: u8| if a == b {1i32} else {-1i32};
        let mut aligner = Aligner::with_capacity(x.len(), y.len(), -5, -1, score);
        let alignment = aligner.global(x, y);
        assert_eq!(alignment.i, 0);
        assert_eq!(alignment.j, 0);
        assert_eq!(alignment.operations, [Del, Del, Del, Del, Match, Match, Match, Match, Match, Subst, Match, Match, Match]);
    }
}
<commit_msg>Docs.<commit_after>use std::i32;
use std::iter::repeat;
use std::cmp::max;
use std::collections::Bitv;

use alignment::{Alignment, AlignmentOperation};

#[derive(Copy)]
enum AlignmentType {
    Global,
    Semiglobal,
    Local
}

/// Calculate alignments with a generalized variant of the Smith Waterman algorithm.
/// Complexity: O(n * m) for strings of length m and n.
///
/// # Example
///
/// ```
/// use bio::alignment::pairwise::Aligner;
/// use bio::alignment::AlignmentOperation::{Match, Subst, Ins, Del};
/// let x = b"ACCGTGGAT";
/// let y = b"AAAAACCGTTGAT";
/// let score = |&: a: u8, b: u8| if a == b {1i32} else {-1i32};
/// let mut aligner = Aligner::with_capacity(x.len(), y.len(), -5, -1, score);
/// let alignment = aligner.semiglobal(x, y);
/// assert_eq!(alignment.i, 4);
/// assert_eq!(alignment.j, 0);
/// assert_eq!(alignment.operations, [Match, Match, Match, Match, Match, Subst, Match, Match, Match]);
/// ```
#[allow(non_snake_case)]
pub struct Aligner<F> where F: Fn(u8, u8) -> i32 {
    S: [Vec<i32>; 2],
    I: [Vec<i32>; 2],
    D: [Vec<i32>; 2],
    traceback: Traceback,
    gap_open: i32,
    gap_extend: i32,
    score: F
}

impl<F> Aligner<F> where F: Fn(u8, u8) -> i32 {
    /// Create new aligner instance. The size hints help to
    /// avoid unnecessary memory allocations.
    ///
    /// # Arguments
    ///
    /// * `m` - the expected size of x
    /// * `n` - the expected size of y
    /// * `gap_open` - the score for opening a gap (should be negative)
    /// * `gap_extend` - the score for extending a gap (should be negative)
    /// * `score` - function that returns the score for substitutions
    ///
    pub fn with_capacity(m: usize, n: usize, gap_open: i32, gap_extend: i32, score: F) -> Self {
        let get_vec = |&:| Vec::with_capacity(m + 1);
        Aligner {
            S: [get_vec(), get_vec()],
            I: [get_vec(), get_vec()],
            D: [get_vec(), get_vec()],
            traceback: Traceback::with_capacity(m, n),
            gap_open: gap_open,
            gap_extend: gap_extend,
            score: score
        }
    }

    fn init(&mut self, m: usize, alignment_type: AlignmentType) {
        // set minimum score to -inf, and allow to add gap_extend
        // without overflow
        let min_score = i32::MIN - self.gap_extend;
        for k in 0..2us {
            self.S[k].clear();
            self.I[k].clear();
            self.D[k].clear();
            self.I[k].extend(repeat(min_score).take(m + 1));
            self.D[k].extend(repeat(min_score).take(m + 1));
            match alignment_type {
                AlignmentType::Global => {
                    let ref mut s = self.S[k];
                    let mut score = self.gap_open;
                    for _ in 0..m+1 {
                        s.push(score);
                        score += self.gap_extend;
                    }
                },
                _ => self.S[k].extend(repeat(0).take(m + 1))
            }
        }
    }

    /// Calculate global alignment.
    pub fn global(&mut self, x: &[u8], y: &[u8]) -> Alignment {
        self.align(x, y, AlignmentType::Global)
    }

    /// Calculate semiglobal alignment.
    pub fn semiglobal(&mut self, x: &[u8], y: &[u8]) -> Alignment {
        self.align(x, y, AlignmentType::Semiglobal)
    }

    /// Calculate local alignment.
    pub fn local(&mut self, x: &[u8], y: &[u8]) -> Alignment {
        self.align(x, y, AlignmentType::Local)
    }

    fn align(&mut self, x: &[u8], y: &[u8], alignment_type: AlignmentType) -> Alignment {
        let (m, n) = (x.len(), y.len());

        self.init(m, alignment_type);
        self.traceback.init(n, alignment_type);

        let (mut best, mut best_i, mut best_j) = (0, 0, 0);
        let mut col = 0;

        for i in 1..n+1 {
            col = i % 2;
            let prev = 1 - col;

            match alignment_type {
                AlignmentType::Global => {
                    self.S[col][0] = self.gap_open + (i as i32 - 1) * self.gap_extend;
                    self.traceback.del(i, 0);
                },
                _ => {
                    // with local and semiglobal, allow to begin anywhere in y
                    self.S[col][0] = 0;
                }
            }

            let b = y[i - 1];
            let mut score = 0i32;
            for j in 1..m+1 {
                let a = x[j - 1];

                let d_score = max(
                    self.S[prev][j] + self.gap_open,
                    self.D[prev][j] + self.gap_extend
                );
                let i_score = max(
                    self.S[col][j-1] + self.gap_open,
                    self.I[col][j-1] + self.gap_extend
                );
                score = self.S[prev][j-1] + (self.score)(a, b);

                if d_score > score {
                    score = d_score;
                    self.traceback.del(i, j);
                }
                else if i_score > score {
                    score = i_score;
                    self.traceback.ins(i, j);
                }
                else {
                    self.traceback.subst(i, j);
                }

                match alignment_type {
                    AlignmentType::Local => {
                        if score < 0 {
                            self.traceback.start(i, j);
                            score = 0;
                        }
                        else if score > best {
                            best = score;
                            best_i = i;
                            best_j = j;
                        }
                    },
                    _ => ()
                }

                self.S[col][j] = score;
                self.D[col][j] = d_score;
                self.I[col][j] = i_score;
            }

            match alignment_type {
                AlignmentType::Semiglobal => {
                    if score > best {
                        best = score;
                        best_i = i;
                        best_j = m;
                    }
                },
                _ => ()
            }
        }
        match alignment_type {
            AlignmentType::Global => {
                let score = self.S[col][m];
                self.traceback.get_alignment(n, m, x, y, score)
            },
            _ => self.traceback.get_alignment(best_i, best_j, x, y, best)
        }

    }
}

struct Traceback {
    subst: Vec<Bitv>,
    del: Vec<Bitv>,
    ins: Vec<Bitv>
}

impl Traceback {
    fn with_capacity(m: usize, n: usize) -> Self {
        let get_vec = |&:| repeat(Bitv::from_elem(m + 1, false)).take(n + 1).collect::<Vec<Bitv>>();
        Traceback {
            subst: get_vec(),
            del: get_vec(),
            ins: get_vec()
        }
    }

    fn init(&mut self, n: usize, alignment_type: AlignmentType) {
        match alignment_type {
            AlignmentType::Global => {
                for i in 0..n+1 {
                    self.subst[i].set_all();
                    self.subst[i].negate();
                    self.del[i].set_all();
                    self.ins[i].set_all();
                    self.ins[i].negate();
                }
                // set the first cell to start, the rest to deletions
                self.del[0].set(0, false);
            },
            _ => {
                for i in 0..n+1 {
                    self.subst[i].set_all();
                    self.subst[i].negate();
                    self.del[i].set_all();
                    self.del[i].negate();
                    self.ins[i].set_all();
                    self.ins[i].negate();
                }
            }
        }
    }

    fn start(&mut self, i: usize, j: usize) {
        self.subst[i].set(j, false);
        self.del[i].set(j, false);
        self.ins[i].set(j, false);
    }

    fn subst(&mut self, i: usize, j: usize) {
        self.subst[i].set(j, true);
    }

    fn del(&mut self, i: usize, j: usize) {
        self.del[i].set(j, true);
    }

    fn ins(&mut self, i: usize, j: usize) {
        self.ins[i].set(j, true);
    }

    fn is_subst(&self, i: usize, j: usize) -> bool {
        self.subst[i].get(j).unwrap()
    }

    fn is_del(&self, i: usize, j: usize) -> bool {
        self.del[i].get(j).unwrap()
    }

    fn is_ins(&self, i: usize, j: usize) -> bool {
        self.ins[i].get(j).unwrap()
    }

    fn get_alignment(&self, mut i: usize, mut j: usize, x: &[u8], y: &[u8], score: i32) -> Alignment {
        let mut ops = Vec::with_capacity(x.len());

        loop {
            let (ii, jj, op) = if self.is_subst(i, j) {
                let op = if y[i-1] == x[j-1] {
                    AlignmentOperation::Match
                }
                else {
                    AlignmentOperation::Subst
                };
                (i - 1, j - 1, op)
            }
            else if self.is_del(i, j) {
                (i - 1, j, AlignmentOperation::Del)
            }
            else if self.is_ins(i, j) {
                (i, j - 1, AlignmentOperation::Ins)
            } else {
                // reached alignment start
                break;
            };
            ops.push(op);
            i = ii;
            j = jj;
        }

        ops.reverse();
        Alignment { i: i, j: j, operations: ops, score: score}
    }
}

#[cfg(test)]
mod tests {
    use super::Aligner;
    use alignment::AlignmentOperation::{Match, Subst, Del};

    #[test]
    fn test_semiglobal() {
        let x = b"ACCGTGGAT";
        let y = b"AAAAACCGTTGAT";
        let score = |&: a: u8, b: u8| if a == b {1i32} else {-1i32};
        let mut aligner = Aligner::with_capacity(x.len(), y.len(), -5, -1, score);
        let alignment = aligner.semiglobal(x, y);
        assert_eq!(alignment.i, 4);
        assert_eq!(alignment.j, 0);
        assert_eq!(alignment.operations, [Match, Match, Match, Match, Match, Subst, Match, Match, Match]);
    }

    #[test]
    fn test_local() {
        let x = b"ACCGTGGAT";
        let y = b"AAAAACCGTTGAT";
        let score = |&: a: u8, b: u8| if a == b {1i32} else {-1i32};
        let mut aligner = Aligner::with_capacity(x.len(), y.len(), -5, -1, score);
        let alignment = aligner.local(x, y);
        assert_eq!(alignment.i, 4);
        assert_eq!(alignment.j, 0);
        assert_eq!(alignment.operations, [Match, Match, Match, Match, Match, Subst, Match, Match, Match]);
    }

    #[test]
    fn test_global() {
        let x = b"ACCGTGGAT";
        let y = b"AAAAACCGTTGAT";
        let score = |&: a: u8, b: u8| if a == b {1i32} else {-1i32};
        let mut aligner = Aligner::with_capacity(x.len(), y.len(), -5, -1, score);
        let alignment = aligner.global(x, y);
        assert_eq!(alignment.i, 0);
        assert_eq!(alignment.j, 0);
        assert_eq!(alignment.operations, [Del, Del, Del, Del, Match, Match, Match, Match, Match, Subst, Match, Match, Match]);
    }
}
<|endoftext|>


<commit_before>//! # Lucet Runtime for Sandboxed WebAssembly Applications
//!
//! This crate runs programs that were compiled with the `lucetc` WebAssembly to native code
//! compiler. It provides an interface for modules to be loaded from shared object files (see
//! `DlModule`), and for hosts to provide specialized functionality to guests (see
//! `Instance::embed_ctx()`).
//!
//! The runtime is a critical part of the safety and security story for Lucet. While the semantics
//! of WebAssembly and the `lucetc` compiler provide many guarantees, the runtime must be correct in
//! order for the assumptions of those guarantees to hold. For example, the runtime uses guard pages
//! to ensure that any attempts by guest programs to access memory past the end of the guest heap are
//! safely caught.
//!
//! The runtime is also extensible, and some of the key types are defined as traits for
//! flexibility. See the `lucet-runtime-internals` crate for details.
//!
//! ## Running a Lucet Program
//!
//! There are a few essential types for using the runtime:
//!
//! - [`Instance`](struct.Instance.html): a Lucet program, together with its dedicated memory and
//! signal handlers. Users of this API never own an `Instance` directly, but can own the
//! [`InstanceHandle`](struct.InstanceHandle.html) smart pointer.
//!
//! - [`Region`](trait.Region.html): the memory from which instances are created. This crate
//! includes [`MmapRegion`](struct.MmapRegion.html), an implementation backed by `mmap`.
//!
//! - [`Limits`](struct.Limits.html): upper bounds for the resources a Lucet instance may
//! consume. These may be larger or smaller than the limits described in the WebAssembly module
//! itself; the smaller limit is always enforced.
//!
//! - [`Module`](trait.Module.html): the read-only parts of a Lucet program, including its code and
//! initial heap configuration. This crate includes [`DlModule`](struct.DlModule.html), an
//! implementation backed by dynamic loading of shared objects.
//!
//! - [`Val`](enum.Val.html): an enum describing values in WebAssembly, used to provide
//! arguments. These can be created using `From` implementations of primitive types, for example
//! `5u64.into()` in the example below.
//!
//! - [`UntypedRetVal`](struct.UntypedRetVal.html): values returned from WebAssembly
//! functions. These must be interpreted at the correct type by the user via `From` implementations
//! or `retval.as_T()` methods, for example `u64::from(retval)` in the example below.
//!
//! To run a Lucet program, you start by creating a region, capable of backing a number of
//! instances. You then load a module and then create a new instance using the region and the
//! module. You can then run any of the functions that the Lucet program exports, retrieve return
//! values from those functions, and access the linear memory of the guest.
//!
//! ```no_run
//! use lucet_runtime::{DlModule, Limits, MmapRegion, Region};
//!
//! let module = DlModule::load("/my/lucet/module.so").unwrap();
//! let region = MmapRegion::create(1, &Limits::default()).unwrap();
//! let mut inst = region.new_instance(module).unwrap();
//!
//! let retval = inst.run(b"factorial", &[5u64.into()]).unwrap();
//! assert_eq!(u64::from(retval), 120u64);
//! ```
//!
//! ## Embedding With Hostcalls
//!
//! A "hostcall" is a function called by WebAssembly that is not defined in WebAssembly. Since
//! WebAssembly is such a minimal language, hostcalls are required for Lucet programs to do anything
//! interesting with the outside world. For example, in Fastly's [Terrarium
//! demo](https://wasm.fastly-labs.com/), hostcalls are provided for manipulating HTTP requests,
//! accessing a key/value store, etc.
//!
//! Some simple hostcalls can be implemented simply as an exported C function that takes an opaque
//! pointer argument (usually called `vmctx`). Hostcalls that require access to some underlying
//! state, such as the key/value store in Terrarium, can access a custom embedder context through
//! `vmctx`. For example, to make a `u32` available to hostcalls:
//!
//! ```no_run
//! use lucet_runtime::{DlModule, Limits, MmapRegion, Region};
//! use lucet_runtime::vmctx::{Vmctx, lucet_vmctx};
//!
//! struct MyContext { x: u32 }
//!
//! #[no_mangle]
//! unsafe extern "C" fn foo(vmctx: *mut lucet_vmctx) {
//!     let mut vmctx = Vmctx::from_raw(vmctx);
//!     let hostcall_context = vmctx
//!         .get_embed_ctx_mut::<MyContext>();
//!     hostcall_context.x = 42;
//! }
//!
//! let module = DlModule::load("/my/lucet/module.so").unwrap();
//! let region = MmapRegion::create(1, &Limits::default()).unwrap();
//! let mut inst = region
//!     .new_instance_builder(module)
//!     .with_embed_ctx(MyContext { x: 0 })
//!     .build()
//!     .unwrap();
//!
//! inst.run(b"call_foo", &[]).unwrap();
//!
//! let context_after = inst.get_embed_ctx::<MyContext>().unwrap();
//! assert_eq!(context_after.x, 42);
//! ```
//!
//! The embedder context is backed by a structure that can hold a single value of any type. Rust
//! embedders should add their own custom state type (like `MyContext` above) for any context they
//! require, rather than using a common type (such as the `u32`) from the standard library. This
//! avoids collisions between libraries, and allows for easy composition of embeddings.
//!
//! For C-based embedders, the type `*mut libc::c_void` is privileged as the only type that the C
//! API provides. The following example shows how a Rust embedder can initialize a C-compatible
//! context:
//!
//! ```no_run
//! use lucet_runtime::{DlModule, Limits, MmapRegion, Region};
//!
//! let module = DlModule::load("/my/lucet/module.so").unwrap();
//! let region = MmapRegion::create(1, &Limits::default()).unwrap();
//! struct PretendLibcRuntime { _unused: u8 };
//! let mut libc = PretendLibcRuntime { _unused: 0 };
//! let mut inst = region
//!     .new_instance_builder(module)
//!     .with_embed_ctx(libc)
//!     .build()
//!     .unwrap();
//!
//! inst.run(b"main", &[]).unwrap();
//!
//! // clean up embedder context
//! drop(inst);
//! ```
//!
//! ## Custom Signal Handlers
//!
//! Since Lucet programs are run as native machine code, signals such as `SIGSEGV` and `SIGFPE` can
//! arise during execution. Rather than letting these signals bring down the entire process, the
//! Lucet runtime installs alternate signal handlers that limit the effects to just the instance
//! that raised the signal.
//!
//! By default, the signal handler sets the instance state to `State::Fault` and returns early from
//! the call to `Instance::run()`. You can, however, implement custom error recovery and logging
//! behavior by defining new signal handlers on a per-instance basis. For example, the following
//! signal handler increments a counter of signals it has seen before setting the fault state:
//!
//! ```no_run
//! use lucet_runtime::{
//!     DlModule, Error, Instance, Limits, MmapRegion, Region, SignalBehavior, TrapCode
//! };
//! use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
//!
//! static SIGNAL_COUNT: AtomicUsize = ATOMIC_USIZE_INIT;
//!
//! fn signal_handler_count(
//!     _inst: &Instance,
//!     _trapcode: &TrapCode,
//!     _signum: libc::c_int,
//!     _siginfo_ptr: *const libc::siginfo_t,
//!     _ucontext_ptr: *const libc::c_void,
//! ) -> SignalBehavior {
//!     SIGNAL_COUNT.fetch_add(1, Ordering::SeqCst);
//!     SignalBehavior::Default
//! }
//!
//! let module = DlModule::load("/my/lucet/module.so").unwrap();
//! let region = MmapRegion::create(1, &Limits::default()).unwrap();
//! let mut inst = region.new_instance(module).unwrap();
//!
//! // install the handler
//! inst.set_signal_handler(signal_handler_count);
//!
//! match inst.run(b"raise_a_signal", &[]) {
//!     Err(Error::RuntimeFault(_)) => {
//!         println!("I've now handled {} signals!", SIGNAL_COUNT.load(Ordering::SeqCst));
//!     }
//!     res => panic!("unexpected result: {:?}", res),
//! }
//! ```
//!
//! When implementing custom signal handlers for the Lucet runtime, the usual caveats about signal
//! safety apply: see
//! [`signal-safety(7)`](http://man7.org/linux/man-pages/man7/signal-safety.7.html).
//!
//! ## Interaction With Host Signal Handlers
//!
//! Great care must be taken if host application installs or otherwise modifies signal handlers
//! anywhere in the process. Lucet installs handlers for `SIGBUS`, `SIGFPE`, `SIGILL`, and `SIGSEGV`
//! when the first Lucet instance begins running, and restores the preëxisting handlers when the
//! last Lucet instance terminates. During this time, other threads in the host process *must not*
//! modify those signal handlers, since signal handlers can only be installed on a process-wide
//! basis.
//!
//! Despite this limitation, Lucet is designed to compose with other signal handlers in the host
//! program. If one of the above signals is caught by the Lucet signal handler, but that thread is
//! not currently running a Lucet instance, the saved host signal handler is called. This means
//! that, for example, a `SIGSEGV` on a non-Lucet thread of a host program will still likely abort
//! the entire process.

pub use lucet_runtime_internals::alloc::Limits;
pub use lucet_runtime_internals::error::Error;
pub use lucet_runtime_internals::instance::{
    FaultDetails, Instance, InstanceHandle, SignalBehavior, TerminationDetails,
};
pub use lucet_runtime_internals::module::{DlModule, Module};
pub use lucet_runtime_internals::region::mmap::MmapRegion;
pub use lucet_runtime_internals::region::{InstanceBuilder, Region};
pub use lucet_runtime_internals::trapcode::{TrapCode, TrapCodeType};
pub use lucet_runtime_internals::val::{UntypedRetVal, Val};
pub use lucet_runtime_internals::WASM_PAGE_SIZE;

pub mod vmctx {
    //! Functions for manipulating instances from hostcalls.
    //!
    //! The Lucet compiler inserts an extra `*mut lucet_vmctx` argument to all functions defined and
    //! called by WebAssembly code. Through this pointer, code running in the guest context can
    //! access and manipulate the instance and its structures. These functions are intended for use
    //! in hostcall implementations, and must only be used from within a running guest.
    //!
    //! # Panics
    //!
    //! All of the `Vmctx` methods will panic if the `Vmctx` was not created from a valid pointer
    //! associated with a running instance. This should never occur if run in guest code on the
    //! pointer argument inserted by the compiler.
    pub use lucet_runtime_internals::vmctx::{lucet_vmctx, Vmctx};
}

/// Call this if you're having trouble with `lucet_*` symbols not being exported.
///
/// This is pretty hackish; we will hopefully be able to avoid this altogether once [this
/// issue](https://github.com/rust-lang/rust/issues/58037) is addressed.
#[no_mangle]
pub extern "C" fn lucet_internal_ensure_linked() {
    lucet_runtime_internals::vmctx::vmctx_capi_init();
}
<commit_msg>lucet-runtime: fix doc comment about C context<commit_after>//! # Lucet Runtime for Sandboxed WebAssembly Applications
//!
//! This crate runs programs that were compiled with the `lucetc` WebAssembly to native code
//! compiler. It provides an interface for modules to be loaded from shared object files (see
//! `DlModule`), and for hosts to provide specialized functionality to guests (see
//! `Instance::embed_ctx()`).
//!
//! The runtime is a critical part of the safety and security story for Lucet. While the semantics
//! of WebAssembly and the `lucetc` compiler provide many guarantees, the runtime must be correct in
//! order for the assumptions of those guarantees to hold. For example, the runtime uses guard pages
//! to ensure that any attempts by guest programs to access memory past the end of the guest heap are
//! safely caught.
//!
//! The runtime is also extensible, and some of the key types are defined as traits for
//! flexibility. See the `lucet-runtime-internals` crate for details.
//!
//! ## Running a Lucet Program
//!
//! There are a few essential types for using the runtime:
//!
//! - [`Instance`](struct.Instance.html): a Lucet program, together with its dedicated memory and
//! signal handlers. Users of this API never own an `Instance` directly, but can own the
//! [`InstanceHandle`](struct.InstanceHandle.html) smart pointer.
//!
//! - [`Region`](trait.Region.html): the memory from which instances are created. This crate
//! includes [`MmapRegion`](struct.MmapRegion.html), an implementation backed by `mmap`.
//!
//! - [`Limits`](struct.Limits.html): upper bounds for the resources a Lucet instance may
//! consume. These may be larger or smaller than the limits described in the WebAssembly module
//! itself; the smaller limit is always enforced.
//!
//! - [`Module`](trait.Module.html): the read-only parts of a Lucet program, including its code and
//! initial heap configuration. This crate includes [`DlModule`](struct.DlModule.html), an
//! implementation backed by dynamic loading of shared objects.
//!
//! - [`Val`](enum.Val.html): an enum describing values in WebAssembly, used to provide
//! arguments. These can be created using `From` implementations of primitive types, for example
//! `5u64.into()` in the example below.
//!
//! - [`UntypedRetVal`](struct.UntypedRetVal.html): values returned from WebAssembly
//! functions. These must be interpreted at the correct type by the user via `From` implementations
//! or `retval.as_T()` methods, for example `u64::from(retval)` in the example below.
//!
//! To run a Lucet program, you start by creating a region, capable of backing a number of
//! instances. You then load a module and then create a new instance using the region and the
//! module. You can then run any of the functions that the Lucet program exports, retrieve return
//! values from those functions, and access the linear memory of the guest.
//!
//! ```no_run
//! use lucet_runtime::{DlModule, Limits, MmapRegion, Region};
//!
//! let module = DlModule::load("/my/lucet/module.so").unwrap();
//! let region = MmapRegion::create(1, &Limits::default()).unwrap();
//! let mut inst = region.new_instance(module).unwrap();
//!
//! let retval = inst.run(b"factorial", &[5u64.into()]).unwrap();
//! assert_eq!(u64::from(retval), 120u64);
//! ```
//!
//! ## Embedding With Hostcalls
//!
//! A "hostcall" is a function called by WebAssembly that is not defined in WebAssembly. Since
//! WebAssembly is such a minimal language, hostcalls are required for Lucet programs to do anything
//! interesting with the outside world. For example, in Fastly's [Terrarium
//! demo](https://wasm.fastly-labs.com/), hostcalls are provided for manipulating HTTP requests,
//! accessing a key/value store, etc.
//!
//! Some simple hostcalls can be implemented simply as an exported C function that takes an opaque
//! pointer argument (usually called `vmctx`). Hostcalls that require access to some underlying
//! state, such as the key/value store in Terrarium, can access a custom embedder context through
//! `vmctx`. For example, to make a `u32` available to hostcalls:
//!
//! ```no_run
//! use lucet_runtime::{DlModule, Limits, MmapRegion, Region};
//! use lucet_runtime::vmctx::{Vmctx, lucet_vmctx};
//!
//! struct MyContext { x: u32 }
//!
//! #[no_mangle]
//! unsafe extern "C" fn foo(vmctx: *mut lucet_vmctx) {
//!     let mut vmctx = Vmctx::from_raw(vmctx);
//!     let hostcall_context = vmctx
//!         .get_embed_ctx_mut::<MyContext>();
//!     hostcall_context.x = 42;
//! }
//!
//! let module = DlModule::load("/my/lucet/module.so").unwrap();
//! let region = MmapRegion::create(1, &Limits::default()).unwrap();
//! let mut inst = region
//!     .new_instance_builder(module)
//!     .with_embed_ctx(MyContext { x: 0 })
//!     .build()
//!     .unwrap();
//!
//! inst.run(b"call_foo", &[]).unwrap();
//!
//! let context_after = inst.get_embed_ctx::<MyContext>().unwrap();
//! assert_eq!(context_after.x, 42);
//! ```
//!
//! The embedder context is backed by a structure that can hold a single value of any type. Rust
//! embedders should add their own custom state type (like `MyContext` above) for any context they
//! require, rather than using a common type (such as the `u32`) from the standard library. This
//! avoids collisions between libraries, and allows for easy composition of embeddings.
//!
//! For C-based embedders, the type `*mut libc::c_void` is privileged as the only type that the C
//! API provides. The following example shows how a Rust embedder can initialize a C-compatible
//! context:
//!
//! ```no_run
//! use lucet_runtime::{DlModule, Limits, MmapRegion, Region};
//!
//! let module = DlModule::load("/my/lucet/module.so").unwrap();
//! let region = MmapRegion::create(1, &Limits::default()).unwrap();
//! #[repr(C)]
//! struct MyForeignContext { _unused: u8 };
//! let mut foreign_ctx = Box::into_raw(Box::new(MyForeignContext{ _unused: 0 }));
//! let mut inst = region
//!     .new_instance_builder(module)
//!     .with_embed_ctx(foreign_ctx as *mut libc::c_void)
//!     .build()
//!     .unwrap();
//!
//! inst.run(b"main", &[]).unwrap();
//!
//! // clean up embedder context
//! drop(inst);
//! // foreign_ctx must outlive inst, but then must be turned back into a box
//! // in order to drop.
//! unsafe { Box::from_raw(foreign_ctx) };
//! ```
//!
//! ## Custom Signal Handlers
//!
//! Since Lucet programs are run as native machine code, signals such as `SIGSEGV` and `SIGFPE` can
//! arise during execution. Rather than letting these signals bring down the entire process, the
//! Lucet runtime installs alternate signal handlers that limit the effects to just the instance
//! that raised the signal.
//!
//! By default, the signal handler sets the instance state to `State::Fault` and returns early from
//! the call to `Instance::run()`. You can, however, implement custom error recovery and logging
//! behavior by defining new signal handlers on a per-instance basis. For example, the following
//! signal handler increments a counter of signals it has seen before setting the fault state:
//!
//! ```no_run
//! use lucet_runtime::{
//!     DlModule, Error, Instance, Limits, MmapRegion, Region, SignalBehavior, TrapCode
//! };
//! use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
//!
//! static SIGNAL_COUNT: AtomicUsize = ATOMIC_USIZE_INIT;
//!
//! fn signal_handler_count(
//!     _inst: &Instance,
//!     _trapcode: &TrapCode,
//!     _signum: libc::c_int,
//!     _siginfo_ptr: *const libc::siginfo_t,
//!     _ucontext_ptr: *const libc::c_void,
//! ) -> SignalBehavior {
//!     SIGNAL_COUNT.fetch_add(1, Ordering::SeqCst);
//!     SignalBehavior::Default
//! }
//!
//! let module = DlModule::load("/my/lucet/module.so").unwrap();
//! let region = MmapRegion::create(1, &Limits::default()).unwrap();
//! let mut inst = region.new_instance(module).unwrap();
//!
//! // install the handler
//! inst.set_signal_handler(signal_handler_count);
//!
//! match inst.run(b"raise_a_signal", &[]) {
//!     Err(Error::RuntimeFault(_)) => {
//!         println!("I've now handled {} signals!", SIGNAL_COUNT.load(Ordering::SeqCst));
//!     }
//!     res => panic!("unexpected result: {:?}", res),
//! }
//! ```
//!
//! When implementing custom signal handlers for the Lucet runtime, the usual caveats about signal
//! safety apply: see
//! [`signal-safety(7)`](http://man7.org/linux/man-pages/man7/signal-safety.7.html).
//!
//! ## Interaction With Host Signal Handlers
//!
//! Great care must be taken if host application installs or otherwise modifies signal handlers
//! anywhere in the process. Lucet installs handlers for `SIGBUS`, `SIGFPE`, `SIGILL`, and `SIGSEGV`
//! when the first Lucet instance begins running, and restores the preëxisting handlers when the
//! last Lucet instance terminates. During this time, other threads in the host process *must not*
//! modify those signal handlers, since signal handlers can only be installed on a process-wide
//! basis.
//!
//! Despite this limitation, Lucet is designed to compose with other signal handlers in the host
//! program. If one of the above signals is caught by the Lucet signal handler, but that thread is
//! not currently running a Lucet instance, the saved host signal handler is called. This means
//! that, for example, a `SIGSEGV` on a non-Lucet thread of a host program will still likely abort
//! the entire process.

pub use lucet_runtime_internals::alloc::Limits;
pub use lucet_runtime_internals::error::Error;
pub use lucet_runtime_internals::instance::{
    FaultDetails, Instance, InstanceHandle, SignalBehavior, TerminationDetails,
};
pub use lucet_runtime_internals::module::{DlModule, Module};
pub use lucet_runtime_internals::region::mmap::MmapRegion;
pub use lucet_runtime_internals::region::{InstanceBuilder, Region};
pub use lucet_runtime_internals::trapcode::{TrapCode, TrapCodeType};
pub use lucet_runtime_internals::val::{UntypedRetVal, Val};
pub use lucet_runtime_internals::WASM_PAGE_SIZE;

pub mod vmctx {
    //! Functions for manipulating instances from hostcalls.
    //!
    //! The Lucet compiler inserts an extra `*mut lucet_vmctx` argument to all functions defined and
    //! called by WebAssembly code. Through this pointer, code running in the guest context can
    //! access and manipulate the instance and its structures. These functions are intended for use
    //! in hostcall implementations, and must only be used from within a running guest.
    //!
    //! # Panics
    //!
    //! All of the `Vmctx` methods will panic if the `Vmctx` was not created from a valid pointer
    //! associated with a running instance. This should never occur if run in guest code on the
    //! pointer argument inserted by the compiler.
    pub use lucet_runtime_internals::vmctx::{lucet_vmctx, Vmctx};
}

/// Call this if you're having trouble with `lucet_*` symbols not being exported.
///
/// This is pretty hackish; we will hopefully be able to avoid this altogether once [this
/// issue](https://github.com/rust-lang/rust/issues/58037) is addressed.
#[no_mangle]
pub extern "C" fn lucet_internal_ensure_linked() {
    lucet_runtime_internals::vmctx::vmctx_capi_init();
}
<|endoftext|>


<commit_before>extern crate test;

use std::old_io::fs::PathExtensions;
use std::os::getenv;
use std::old_io::File;
use self::test::Bencher;
use racer::codecleaner::code_chunks;
use racer::codeiter::iter_stmts;

fn get_rust_file_str(path: &[&str]) -> String {

    let mut src_path = match getenv("RUST_SRC_PATH") {
        Some(env) => { Path::new(&env[]) },
        None => panic!("Cannot find $RUST_SRC_PATH")
    };
    for &s in path.iter() { src_path.push(s); }

    File::open(&src_path).read_to_string().unwrap()
}

#[bench]
fn bench_code_chunks(b: &mut Bencher) {
    let src = &get_rust_file_str(&["libcollections", "bit.rs"])[];
    b.iter(|| {
        let chunks = code_chunks(src).collect::<Vec<_>>();
    });
}

#[bench]
fn bench_iter_stmts(b: &mut Bencher) {
    let src = &get_rust_file_str(&["libcollections", "bit.rs"])[];
    b.iter(|| {
        let chunks = iter_stmts(src).collect::<Vec<_>>();
    });
}

<commit_msg>Add mask_comment bench<commit_after>extern crate test;

use std::old_io::fs::PathExtensions;
use std::os::getenv;
use std::old_io::File;
use self::test::Bencher;
use racer::codecleaner::code_chunks;
use racer::codeiter::iter_stmts;
use racer::scopes::mask_comments;

fn get_rust_file_str(path: &[&str]) -> String {

    let mut src_path = match getenv("RUST_SRC_PATH") {
        Some(env) => { Path::new(&env[]) },
        None => panic!("Cannot find $RUST_SRC_PATH")
    };
    for &s in path.iter() { src_path.push(s); }

    File::open(&src_path).read_to_string().unwrap()
}

#[bench]
fn bench_code_chunks(b: &mut Bencher) {
    let src = &get_rust_file_str(&["libcollections", "bit.rs"])[];
    b.iter(|| {
        let chunks = code_chunks(src).collect::<Vec<_>>();
    });
}

#[bench]
fn bench_iter_stmts(b: &mut Bencher) {
    let src = &get_rust_file_str(&["libcollections", "bit.rs"])[];
    b.iter(|| {
        let chunks = iter_stmts(src).collect::<Vec<_>>();
    });
}

#[bench]
fn bench_mask_comments(b: &mut Bencher) {
    let src = &get_rust_file_str(&["libcollections", "bit.rs"])[];
    b.iter(|| {
        mask_comments(src);
    });
}

<|endoftext|>


<commit_before>use std::fs::File;
use std::io::Read;
use std::env;
use std::path::{Path,PathBuf};
use util::{path_exists, is_dir};
use std::fs::{read_dir};
use toml;

// otry is 'option try'
macro_rules! otry {
    ($e:expr) => (match $e { Some(e) => e, None => return None })
}

// converts errors into None
macro_rules! otry2 {
    ($e:expr) => (match $e { Ok(e) => e, Err(e) => { error!("ERROR!: {:?} {} {}", e, file!(), line!()); return None } })
}

fn find_src_via_lockfile(kratename: &str, cargofile: &Path) -> Option<PathBuf> {
    let mut file = otry2!(File::open(cargofile));
    let mut string = String::new();
    otry2!(file.read_to_string(&mut string));
    let mut parser = toml::Parser::new(&string);
    let lock_table = parser.parse().unwrap();

    debug!("find_src_via_lockfile found lock table {:?}", lock_table);

    let t = match lock_table.get("package") {
        Some(&toml::Value::Array(ref t1)) => t1,
        _ => return None
    };

    for item in t {
        if let &toml::Value::Table(ref t) = item {
            if let Some(&toml::Value::String(ref name)) = t.get("name") {
                if name.replace("-", "_") == kratename {
                    debug!("found matching crate {:?}", t);
                    let version = otry!(getstr(t, "version"));
                    let source = otry!(getstr(t, "source"));

                    if Some("registry") == source.split("+").nth(0) {
                        return get_versioned_cratefile(name, &version);
                    } else if Some("git") == source.split("+").nth(0) {
                        let sha1 = otry!(source.split("#").last());
                        let mut d = otry!(get_cargo_rootdir());
                        d.push("git");
                        d.push("checkouts");
                        d = otry!(find_git_src_dir(d, name, &sha1));
                        d.push("src");
                        d.push("lib.rs");
                        return Some(d);
                    }
                }
            }
        }
    }
    None
}

fn get_cargo_rootdir() -> Option<PathBuf> {
    let mut d = otry!(env::home_dir());

    // try multirust first, since people with multirust installed will often still
    // have an old .cargo directory lying around
    d.push(".multirust");
    d.push("default");
    if let Ok(mut multirustdefault) = File::open(&d) {
        let mut s = String::new();
        otry2!(multirustdefault.read_to_string(&mut s));
        d.pop();
        d.push("toolchains");
        d.push(s.trim());
        d.push("cargo");
        debug!("get_cargo_rootdir root is {:?}",d);
        return Some(d)
    }

    d.pop();
    d.pop();
    d.push(".cargo");
    if path_exists(&d) {
        Some(d)
    } else {
        None
    }
}

fn get_versioned_cratefile(kratename: &str, version: &str) -> Option<PathBuf> {
    let mut d = otry!(get_cargo_rootdir());
    d.push("registry");
    d.push("src");
    d = otry!(find_cratesio_src_dir(d));

    // if version=* then search for the first matching folder
    if version == "*" {
        use std::fs::read_dir;
        let mut start_path = d.clone();
        start_path.push(kratename);
        let start_name = start_path.to_str().unwrap();

        if let Ok(reader) = read_dir(d) {
            if let Some(path) = reader
                                .map(|entry| entry.unwrap().path())
                                .find(|path| path.to_str().unwrap().starts_with(start_name)) {
                d = path.clone();
            } else {
                return None;
            }
        } else { return None; }
    } else {
        d.push(kratename.to_string() + "-" + &version);
    }

    d.push("src");
    debug!("crate path {:?}",d);

    // First, check for package name at root (src/kratename/lib.rs)
    d.push(kratename.to_string());
    if let Err(_) = File::open(&d) {
        // It doesn't exist, so assume src/lib.rs
        d.pop();
    }
    d.push("lib.rs");
    if let Err(_) = File::open(&d) {
        return None;
    }

    Some(d)
 }

fn find_src_via_tomlfile(kratename: &str, cargofile: &Path) -> Option<PathBuf> {
    // only look for 'path' references here.
    // We find the git and crates.io stuff via the lockfile

    let mut file = otry2!(File::open(cargofile));
    let mut string = String::new();
    otry2!(file.read_to_string(&mut string));
    let mut parser = toml::Parser::new(&string);
    let table = otry!(parser.parse());
    let t = match table.get("dependencies") {
        Some(&toml::Value::Table(ref t)) => t,
        _ => return None
    };

    let mut name = kratename;
    let value = if kratename.contains('_') {
        t.iter().find(|&(k, _)| k.replace("-", "_") == name).map(|(k,v)| {
            name = k;
            v
        })
    } else {
        t.get(kratename)
    };

    match value {
        Some(&toml::Value::Table(ref t)) => {
            // local directory
            let relative_path = otry!(getstr(t, "path"));
            return Some(otry!(cargofile.parent())
                        .join(relative_path)
                        .join("src")
                        .join("lib.rs"));
        },
        Some(&toml::Value::String(ref version)) => {
            // versioned crate
            return get_versioned_cratefile(name, version);
        }
        _ => return None
    }
}

fn find_cratesio_src_dir(d: PathBuf) -> Option<PathBuf> {
    for entry in otry2!(read_dir(d)) {
        let path = otry2!(entry).path();
        if is_dir(path.as_path()) {
            if let Some(ref fname) = path.file_name().and_then(|s| s.to_str()) {
                if fname.starts_with("github.com-") {
                    return Some(path.clone());
                }
            }
        }
    }
    None
}

fn find_git_src_dir(d: PathBuf, name: &str, sha1: &str) -> Option<PathBuf> {
    for entry in otry2!(read_dir(d)) {
        let path = otry2!(entry).path();
        if is_dir(path.as_path()) {
            if let Some(ref fname) = path.file_name().and_then(|s| s.to_str()) {
                if fname.starts_with(name) {
                    let mut d = path.clone();

                    // dirname can be the sha1 or master.
                    d.push(sha1);

                    if !is_dir(d.as_path()) {
                        d.pop();
                        d.push("master");
                    }

                    let retval = d.clone();

                    // check that the checkout matches the commit sha1
                    d.push(".git");
                    d.push("refs");
                    d.push("heads");
                    d.push("master");

                    let mut headref = String::new();
                    otry2!(otry2!(File::open(d)).read_to_string(&mut headref));

                    debug!("git headref is {:?}", headref);

                    if headref.ends_with("\n") {
                        headref.pop();
                    }

                    if sha1 == headref {
                        return Some(retval);
                    }
                }
            }
        }
    }
    None
}

fn getstr(t: &toml::Table, k: &str) -> Option<String> {
    match t.get(k) {
        Some(&toml::Value::String(ref s)) => Some(s.clone()),
        _ => None
    }
}

fn find_cargo_tomlfile(currentfile: &Path) -> Option<PathBuf> {
    let mut f = currentfile.to_path_buf();
    f.push("Cargo.toml");
    if path_exists(f.as_path()) {
        return Some(f);
    } else {
        if f.pop() && f.pop() {
            return find_cargo_tomlfile(&f);
        } else {
            None
        }
    }
}

pub fn get_crate_file(kratename: &str, from_path: &Path) -> Option<PathBuf> {
    if let Some(tomlfile) = find_cargo_tomlfile(from_path) {
        // look in the lockfile first, if there is one
        debug!("get_crate_file tomlfile is {:?}", tomlfile);
        let mut lockfile = tomlfile.clone();
        lockfile.pop();
        lockfile.push("Cargo.lock");
        if path_exists(lockfile.as_path()) {
            if let Some(f) = find_src_via_lockfile(kratename, &lockfile) {
                return Some(f);
            }
        }

        // oh, no luck with the lockfile. Try the tomlfile
        return find_src_via_tomlfile(kratename, &tomlfile)
    }
    None
}
<commit_msg>[pd] Search 'lib' entry in Cargo.toml<commit_after>use std::fs::File;
use std::io::Read;
use std::env;
use std::path::{Path,PathBuf};
use util::{path_exists, is_dir};
use std::fs::{read_dir};
use toml;

// otry is 'option try'
macro_rules! otry {
    ($e:expr) => (match $e { Some(e) => e, None => return None })
}

// converts errors into None
macro_rules! otry2 {
    ($e:expr) => (match $e { Ok(e) => e, Err(e) => { error!("ERROR!: {:?} {} {}", e, file!(), line!()); return None } })
}

fn find_src_via_lockfile(kratename: &str, cargofile: &Path) -> Option<PathBuf> {
    let mut file = otry2!(File::open(cargofile));
    let mut string = String::new();
    otry2!(file.read_to_string(&mut string));
    let mut parser = toml::Parser::new(&string);
    let lock_table = parser.parse().unwrap();

    debug!("find_src_via_lockfile found lock table {:?}", lock_table);

    let t = match lock_table.get("package") {
        Some(&toml::Value::Array(ref t1)) => t1,
        _ => return None
    };

    for item in t {
        if let &toml::Value::Table(ref t) = item {
            if let Some(&toml::Value::String(ref name)) = t.get("name") {
                if name.replace("-", "_") == kratename {
                    debug!("found matching crate {:?}", t);
                    let version = otry!(getstr(t, "version"));
                    let source = otry!(getstr(t, "source"));

                    if Some("registry") == source.split("+").nth(0) {
                        return get_versioned_cratefile(name, &version);
                    } else if Some("git") == source.split("+").nth(0) {
                        let sha1 = otry!(source.split("#").last());
                        let mut d = otry!(get_cargo_rootdir());
                        d.push("git");
                        d.push("checkouts");
                        d = otry!(find_git_src_dir(d, name, &sha1));
                        d.push("src");
                        d.push("lib.rs");
                        return Some(d);
                    }
                }
            }
        }
    }
    None
}

fn get_cargo_rootdir() -> Option<PathBuf> {
    let mut d = otry!(env::home_dir());

    // try multirust first, since people with multirust installed will often still
    // have an old .cargo directory lying around
    d.push(".multirust");
    d.push("default");
    if let Ok(mut multirustdefault) = File::open(&d) {
        let mut s = String::new();
        otry2!(multirustdefault.read_to_string(&mut s));
        d.pop();
        d.push("toolchains");
        d.push(s.trim());
        d.push("cargo");
        debug!("get_cargo_rootdir root is {:?}",d);
        return Some(d)
    }

    d.pop();
    d.pop();
    d.push(".cargo");
    if path_exists(&d) {
        Some(d)
    } else {
        None
    }
}

fn get_versioned_cratefile(kratename: &str, version: &str) -> Option<PathBuf> {
    let mut d = otry!(get_cargo_rootdir());
    d.push("registry");
    d.push("src");
    d = otry!(find_cratesio_src_dir(d));

    // if version=* then search for the first matching folder
    if version == "*" {
        use std::fs::read_dir;
        let mut start_path = d.clone();
        start_path.push(kratename);
        let start_name = start_path.to_str().unwrap();

        if let Ok(reader) = read_dir(d) {
            if let Some(path) = reader
                                .map(|entry| entry.unwrap().path())
                                .find(|path| path.to_str().unwrap().starts_with(start_name)) {
                d = path.clone();
            } else {
                return None;
            }
        } else { return None; }
    } else {
        d.push(kratename.to_string() + "-" + &version);
    }

    d.push("src");
    debug!("crate path {:?}",d);

    // First, check for package name at root (src/kratename/lib.rs)
    d.push(kratename.to_string());
    if let Err(_) = File::open(&d) {
        // It doesn't exist, so assume src/lib.rs
        d.pop();
    }
    d.push("lib.rs");
    if let Err(_) = File::open(&d) {
        return None;
    }

    Some(d)
 }

fn find_src_via_tomlfile(kratename: &str, cargofile: &Path) -> Option<PathBuf> {
    // only look for 'path' references here.
    // We find the git and crates.io stuff via the lockfile

    let mut file = otry2!(File::open(cargofile));
    let mut string = String::new();
    otry2!(file.read_to_string(&mut string));
    let mut parser = toml::Parser::new(&string);
    let table = otry!(parser.parse());

    // is it this lib?  (e.g. you're searching from tests to find the main library crate)
    if let Some(&toml::Value::Table(ref t)) = table.get("lib") {
        if let Some(&toml::Value::String(ref name)) = t.get("name") {
            if name == kratename {
                debug!("found {} as lib entry in Cargo.toml", kratename);
                if let Some(&toml::Value::String(ref pathstr)) = t.get("path") {
                    let p = Path::new(pathstr);
                    let libpath = otry!(cargofile.parent()).join(p);
                    return Some(libpath);
                }
            }
        }
    }

    // otherwise search the dependencies
    let t = match table.get("dependencies") {
        Some(&toml::Value::Table(ref t)) => t,
        _ => return None
    };

    let mut name = kratename;
    let value = if kratename.contains('_') {
        t.iter().find(|&(k, _)| k.replace("-", "_") == name).map(|(k,v)| {
            name = k;
            v
        })
    } else {
        t.get(kratename)
    };

    match value {
        Some(&toml::Value::Table(ref t)) => {
            // local directory
            let relative_path = otry!(getstr(t, "path"));
            return Some(otry!(cargofile.parent())
                        .join(relative_path)
                        .join("src")
                        .join("lib.rs"));
        },
        Some(&toml::Value::String(ref version)) => {
            // versioned crate
            return get_versioned_cratefile(name, version);
        }
        _ => return None
    }
}

fn find_cratesio_src_dir(d: PathBuf) -> Option<PathBuf> {
    for entry in otry2!(read_dir(d)) {
        let path = otry2!(entry).path();
        if is_dir(path.as_path()) {
            if let Some(ref fname) = path.file_name().and_then(|s| s.to_str()) {
                if fname.starts_with("github.com-") {
                    return Some(path.clone());
                }
            }
        }
    }
    None
}

fn find_git_src_dir(d: PathBuf, name: &str, sha1: &str) -> Option<PathBuf> {
    for entry in otry2!(read_dir(d)) {
        let path = otry2!(entry).path();
        if is_dir(path.as_path()) {
            if let Some(ref fname) = path.file_name().and_then(|s| s.to_str()) {
                if fname.starts_with(name) {
                    let mut d = path.clone();

                    // dirname can be the sha1 or master.
                    d.push(sha1);

                    if !is_dir(d.as_path()) {
                        d.pop();
                        d.push("master");
                    }

                    let retval = d.clone();

                    // check that the checkout matches the commit sha1
                    d.push(".git");
                    d.push("refs");
                    d.push("heads");
                    d.push("master");

                    let mut headref = String::new();
                    otry2!(otry2!(File::open(d)).read_to_string(&mut headref));

                    debug!("git headref is {:?}", headref);

                    if headref.ends_with("\n") {
                        headref.pop();
                    }

                    if sha1 == headref {
                        return Some(retval);
                    }
                }
            }
        }
    }
    None
}

fn getstr(t: &toml::Table, k: &str) -> Option<String> {
    match t.get(k) {
        Some(&toml::Value::String(ref s)) => Some(s.clone()),
        _ => None
    }
}

fn find_cargo_tomlfile(currentfile: &Path) -> Option<PathBuf> {
    let mut f = currentfile.to_path_buf();
    f.push("Cargo.toml");
    if path_exists(f.as_path()) {
        return Some(f);
    } else {
        if f.pop() && f.pop() {
            return find_cargo_tomlfile(&f);
        } else {
            None
        }
    }
}

pub fn get_crate_file(kratename: &str, from_path: &Path) -> Option<PathBuf> {
    if let Some(tomlfile) = find_cargo_tomlfile(from_path) {
        // look in the lockfile first, if there is one
        debug!("get_crate_file tomlfile is {:?}", tomlfile);
        let mut lockfile = tomlfile.clone();
        lockfile.pop();
        lockfile.push("Cargo.lock");
        if path_exists(lockfile.as_path()) {
            if let Some(f) = find_src_via_lockfile(kratename, &lockfile) {
                return Some(f);
            }
        }

        // oh, no luck with the lockfile. Try the tomlfile
        return find_src_via_tomlfile(kratename, &tomlfile)
    }
    None
}
<|endoftext|>


<commit_before>//! Local side

use std::io::{self, ErrorKind};

use futures::{future::select_all, FutureExt};
use log::{debug, error, trace, warn};
use tokio::runtime::Handle;

use crate::{
    config::{Config, ConfigType},
    context::{Context, ServerState, SharedContext},
    plugin::{PluginMode, Plugins},
    relay::{tcprelay::local::run as run_tcp, udprelay::local::run as run_udp, utils::set_nofile},
};

#[cfg(target_os = "android")]
use crate::relay::dnsrelay::run as run_dns_relay;

/// Relay server running under local environment.
pub async fn run(mut config: Config, rt: Handle) -> io::Result<()> {
    trace!("initializing local server with {:?}", config);

    assert!(config.config_type.is_local());

    if let Some(nofile) = config.nofile {
        debug!("setting RLIMIT_NOFILE to {}", nofile);
        if let Err(err) = set_nofile(nofile) {
            match err.kind() {
                ErrorKind::PermissionDenied => {
                    warn!("insufficient permission to change RLIMIT_NOFILE, try to restart as root user");
                }
                ErrorKind::InvalidInput => {
                    warn!("invalid `nofile` value {}, decrease it and try again", nofile);
                }
                _ => {
                    error!("failed to set RLIMIT_NOFILE with value {}, error: {}", nofile, err);
                }
            }
            return Err(err);
        }
    }

    let config_type = config.config_type;
    let mode = config.mode;

    // Create a context containing a DNS resolver and server running state flag.
    let state = ServerState::new_shared(&config, rt).await;

    let mut vf = Vec::new();

    let enable_tcp = match config_type {
        // Socks5 always true, because UDP associate command also requires a TCP connection
        ConfigType::Socks5Local => true,
        // Tunnel mode controlled by this flag
        ConfigType::TunnelLocal => mode.enable_tcp(),
        // HTTP must be TCP
        ConfigType::HttpLocal => true,
        // Redir mode controlled by this flag
        ConfigType::RedirLocal => mode.enable_tcp(),

        _ => false,
    };

    let context = if enable_tcp {
        // Run TCP local server if
        //
        //  1. Enabled TCP relay
        //  2. Not in tunnel mode. (Socks5 UDP relay requires TCP port enabled)

        if config.has_server_plugins() {
            let plugins = Plugins::launch_plugins(&mut config, PluginMode::Client)?;

            // Wait until all plugins actually start
            // Some plugins require quite a lot bootstrap time
            Plugins::check_plugins_started(&config).await?;

            vf.push(plugins.into_future().boxed());
        }

        let context = Context::new_shared(config, state);

        let tcp_fut = run_tcp(context.clone());
        vf.push(tcp_fut.boxed());

        context
    } else {
        Context::new_shared(config, state)
    };

    let enable_udp = match config_type {
        ConfigType::Socks5Local | ConfigType::TunnelLocal | ConfigType::RedirLocal => mode.enable_udp(),
        _ => false,
    };

    if enable_udp {
        // Run UDP relay before starting plugins
        // Because plugins doesn't support UDP relay
        let udp_fut = run_udp(context.clone());
        vf.push(udp_fut.boxed());
    }

    #[cfg(target_os = "android")]
    {
        // For Android's local resolver
        let dns_relay = run_dns_relay(context.clone());
        vf.push(dns_relay.boxed());
    }

    if cfg!(target_os = "android") && context.config().stat_path.is_some() {
        // For Android's flow statistic

        let report_fut = flow_report_task(context.clone());
        vf.push(report_fut.boxed());
    }

    let (res, ..) = select_all(vf.into_iter()).await;
    error!("one of servers exited unexpectly, result: {:?}", res);

    // Tells all detached tasks to exit
    context.set_server_stopped();

    Err(io::Error::new(io::ErrorKind::Other, "server exited unexpectly"))
}

#[cfg(target_os = "android")]
async fn flow_report_task(context: SharedContext) -> io::Result<()> {
    use std::{slice, time::Duration};

    use tokio::{io::AsyncWriteExt, net::UnixStream, time};

    // Android's flow statistic report RPC
    let path = context.config().stat_path.as_ref().expect("stat_path must be provided");
    let timeout = Duration::from_secs(1);

    while context.server_running() {
        // keep it as libev's default, 0.5 seconds
        time::delay_for(Duration::from_millis(500)).await;
        let mut stream = match time::timeout(timeout, UnixStream::connect(path)).await {
            Ok(Ok(s)) => s,
            Ok(Err(err)) => {
                error!("send client flow statistic error: {}", err);
                continue;
            }
            Err(..) => {
                error!("send client flow statistic error: timeout");
                continue;
            }
        };

        let flow_stat = context.local_flow_statistic();
        let tx = flow_stat.tcp().tx() + flow_stat.udp().tx();
        let rx = flow_stat.tcp().rx() + flow_stat.udp().rx();

        let buf: [u64; 2] = [tx, rx];
        let buf = unsafe { slice::from_raw_parts(buf.as_ptr() as *const _, 16) };

        match time::timeout(timeout, stream.write_all(buf)).await {
            Ok(Ok(..)) => {}
            Ok(Err(err)) => {
                error!("send client flow statistic error: {}", err);
            }
            Err(..) => {
                error!("send client flow statistic error: timeout");
            }
        }
    }
    Ok(())
}

#[cfg(not(target_os = "android"))]
async fn flow_report_task(_context: SharedContext) -> io::Result<()> {
    unimplemented!("only for android")
}
<commit_msg>Fix tx/rx order for android RPC<commit_after>//! Local side

use std::io::{self, ErrorKind};

use futures::{future::select_all, FutureExt};
use log::{debug, error, trace, warn};
use tokio::runtime::Handle;

use crate::{
    config::{Config, ConfigType},
    context::{Context, ServerState, SharedContext},
    plugin::{PluginMode, Plugins},
    relay::{tcprelay::local::run as run_tcp, udprelay::local::run as run_udp, utils::set_nofile},
};

#[cfg(target_os = "android")]
use crate::relay::dnsrelay::run as run_dns_relay;

/// Relay server running under local environment.
pub async fn run(mut config: Config, rt: Handle) -> io::Result<()> {
    trace!("initializing local server with {:?}", config);

    assert!(config.config_type.is_local());

    if let Some(nofile) = config.nofile {
        debug!("setting RLIMIT_NOFILE to {}", nofile);
        if let Err(err) = set_nofile(nofile) {
            match err.kind() {
                ErrorKind::PermissionDenied => {
                    warn!("insufficient permission to change RLIMIT_NOFILE, try to restart as root user");
                }
                ErrorKind::InvalidInput => {
                    warn!("invalid `nofile` value {}, decrease it and try again", nofile);
                }
                _ => {
                    error!("failed to set RLIMIT_NOFILE with value {}, error: {}", nofile, err);
                }
            }
            return Err(err);
        }
    }

    let config_type = config.config_type;
    let mode = config.mode;

    // Create a context containing a DNS resolver and server running state flag.
    let state = ServerState::new_shared(&config, rt).await;

    let mut vf = Vec::new();

    let enable_tcp = match config_type {
        // Socks5 always true, because UDP associate command also requires a TCP connection
        ConfigType::Socks5Local => true,
        // Tunnel mode controlled by this flag
        ConfigType::TunnelLocal => mode.enable_tcp(),
        // HTTP must be TCP
        ConfigType::HttpLocal => true,
        // Redir mode controlled by this flag
        ConfigType::RedirLocal => mode.enable_tcp(),

        _ => false,
    };

    let context = if enable_tcp {
        // Run TCP local server if
        //
        //  1. Enabled TCP relay
        //  2. Not in tunnel mode. (Socks5 UDP relay requires TCP port enabled)

        if config.has_server_plugins() {
            let plugins = Plugins::launch_plugins(&mut config, PluginMode::Client)?;

            // Wait until all plugins actually start
            // Some plugins require quite a lot bootstrap time
            Plugins::check_plugins_started(&config).await?;

            vf.push(plugins.into_future().boxed());
        }

        let context = Context::new_shared(config, state);

        let tcp_fut = run_tcp(context.clone());
        vf.push(tcp_fut.boxed());

        context
    } else {
        Context::new_shared(config, state)
    };

    let enable_udp = match config_type {
        ConfigType::Socks5Local | ConfigType::TunnelLocal | ConfigType::RedirLocal => mode.enable_udp(),
        _ => false,
    };

    if enable_udp {
        // Run UDP relay before starting plugins
        // Because plugins doesn't support UDP relay
        let udp_fut = run_udp(context.clone());
        vf.push(udp_fut.boxed());
    }

    #[cfg(target_os = "android")]
    {
        // For Android's local resolver
        let dns_relay = run_dns_relay(context.clone());
        vf.push(dns_relay.boxed());
    }

    if cfg!(target_os = "android") && context.config().stat_path.is_some() {
        // For Android's flow statistic

        let report_fut = flow_report_task(context.clone());
        vf.push(report_fut.boxed());
    }

    let (res, ..) = select_all(vf.into_iter()).await;
    error!("one of servers exited unexpectly, result: {:?}", res);

    // Tells all detached tasks to exit
    context.set_server_stopped();

    Err(io::Error::new(io::ErrorKind::Other, "server exited unexpectly"))
}

#[cfg(target_os = "android")]
async fn flow_report_task(context: SharedContext) -> io::Result<()> {
    use std::{slice, time::Duration};

    use tokio::{io::AsyncWriteExt, net::UnixStream, time};

    // Android's flow statistic report RPC
    let path = context.config().stat_path.as_ref().expect("stat_path must be provided");
    let timeout = Duration::from_secs(1);

    while context.server_running() {
        // keep it as libev's default, 0.5 seconds
        time::delay_for(Duration::from_millis(500)).await;
        let mut stream = match time::timeout(timeout, UnixStream::connect(path)).await {
            Ok(Ok(s)) => s,
            Ok(Err(err)) => {
                error!("send client flow statistic error: {}", err);
                continue;
            }
            Err(..) => {
                error!("send client flow statistic error: timeout");
                continue;
            }
        };

        let flow_stat = context.local_flow_statistic();
        let tx = flow_stat.tcp().tx() + flow_stat.udp().tx();
        let rx = flow_stat.tcp().rx() + flow_stat.udp().rx();

        // first is rx, second is tx.
        let buf: [u64; 2] = [rx, tx];
        let buf = unsafe { slice::from_raw_parts(buf.as_ptr() as *const _, 16) };

        match time::timeout(timeout, stream.write_all(buf)).await {
            Ok(Ok(..)) => {}
            Ok(Err(err)) => {
                error!("send client flow statistic error: {}", err);
            }
            Err(..) => {
                error!("send client flow statistic error: timeout");
            }
        }
    }
    Ok(())
}

#[cfg(not(target_os = "android"))]
async fn flow_report_task(_context: SharedContext) -> io::Result<()> {
    unimplemented!("only for android")
}
<|endoftext|>


<commit_before>use Decimal;
use num::FromPrimitive;
use serde;
use std::fmt;
use std::str::FromStr;
use serde::de::Unexpected;
use num::Zero;

impl<'de> serde::Deserialize<'de> for Decimal {
    fn deserialize<D>(deserializer: D) -> Result<Decimal, D::Error>
    where
        D: serde::de::Deserializer<'de>, {
        deserializer.deserialize_any(DecimalVisitor)
    }
}

struct DecimalVisitor;

impl<'de> serde::de::Visitor<'de> for DecimalVisitor {
    type Value = Decimal;

    fn visit_f64<E>(self, value: f64) -> Result<Decimal, E> {
        match Decimal::from_str(&value.to_string()) {
            Ok(s) => Ok(s),
            Err(_) => Ok(Decimal::zero()),
        }
    }

    fn visit_i64<E>(self, value: i64) -> Result<Decimal, E>
        where E: serde::de::Error
    {
        match Decimal::from_i64(value) {
            Some(s) => Ok(s),
            None => Err(E::invalid_value(Unexpected::Signed(value), &self)),
        }
    }

    fn visit_u64<E>(self, value: u64) -> Result<Decimal, E>
        where E: serde::de::Error
    {
        match Decimal::from_u64(value) {
            Some(s) => Ok(s),
            None => Err(E::invalid_value(Unexpected::Unsigned(value), &self)),
        }
    }

    fn visit_str<E>(self, value: &str) -> Result<Decimal, E>
        where E: serde::de::Error
    {
        Decimal::from_str(value).map_err(|_| E::invalid_value(Unexpected::Str(value), &self))
    }

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(
            formatter,
            "a Decimal type representing a fixed-point number"
        )
    }
}

impl serde::Serialize for Decimal {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer, {
        serializer.serialize_str(&self.to_string())
    }
}

#[cfg(test)]
mod test {
    extern crate serde_json;

    use super::*;

    #[derive(Serialize, Deserialize, Debug)]
    struct Record {
        amount: Decimal
    }

    #[test]
    fn deserialize_valid_decimal() {
        let data = [
            ("{\"amount\":\"1.234\"}", "1.234"),
            ("{\"amount\":1234}", "1234"),
        ];
        for &(serialized,value) in data.iter() {
            let record : Record = serde_json::from_str(serialized).unwrap();
            assert_eq!(value, record.amount.to_string());
        }
    }

    #[test]
    #[should_panic]
    fn deserialize_invalid_decimal() {
        let serialized = "{\"amount\":\"foo\"}";
        let _ : Record = serde_json::from_str(serialized).unwrap();
    }

    #[test]
    fn serialize_decimal() {
        let record = Record { amount: Decimal::new(1234, 3) };
        let serialized = serde_json::to_string(&record).unwrap();
        assert_eq!("{\"amount\":\"1.234\"}", serialized);
    }
}
<commit_msg>Unify error handling<commit_after>use Decimal;
use num::FromPrimitive;
use serde;
use std::fmt;
use std::str::FromStr;
use serde::de::Unexpected;
use num::Zero;

impl<'de> serde::Deserialize<'de> for Decimal {
    fn deserialize<D>(deserializer: D) -> Result<Decimal, D::Error>
    where
        D: serde::de::Deserializer<'de>, {
        deserializer.deserialize_any(DecimalVisitor)
    }
}

struct DecimalVisitor;

impl<'de> serde::de::Visitor<'de> for DecimalVisitor {
    type Value = Decimal;

    fn visit_f64<E>(self, value: f64) -> Result<Decimal, E>
        where E: serde::de::Error
    {
        Decimal::from_str(&value.to_string()).map_err(|_| E::invalid_value(Unexpected::Float(value), &self))
    }

    fn visit_i64<E>(self, value: i64) -> Result<Decimal, E>
        where E: serde::de::Error
    {
        match Decimal::from_i64(value) {
            Some(s) => Ok(s),
            None => Err(E::invalid_value(Unexpected::Signed(value), &self)),
        }
    }

    fn visit_u64<E>(self, value: u64) -> Result<Decimal, E>
        where E: serde::de::Error
    {
        match Decimal::from_u64(value) {
            Some(s) => Ok(s),
            None => Err(E::invalid_value(Unexpected::Unsigned(value), &self)),
        }
    }

    fn visit_str<E>(self, value: &str) -> Result<Decimal, E>
        where E: serde::de::Error
    {
        Decimal::from_str(value).map_err(|_| E::invalid_value(Unexpected::Str(value), &self))
    }

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(
            formatter,
            "a Decimal type representing a fixed-point number"
        )
    }
}

impl serde::Serialize for Decimal {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer, {
        serializer.serialize_str(&self.to_string())
    }
}

#[cfg(test)]
mod test {
    extern crate serde_json;

    use super::*;

    #[derive(Serialize, Deserialize, Debug)]
    struct Record {
        amount: Decimal
    }

    #[test]
    fn deserialize_valid_decimal() {
        let data = [
            ("{\"amount\":\"1.234\"}", "1.234"),
            ("{\"amount\":1234}", "1234"),
        ];
        for &(serialized,value) in data.iter() {
            let record : Record = serde_json::from_str(serialized).unwrap();
            assert_eq!(value, record.amount.to_string());
        }
    }

    #[test]
    #[should_panic]
    fn deserialize_invalid_decimal() {
        let serialized = "{\"amount\":\"foo\"}";
        let _ : Record = serde_json::from_str(serialized).unwrap();
    }

    #[test]
    fn serialize_decimal() {
        let record = Record { amount: Decimal::new(1234, 3) };
        let serialized = serde_json::to_string(&record).unwrap();
        assert_eq!("{\"amount\":\"1.234\"}", serialized);
    }
}
<|endoftext|>