<commit_before>use super::paging::{Page, PageRange};
use core::ops;

/// A borrowed handle on a frame with a specified lifetime.
///
/// This automatically deallocates the frame when the borrow's lifetime
/// ends. It also ensures that the borrow only lives as long as the allocator
/// that provided it, and that the borrow is dropped if the allocator is
/// dropped.
pub struct BorrowedFrame<'a, F, A>
where F: Page
    , A: FrameAllocator<F>
    , A: 'a {
    frame: F
  , allocator: &'a A
}

impl<'a, F, A> ops::Deref for BorrowedFrame<'a, F, A>
where F: Page
    , A: 'a {
    type Target = F;
    fn deref(&self) -> &F { &self.frame }
}

impl<'a, F, A> ops::DerefMut for BorrowedFrame<'a, F, A>
where F: Page
    , A: 'a {
    fn deref_mut(&mut self) -> &mut F { &mut self.frame }
}

impl<'a, F, A> Drop for BorrowedFrame<'a, F, A>
where F: Page
    , A: FrameAllocator<F>
    , A: 'a {
    fn drop(&mut self) {
        unsafe { self.allocator.deallocate(self.frame) }
    }
}

/// Identical to a `BorrowedFrame` but borrowing a range of `Frame`s.
pub struct BorrowedFrameRange<'a, F, A>
where F: Page
    , A: FrameAllocator<F>
    , A: 'a {
    range: PageRange<F>
  , allocator: &'a A
}

impl<'a, F, A> ops::Deref for BorrowedFrame<'a, F, A>
where F: Page
    , A: 'a {
    type Target = PageRange<F>;
    fn deref(&self) -> &Self::Target { &self.range }
}

impl<'a, F, A> ops::DerefMut for BorrowedFrame<'a, F, A>
where F: Page
    , A: 'a {
    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.range }
}

impl<'a, F, A> Drop for BorrowedFrame<'a, F, A>
where F: Page
    , A: FrameAllocator<F>
    , A: 'a {
    fn drop(&mut self) {
        unsafe { self.allocator.deallocate_range(self.range) }
    }
}

pub trait FrameAllocator<Frame>
where Frame: Page {

    unsafe fn allocate(&self) -> Option<Frame>;
    unsafe fn deallocate(&self, frame: Frame);
    fn borrow(&self) -> Option<BorrowedFrame<Frame, Self>>;

    unsafe fn allocate_range(&self, num: usize) -> Option<PageRange<Frame>>;
    unsafe fn deallocate_range(&self, range: PageRange<Frame>);
    fn borrow_range(&self, num: usize)
                    -> Option<BorrowedFrameRange<Frame, Self>>;

}

/// An `Allocator` implements a particular memory allocation strategy.
pub trait Allocator {

    /// Allocate a new block of size `size` on alignment `align`.
    ///
    /// # Arguments:
    ///   - `size`: the amount of memory to allocate (in bytes)
    ///   - `align`: the alignment for the allocation request
    ///
    /// # Returns:
    ///   - `Some(*mut u8)` if the request was allocated successfully
    ///   - `None` if the allocator is out of memory or if the request was
    ///     invalid.
    unsafe fn allocate( &mut self
                      , size: usize
                      , align: usize)
                      -> Option<*mut u8>;

    /// Release an allocated block of memory.
    ///
    /// The `size` and `align` parameters _must_ be the same as the original
    /// size and alignment of the frame being deallocated, otherwise our
    /// heap will become corrupted.
    ///
    /// # Arguments:
    ///   - `frame`: a pointer to the block of memory to deallocate
    ///   - `size`: the size of the block being deallocated
    ///   - `align`: the alignment of the block being deallocated
    unsafe fn deallocate( &mut self
                        , frame: *mut u8
                        , size: usize, align: usize);

    /// Reallocate `old_frame` from `old_size` bytes to `new_size` bytes
    ///
    /// The `old_size` and `align` parameters _must_ be the same as the
    /// original size and alignment of the frame being reallocated, otherwise
    /// our heap will become corrupted.
    ///
    /// # Arguments:
    ///   - `old_frame`: a pointer to the frame to be reallocated
    ///   - `old_size`: the size (in bytes) of the frame being reallocated
    ///   - `new_size`: the size to reallocate the frame to.
    ///   - `align`: the alignment for the allocation request
    ///
    /// # Returns:
    ///   - `Some(*mut u8)` if the frame was reallocated successfully
    ///   - `None` if the allocator is out of memory or if the request was
    ///     invalid.
    // TODO: Optimization: check if the reallocation request fits in
    // the old frame and return immediately if it does
    unsafe fn reallocate( &mut self
                        , old_frame: *mut u8
                        , old_size: usize
                        , new_size: usize
                        , align: usize )
                        -> Option<*mut u8> {
        // First, attempt to allocate a new frame...
        self.allocate(new_size, align)
            .map(|new_frame| {
                // If a new frame was allocated, copy all the data from the
                // old frame into the new frame.
                ptr::copy(new_frame, old_frame, min(old_size, new_size));
                // Then we can deallocate the old frame
                self.deallocate(old_frame, old_size, align);
                new_frame
            })
    }

    unsafe fn zero_alloc( &mut self
                        , _size: usize
                        , _align: usize)
                        -> Option<*mut u8> {
        unimplemented!()
    }
}
<commit_msg>[kernel] start implementing smart allocator API<commit_after>use super::paging::{Page, PageRange};
use core::ops;

/// A borrowed handle on a frame with a specified lifetime.
///
/// This automatically deallocates the frame when the borrow's lifetime
/// ends. It also ensures that the borrow only lives as long as the allocator
/// that provided it, and that the borrow is dropped if the allocator is
/// dropped.
pub struct BorrowedFrame<'a, F, A>
where F: Page
    , A: FrameAllocator<F>
    , A: 'a {
    frame: F
  , allocator: &'a A
}

impl<'a, F, A> ops::Deref for BorrowedFrame<'a, F, A>
where F: Page
    , A: 'a {
    type Target = F;
    fn deref(&self) -> &F { &self.frame }
}

impl<'a, F, A> ops::DerefMut for BorrowedFrame<'a, F, A>
where F: Page
    , A: 'a {
    fn deref_mut(&mut self) -> &mut F { &mut self.frame }
}

impl<'a, F, A> Drop for BorrowedFrame<'a, F, A>
where F: Page
    , A: FrameAllocator<F>
    , A: 'a {
    fn drop(&mut self) {
        unsafe { self.allocator.deallocate(self.frame) }
    }
}

/// Identical to a `BorrowedFrame` but borrowing a range of `Frame`s.
pub struct BorrowedFrameRange<'a, F, A>
where F: Page
    , A: FrameAllocator<F>
    , A: 'a {
    range: PageRange<F>
  , allocator: &'a A
}

impl<'a, F, A> ops::Deref for BorrowedFrame<'a, F, A>
where F: Page
    , A: 'a {
    type Target = PageRange<F>;
    fn deref(&self) -> &Self::Target { &self.range }
}

impl<'a, F, A> ops::DerefMut for BorrowedFrame<'a, F, A>
where F: Page
    , A: 'a {
    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.range }
}

impl<'a, F, A> Drop for BorrowedFrame<'a, F, A>
where F: Page
    , A: FrameAllocator<F>
    , A: 'a {
    fn drop(&mut self) {
        unsafe { self.allocator.deallocate_range(self.range) }
    }
}

pub trait FrameAllocator<Frame>
where Frame: Page {

    unsafe fn allocate(&self) -> Option<Frame>;
    unsafe fn deallocate(&self, frame: Frame);

    /// Borrow a `Frame` from this allocator.
    ///
    /// The `BorrowedFrame` will live as long as this allocator, and will
    /// contain a handle on a `Frame` that will be automatically deallocated
    /// when the `BorrowedFrame` is dropped.
    ///
    /// # Returns:
    /// + `Some(BorrowedFrame)` if there are frames remaining in this
    ///    allocator.
    /// + `None` if the allocator is out of frames.
    fn borrow(&self) -> Option<BorrowedFrame<Frame, Self>> {
        self.allocate()
            .map(|frame| BorrowedFrame { frame: frame, allocator: self })
    }

    unsafe fn allocate_range(&self, num: usize) -> Option<PageRange<Frame>>;
    unsafe fn deallocate_range(&self, range: PageRange<Frame>);

    /// Borrow a `FrameRange` from this allocator.
    ///
    /// The `BorrowedFrameRange` will live as long as this allocator, and will
    /// contain a handle on a range of `Frame`s that will be automatically
    /// deallocated when the `BorrowedFrameRange` is dropped.
    ///
    /// # Arguments:
    /// + `num`: The number of frames to allocate.
    ///
    /// # Returns:
    /// + `Some(BorrowedFrameRange)` if there are enough `Frame`s
    ///    remaining in the allocator to fulfill the allocation
    ///    request.
    /// + `None` if there are not enough frames in the allocator to fulfill the
    ///   allocation request.
    fn borrow_range(&self, num: usize)
                    -> Option<BorrowedFrameRange<Frame, Self>> {
        self.allocate_range(num)
            .map(|range| BorrowedFrameRange { range: range
                                            , allocator: self })
    }

}

/// An `Allocator` implements a particular memory allocation strategy.
pub trait Allocator {

    /// Allocate a new block of size `size` on alignment `align`.
    ///
    /// # Arguments:
    ///   - `size`: the amount of memory to allocate (in bytes)
    ///   - `align`: the alignment for the allocation request
    ///
    /// # Returns:
    ///   - `Some(*mut u8)` if the request was allocated successfully
    ///   - `None` if the allocator is out of memory or if the request was
    ///     invalid.
    unsafe fn allocate( &mut self
                      , size: usize
                      , align: usize)
                      -> Option<*mut u8>;

    /// Release an allocated block of memory.
    ///
    /// The `size` and `align` parameters _must_ be the same as the original
    /// size and alignment of the frame being deallocated, otherwise our
    /// heap will become corrupted.
    ///
    /// # Arguments:
    ///   - `frame`: a pointer to the block of memory to deallocate
    ///   - `size`: the size of the block being deallocated
    ///   - `align`: the alignment of the block being deallocated
    unsafe fn deallocate( &mut self
                        , frame: *mut u8
                        , size: usize, align: usize);

    /// Reallocate `old_frame` from `old_size` bytes to `new_size` bytes
    ///
    /// The `old_size` and `align` parameters _must_ be the same as the
    /// original size and alignment of the frame being reallocated, otherwise
    /// our heap will become corrupted.
    ///
    /// # Arguments:
    ///   - `old_frame`: a pointer to the frame to be reallocated
    ///   - `old_size`: the size (in bytes) of the frame being reallocated
    ///   - `new_size`: the size to reallocate the frame to.
    ///   - `align`: the alignment for the allocation request
    ///
    /// # Returns:
    ///   - `Some(*mut u8)` if the frame was reallocated successfully
    ///   - `None` if the allocator is out of memory or if the request was
    ///     invalid.
    // TODO: Optimization: check if the reallocation request fits in
    // the old frame and return immediately if it does
    unsafe fn reallocate( &mut self
                        , old_frame: *mut u8
                        , old_size: usize
                        , new_size: usize
                        , align: usize )
                        -> Option<*mut u8> {
        // First, attempt to allocate a new frame...
        self.allocate(new_size, align)
            .map(|new_frame| {
                // If a new frame was allocated, copy all the data from the
                // old frame into the new frame.
                ptr::copy(new_frame, old_frame, min(old_size, new_size));
                // Then we can deallocate the old frame
                self.deallocate(old_frame, old_size, align);
                new_frame
            })
    }

    unsafe fn zero_alloc( &mut self
                        , _size: usize
                        , _align: usize)
                        -> Option<*mut u8> {
        unimplemented!()
    }
}
<|endoftext|>


<commit_before>use parser::{Cond, Expr, Node, Target, WS};
use std::str;
use std::collections::HashSet;
use syn;
use quote::{Tokens, ToTokens};

fn path_as_identifier(s: &str) -> String {
    let mut res = String::new();
    for c in s.chars() {
        if c.is_alphanumeric() {
            res.push(c);
        } else {
            res.push_str(&format!("{:x}", c as u32));
        }
    }
    res
}

struct Generator<'a> {
    buf: String,
    indent: u8,
    start: bool,
    locals: HashSet<String>,
    next_ws: Option<&'a str>,
    skip_ws: bool,
}

impl<'a> Generator<'a> {

    fn new() -> Generator<'a> {
        Generator {
            buf: String::new(),
            indent: 0,
            start: true,
            locals: HashSet::new(),
            next_ws: None,
            skip_ws: false,
        }
    }

    fn indent(&mut self) {
        self.indent += 1;
    }

    fn dedent(&mut self) {
        self.indent -= 1;
    }

    fn write(&mut self, s: &str) {
        if self.start {
            for _ in 0..(self.indent * 4) {
                self.buf.push(' ');
            }
            self.start = false;
        }
        self.buf.push_str(s);
    }

    fn writeln(&mut self, s: &str) {
        if s.is_empty() {
            return;
        }
        if s == "}" {
            self.dedent();
        }
        self.write(s);
        if s.ends_with('{') {
            self.indent();
        }
        self.buf.push('\n');
        self.start = true;
    }

    fn flush_ws(&mut self, ws: &WS) {
        if self.next_ws.is_some() && !ws.0 {
            let val = self.next_ws.unwrap();
            if !val.is_empty() {
                self.writeln(&format!("writer.write_str({:#?}).unwrap();",
                                      val));
            }
        }
        self.next_ws = None;
    }

    fn prepare_ws(&mut self, ws: &WS) {
        self.skip_ws = ws.1;
    }

    fn handle_ws(&mut self, ws: &WS) {
        self.flush_ws(ws);
        self.prepare_ws(ws);
    }

    fn visit_num_lit(&mut self, s: &str) {
        self.write(s);
    }

    fn visit_str_lit(&mut self, s: &str) {
        self.write(&format!("\"{}\"", s));
    }

    fn visit_var(&mut self, s: &str) {
        if self.locals.contains(s) {
            self.write(s);
        } else {
            self.write(&format!("self.{}", s));
        }
    }

    fn visit_attr(&mut self, obj: &Expr, attr: &str) {
        if let Expr::Var(name) = *obj {
            if name == "loop" {
                self.write("_loop_index");
                if attr == "index" {
                    self.write(" + 1");
                    return;
                } else if attr == "index0" {
                    return;
                } else {
                    panic!("unknown loop variable");
                }
            }
        }
        self.visit_expr(obj);
        self.write(&format!(".{}", attr));
    }

    fn visit_filter(&mut self, name: &str, args: &[Expr]) {
        if name == "format" {
            self.write("format!(");
        } else {
            self.write(&format!("askama::filters::{}(&", name));
        }

        for (i, arg) in args.iter().enumerate() {
            if i > 0 {
                self.write(", &");
            }
            self.visit_expr(arg);
        }
        self.write(")");
    }

    fn visit_binop(&mut self, op: &str, left: &Expr, right: &Expr) {
        self.visit_expr(left);
        self.write(&format!(" {} ", op));
        self.visit_expr(right);
    }

    fn visit_group(&mut self, inner: &Expr) {
        self.write("(");
        self.visit_expr(inner);
        self.write(")");
    }

    fn visit_call(&mut self, obj: &Expr, method: &str, args: &[Expr]) {
        self.visit_expr(obj);
        self.write(&format!(".{}(", method));
        for (i, arg) in args.iter().enumerate() {
            if i > 0 {
                self.write(", ");
            }
            self.visit_expr(arg);
        }
        self.write(")");
    }

    fn visit_expr(&mut self, expr: &Expr) {
        match *expr {
            Expr::NumLit(s) => self.visit_num_lit(s),
            Expr::StrLit(s) => self.visit_str_lit(s),
            Expr::Var(s) => self.visit_var(s),
            Expr::Attr(ref obj, name) => self.visit_attr(obj, name),
            Expr::Filter(name, ref args) => self.visit_filter(name, args),
            Expr::BinOp(op, ref left, ref right) =>
                self.visit_binop(op, left, right),
            Expr::Group(ref inner) => self.visit_group(inner),
            Expr::Call(ref obj, method, ref args) =>
                self.visit_call(obj, method, args),
        }
    }

    fn visit_target_single(&mut self, name: &str) -> Vec<String> {
        vec![name.to_string()]
    }

    fn visit_target(&mut self, target: &Target) -> Vec<String> {
        match *target {
            Target::Name(s) => { self.visit_target_single(s) },
        }
    }

    fn write_lit(&mut self, lws: &'a str, val: &str, rws: &'a str) {
        assert!(self.next_ws.is_none());
        if !lws.is_empty() {
            if self.skip_ws {
                self.skip_ws = false;
            } else if val.is_empty() {
                assert!(rws.is_empty());
                self.next_ws = Some(lws);
            } else {
                self.writeln(&format!("writer.write_str({:#?}).unwrap();",
                                      lws));
            }
        }
        if !val.is_empty() {
            self.writeln(&format!("writer.write_str({:#?}).unwrap();", val));
        }
        if !rws.is_empty() {
            self.next_ws = Some(rws);
        }
    }

    fn write_expr(&mut self, ws: &WS, s: &Expr) {
        self.handle_ws(ws);
        self.write("writer.write_fmt(format_args!(\"{}\", ");
        self.visit_expr(s);
        self.writeln(")).unwrap();");
    }

    fn write_cond(&mut self, conds: &'a [Cond], ws: &WS) {
        for (i, &(ref cws, ref cond, ref nodes)) in conds.iter().enumerate() {
            self.handle_ws(cws);
            match *cond {
                Some(ref expr) => {
                    if i == 0 {
                        self.write("if ");
                    } else {
                        self.dedent();
                        self.write("} else if ");
                    }
                    self.visit_expr(expr);
                },
                None => {
                    self.dedent();
                    self.write("} else");
                },
            }
            self.writeln(" {");
            self.handle(nodes);
        }
        self.handle_ws(ws);
        self.writeln("}");
    }

    fn write_loop(&mut self, ws1: &WS, var: &Target, iter: &Expr,
                  body: &'a [Node], ws2: &WS) {
        self.handle_ws(ws1);
        self.write("for (_loop_index, ");
        let targets = self.visit_target(var);
        for name in &targets {
            self.locals.insert(name.clone());
            self.write(name);
        }
        self.write(") in (&");
        self.visit_expr(iter);
        self.writeln(").into_iter().enumerate() {");

        self.handle(body);
        self.handle_ws(ws2);
        self.writeln("}");
        for name in &targets {
            self.locals.remove(name);
        }
    }

    fn write_block(&mut self, ws1: &WS, name: &str, ws2: &WS) {
        self.flush_ws(ws1);
        self.writeln(&format!("timpl.render_block_{}_to(writer);", name));
        self.prepare_ws(ws2);
    }

    fn write_block_def(&mut self, ws1: &WS, name: &str, nodes: &'a [Node],
                       ws2: &WS) {
        self.writeln("#[allow(unused_variables)]");
        self.writeln(&format!(
            "fn render_block_{}_to(&self, writer: &mut std::fmt::Write) {{",
            name));
        self.prepare_ws(ws1);
        self.handle(nodes);
        self.flush_ws(ws2);
        self.writeln("}");
    }

    fn handle(&mut self, nodes: &'a [Node]) {
        for n in nodes {
            match *n {
                Node::Lit(lws, val, rws) => { self.write_lit(lws, val, rws); }
                Node::Comment() => {},
                Node::Expr(ref ws, ref val) => { self.write_expr(ws, val); },
                Node::Cond(ref conds, ref ws) => {
                    self.write_cond(conds, ws);
                },
                Node::Loop(ref ws1, ref var, ref iter, ref body, ref ws2) => {
                    self.write_loop(ws1, var, iter, body, ws2);
                },
                Node::Block(ref ws1, name, ref ws2) => {
                    self.write_block(ws1, name, ws2);
                },
                Node::BlockDef(ref ws1, name, ref block_nodes, ref ws2) => {
                    self.write_block_def(ws1, name, block_nodes, ws2);
                }
                Node::Extends(_) => {
                    panic!("no extends or block definition allowed in content");
                },
            }
        }
    }

    fn write_header(&mut self, ast: &syn::DeriveInput,
                    trait_suffix: Option<&str>) {
        let mut full_anno = Tokens::new();
        let mut orig_anno = Tokens::new();
        let need_anno = ast.generics.lifetimes.len() > 0 ||
                        ast.generics.ty_params.len() > 0;
        if need_anno {
            full_anno.append("<");
            orig_anno.append("<");
        }

        let mut sep = false;
        for lt in &ast.generics.lifetimes {
            if sep {
                full_anno.append(",");
                orig_anno.append(",");
            }
            lt.to_tokens(&mut full_anno);
            lt.to_tokens(&mut orig_anno);
            sep = true;
        }

        for param in &ast.generics.ty_params {
            if sep {
                full_anno.append(",");
                orig_anno.append(",");
            }
            param.to_tokens(&mut full_anno);
            param.ident.to_tokens(&mut orig_anno);
            sep = true;
        }

        if need_anno {
            full_anno.append(">");
            orig_anno.append(">");
        }

        let mut where_clause = Tokens::new();
        ast.generics.where_clause.to_tokens(&mut where_clause);
        let name = if trait_suffix.is_some() {
            format!("TraitFrom{}", trait_suffix.unwrap())
        } else {
            "askama::Template".to_string()
        };
        self.writeln(&format!("impl{} {} for {}{}{} {{",
                              full_anno.as_str(), &name, ast.ident.as_ref(),
                              orig_anno.as_str(), where_clause.as_str()));
    }

    fn impl_template(&mut self, ast: &syn::DeriveInput, nodes: &'a [Node]) {
        self.write_header(ast, None);
        self.writeln("fn render_to(&self, writer: &mut std::fmt::Write) {");
        self.handle(nodes);
        self.flush_ws(&WS(false, false));
        self.writeln("}");
        self.writeln("}");
    }

    fn impl_trait(&mut self, ast: &syn::DeriveInput, base: &str,
                  blocks: &'a [Node], nodes: Option<&'a [Node]>) {
        self.write_header(ast, Some(&path_as_identifier(base)));
        self.handle(blocks);

        self.writeln("#[allow(unused_variables)]");
        let trait_name = format!("TraitFrom{}", path_as_identifier(base));
        self.writeln(&format!(
            "fn render_trait_to(&self, timpl: &{}, writer: &mut std::fmt::Write) {{",
            trait_name));

        if let Some(nodes) = nodes {
            self.handle(nodes);
            self.flush_ws(&WS(false, false));
        } else {
            self.writeln("self._parent.render_trait_to(self, writer);");
        }

        self.writeln("}");
        self.flush_ws(&WS(false, false));
        self.writeln("}");
    }

    fn impl_template_for_trait(&mut self, ast: &syn::DeriveInput, derived: bool) {
        self.write_header(ast, None);
        self.writeln("fn render_to(&self, writer: &mut std::fmt::Write) {");
        if derived {
            self.writeln("self._parent.render_trait_to(self, writer);");
        } else {
            self.writeln("self.render_trait_to(self, writer);");
        }
        self.writeln("}");
        self.writeln("}");
    }

    fn define_trait(&mut self, path: &str, block_names: &[&str]) {
        let trait_name = format!("TraitFrom{}", path_as_identifier(path));
        self.writeln(&format!("trait {} {{", &trait_name));

        for bname in block_names {
            self.writeln(&format!(
                "fn render_block_{}_to(&self, writer: &mut std::fmt::Write);",
                bname));
        }
        self.writeln(&format!(
            "fn render_trait_to(&self, timpl: &{}, writer: &mut std::fmt::Write);",
            trait_name));

        self.writeln("}");
    }

    fn result(self) -> String {
        self.buf
    }

}

pub fn generate(ast: &syn::DeriveInput, path: &str, mut nodes: Vec<Node>) -> String {
    let mut base: Option<Expr> = None;
    let mut blocks = Vec::new();
    let mut block_names = Vec::new();
    let mut content = Vec::new();
    for n in nodes.drain(..) {
        match n {
            Node::Extends(path) => {
                match base {
                    Some(_) => panic!("multiple extend blocks found"),
                    None => { base = Some(path); },
                }
            },
            Node::BlockDef(ws1, name, _, ws2) => {
                blocks.push(n);
                block_names.push(name);
                content.push(Node::Block(ws1, name, ws2));
            },
            _ => { content.push(n); },
        }
    }

    let mut gen = Generator::new();
    if !blocks.is_empty() {
        if base.is_none() {
            gen.define_trait(path, &block_names);
        }
        let tmpl_path = match base {
            Some(Expr::StrLit(base_path)) => { base_path },
            _ => { path },
        };
        let trait_nodes = if base.is_none() { Some(&content[..]) } else { None };
        gen.impl_trait(ast, tmpl_path, &blocks, trait_nodes);
        gen.impl_template_for_trait(ast, base.is_some());
    } else {
        gen.impl_template(ast, &content);
    }
    gen.result()
}
<commit_msg>Use if let to better handle Option type<commit_after>use parser::{Cond, Expr, Node, Target, WS};
use std::str;
use std::collections::HashSet;
use syn;
use quote::{Tokens, ToTokens};

fn path_as_identifier(s: &str) -> String {
    let mut res = String::new();
    for c in s.chars() {
        if c.is_alphanumeric() {
            res.push(c);
        } else {
            res.push_str(&format!("{:x}", c as u32));
        }
    }
    res
}

struct Generator<'a> {
    buf: String,
    indent: u8,
    start: bool,
    locals: HashSet<String>,
    next_ws: Option<&'a str>,
    skip_ws: bool,
}

impl<'a> Generator<'a> {

    fn new() -> Generator<'a> {
        Generator {
            buf: String::new(),
            indent: 0,
            start: true,
            locals: HashSet::new(),
            next_ws: None,
            skip_ws: false,
        }
    }

    fn indent(&mut self) {
        self.indent += 1;
    }

    fn dedent(&mut self) {
        self.indent -= 1;
    }

    fn write(&mut self, s: &str) {
        if self.start {
            for _ in 0..(self.indent * 4) {
                self.buf.push(' ');
            }
            self.start = false;
        }
        self.buf.push_str(s);
    }

    fn writeln(&mut self, s: &str) {
        if s.is_empty() {
            return;
        }
        if s == "}" {
            self.dedent();
        }
        self.write(s);
        if s.ends_with('{') {
            self.indent();
        }
        self.buf.push('\n');
        self.start = true;
    }

    fn flush_ws(&mut self, ws: &WS) {
        if self.next_ws.is_some() && !ws.0 {
            let val = self.next_ws.unwrap();
            if !val.is_empty() {
                self.writeln(&format!("writer.write_str({:#?}).unwrap();",
                                      val));
            }
        }
        self.next_ws = None;
    }

    fn prepare_ws(&mut self, ws: &WS) {
        self.skip_ws = ws.1;
    }

    fn handle_ws(&mut self, ws: &WS) {
        self.flush_ws(ws);
        self.prepare_ws(ws);
    }

    fn visit_num_lit(&mut self, s: &str) {
        self.write(s);
    }

    fn visit_str_lit(&mut self, s: &str) {
        self.write(&format!("\"{}\"", s));
    }

    fn visit_var(&mut self, s: &str) {
        if self.locals.contains(s) {
            self.write(s);
        } else {
            self.write(&format!("self.{}", s));
        }
    }

    fn visit_attr(&mut self, obj: &Expr, attr: &str) {
        if let Expr::Var(name) = *obj {
            if name == "loop" {
                self.write("_loop_index");
                if attr == "index" {
                    self.write(" + 1");
                    return;
                } else if attr == "index0" {
                    return;
                } else {
                    panic!("unknown loop variable");
                }
            }
        }
        self.visit_expr(obj);
        self.write(&format!(".{}", attr));
    }

    fn visit_filter(&mut self, name: &str, args: &[Expr]) {
        if name == "format" {
            self.write("format!(");
        } else {
            self.write(&format!("askama::filters::{}(&", name));
        }

        for (i, arg) in args.iter().enumerate() {
            if i > 0 {
                self.write(", &");
            }
            self.visit_expr(arg);
        }
        self.write(")");
    }

    fn visit_binop(&mut self, op: &str, left: &Expr, right: &Expr) {
        self.visit_expr(left);
        self.write(&format!(" {} ", op));
        self.visit_expr(right);
    }

    fn visit_group(&mut self, inner: &Expr) {
        self.write("(");
        self.visit_expr(inner);
        self.write(")");
    }

    fn visit_call(&mut self, obj: &Expr, method: &str, args: &[Expr]) {
        self.visit_expr(obj);
        self.write(&format!(".{}(", method));
        for (i, arg) in args.iter().enumerate() {
            if i > 0 {
                self.write(", ");
            }
            self.visit_expr(arg);
        }
        self.write(")");
    }

    fn visit_expr(&mut self, expr: &Expr) {
        match *expr {
            Expr::NumLit(s) => self.visit_num_lit(s),
            Expr::StrLit(s) => self.visit_str_lit(s),
            Expr::Var(s) => self.visit_var(s),
            Expr::Attr(ref obj, name) => self.visit_attr(obj, name),
            Expr::Filter(name, ref args) => self.visit_filter(name, args),
            Expr::BinOp(op, ref left, ref right) =>
                self.visit_binop(op, left, right),
            Expr::Group(ref inner) => self.visit_group(inner),
            Expr::Call(ref obj, method, ref args) =>
                self.visit_call(obj, method, args),
        }
    }

    fn visit_target_single(&mut self, name: &str) -> Vec<String> {
        vec![name.to_string()]
    }

    fn visit_target(&mut self, target: &Target) -> Vec<String> {
        match *target {
            Target::Name(s) => { self.visit_target_single(s) },
        }
    }

    fn write_lit(&mut self, lws: &'a str, val: &str, rws: &'a str) {
        assert!(self.next_ws.is_none());
        if !lws.is_empty() {
            if self.skip_ws {
                self.skip_ws = false;
            } else if val.is_empty() {
                assert!(rws.is_empty());
                self.next_ws = Some(lws);
            } else {
                self.writeln(&format!("writer.write_str({:#?}).unwrap();",
                                      lws));
            }
        }
        if !val.is_empty() {
            self.writeln(&format!("writer.write_str({:#?}).unwrap();", val));
        }
        if !rws.is_empty() {
            self.next_ws = Some(rws);
        }
    }

    fn write_expr(&mut self, ws: &WS, s: &Expr) {
        self.handle_ws(ws);
        self.write("writer.write_fmt(format_args!(\"{}\", ");
        self.visit_expr(s);
        self.writeln(")).unwrap();");
    }

    fn write_cond(&mut self, conds: &'a [Cond], ws: &WS) {
        for (i, &(ref cws, ref cond, ref nodes)) in conds.iter().enumerate() {
            self.handle_ws(cws);
            match *cond {
                Some(ref expr) => {
                    if i == 0 {
                        self.write("if ");
                    } else {
                        self.dedent();
                        self.write("} else if ");
                    }
                    self.visit_expr(expr);
                },
                None => {
                    self.dedent();
                    self.write("} else");
                },
            }
            self.writeln(" {");
            self.handle(nodes);
        }
        self.handle_ws(ws);
        self.writeln("}");
    }

    fn write_loop(&mut self, ws1: &WS, var: &Target, iter: &Expr,
                  body: &'a [Node], ws2: &WS) {
        self.handle_ws(ws1);
        self.write("for (_loop_index, ");
        let targets = self.visit_target(var);
        for name in &targets {
            self.locals.insert(name.clone());
            self.write(name);
        }
        self.write(") in (&");
        self.visit_expr(iter);
        self.writeln(").into_iter().enumerate() {");

        self.handle(body);
        self.handle_ws(ws2);
        self.writeln("}");
        for name in &targets {
            self.locals.remove(name);
        }
    }

    fn write_block(&mut self, ws1: &WS, name: &str, ws2: &WS) {
        self.flush_ws(ws1);
        self.writeln(&format!("timpl.render_block_{}_to(writer);", name));
        self.prepare_ws(ws2);
    }

    fn write_block_def(&mut self, ws1: &WS, name: &str, nodes: &'a [Node],
                       ws2: &WS) {
        self.writeln("#[allow(unused_variables)]");
        self.writeln(&format!(
            "fn render_block_{}_to(&self, writer: &mut std::fmt::Write) {{",
            name));
        self.prepare_ws(ws1);
        self.handle(nodes);
        self.flush_ws(ws2);
        self.writeln("}");
    }

    fn handle(&mut self, nodes: &'a [Node]) {
        for n in nodes {
            match *n {
                Node::Lit(lws, val, rws) => { self.write_lit(lws, val, rws); }
                Node::Comment() => {},
                Node::Expr(ref ws, ref val) => { self.write_expr(ws, val); },
                Node::Cond(ref conds, ref ws) => {
                    self.write_cond(conds, ws);
                },
                Node::Loop(ref ws1, ref var, ref iter, ref body, ref ws2) => {
                    self.write_loop(ws1, var, iter, body, ws2);
                },
                Node::Block(ref ws1, name, ref ws2) => {
                    self.write_block(ws1, name, ws2);
                },
                Node::BlockDef(ref ws1, name, ref block_nodes, ref ws2) => {
                    self.write_block_def(ws1, name, block_nodes, ws2);
                }
                Node::Extends(_) => {
                    panic!("no extends or block definition allowed in content");
                },
            }
        }
    }

    fn write_header(&mut self, ast: &syn::DeriveInput,
                    trait_suffix: Option<&str>) {
        let mut full_anno = Tokens::new();
        let mut orig_anno = Tokens::new();
        let need_anno = ast.generics.lifetimes.len() > 0 ||
                        ast.generics.ty_params.len() > 0;
        if need_anno {
            full_anno.append("<");
            orig_anno.append("<");
        }

        let mut sep = false;
        for lt in &ast.generics.lifetimes {
            if sep {
                full_anno.append(",");
                orig_anno.append(",");
            }
            lt.to_tokens(&mut full_anno);
            lt.to_tokens(&mut orig_anno);
            sep = true;
        }

        for param in &ast.generics.ty_params {
            if sep {
                full_anno.append(",");
                orig_anno.append(",");
            }
            param.to_tokens(&mut full_anno);
            param.ident.to_tokens(&mut orig_anno);
            sep = true;
        }

        if need_anno {
            full_anno.append(">");
            orig_anno.append(">");
        }

        let mut where_clause = Tokens::new();
        ast.generics.where_clause.to_tokens(&mut where_clause);
        let name = if let Some(suffix) = trait_suffix {
            format!("TraitFrom{}", suffix)
        } else {
            "askama::Template".to_string()
        };
        self.writeln(&format!("impl{} {} for {}{}{} {{",
                              full_anno.as_str(), &name, ast.ident.as_ref(),
                              orig_anno.as_str(), where_clause.as_str()));
    }

    fn impl_template(&mut self, ast: &syn::DeriveInput, nodes: &'a [Node]) {
        self.write_header(ast, None);
        self.writeln("fn render_to(&self, writer: &mut std::fmt::Write) {");
        self.handle(nodes);
        self.flush_ws(&WS(false, false));
        self.writeln("}");
        self.writeln("}");
    }

    fn impl_trait(&mut self, ast: &syn::DeriveInput, base: &str,
                  blocks: &'a [Node], nodes: Option<&'a [Node]>) {
        self.write_header(ast, Some(&path_as_identifier(base)));
        self.handle(blocks);

        self.writeln("#[allow(unused_variables)]");
        let trait_name = format!("TraitFrom{}", path_as_identifier(base));
        self.writeln(&format!(
            "fn render_trait_to(&self, timpl: &{}, writer: &mut std::fmt::Write) {{",
            trait_name));

        if let Some(nodes) = nodes {
            self.handle(nodes);
            self.flush_ws(&WS(false, false));
        } else {
            self.writeln("self._parent.render_trait_to(self, writer);");
        }

        self.writeln("}");
        self.flush_ws(&WS(false, false));
        self.writeln("}");
    }

    fn impl_template_for_trait(&mut self, ast: &syn::DeriveInput, derived: bool) {
        self.write_header(ast, None);
        self.writeln("fn render_to(&self, writer: &mut std::fmt::Write) {");
        if derived {
            self.writeln("self._parent.render_trait_to(self, writer);");
        } else {
            self.writeln("self.render_trait_to(self, writer);");
        }
        self.writeln("}");
        self.writeln("}");
    }

    fn define_trait(&mut self, path: &str, block_names: &[&str]) {
        let trait_name = format!("TraitFrom{}", path_as_identifier(path));
        self.writeln(&format!("trait {} {{", &trait_name));

        for bname in block_names {
            self.writeln(&format!(
                "fn render_block_{}_to(&self, writer: &mut std::fmt::Write);",
                bname));
        }
        self.writeln(&format!(
            "fn render_trait_to(&self, timpl: &{}, writer: &mut std::fmt::Write);",
            trait_name));

        self.writeln("}");
    }

    fn result(self) -> String {
        self.buf
    }

}

pub fn generate(ast: &syn::DeriveInput, path: &str, mut nodes: Vec<Node>) -> String {
    let mut base: Option<Expr> = None;
    let mut blocks = Vec::new();
    let mut block_names = Vec::new();
    let mut content = Vec::new();
    for n in nodes.drain(..) {
        match n {
            Node::Extends(path) => {
                match base {
                    Some(_) => panic!("multiple extend blocks found"),
                    None => { base = Some(path); },
                }
            },
            Node::BlockDef(ws1, name, _, ws2) => {
                blocks.push(n);
                block_names.push(name);
                content.push(Node::Block(ws1, name, ws2));
            },
            _ => { content.push(n); },
        }
    }

    let mut gen = Generator::new();
    if !blocks.is_empty() {
        if base.is_none() {
            gen.define_trait(path, &block_names);
        }
        let tmpl_path = match base {
            Some(Expr::StrLit(base_path)) => { base_path },
            _ => { path },
        };
        let trait_nodes = if base.is_none() { Some(&content[..]) } else { None };
        gen.impl_trait(ast, tmpl_path, &blocks, trait_nodes);
        gen.impl_template_for_trait(ast, base.is_some());
    } else {
        gen.impl_template(ast, &content);
    }
    gen.result()
}
<|endoftext|>


<commit_before>use hyper::Url;
use hyper::header::{Authorization, Bearer, ContentType};
use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value};
use rustc_serialize::json;
use std::fs::File;
use std::path::PathBuf;
use std::result::Result;

use access_token::AccessToken;
use config::OtaConfig;
use error::Error;
use error::OtaReason::{CreateFile, Client};
use http_client::{HttpClient, HttpRequest};
use package::Package;
use update_request::UpdateRequestId;

fn vehicle_endpoint(config: &OtaConfig, s: &str) -> Url {
    config.server.join(&format!("/api/v1/vehicles/{}{}", config.vin, s)).unwrap()
}

pub fn download_package_update<C: HttpClient>(token:  &AccessToken,
                                              config: &OtaConfig,
                                              id:     &UpdateRequestId) -> Result<PathBuf, Error> {

    let req = HttpRequest::get(vehicle_endpoint(config, &format!("/updates/{}/download", id)))
        .with_header(Authorization(Bearer { token: token.access_token.clone() }));

    let mut path = PathBuf::new();
    path.push(&config.packages_dir);
    path.push(id);
    path.set_extension("deb");

    let file = try!(File::create(path.as_path())
                    .map_err(|e| Error::Ota(CreateFile(path.clone(), e))));

    try!(C::new().send_request_to(&req, file)
         .map_err(|e| Error::Ota(Client(req.to_string(), format!("{}", e)))));

    return Ok(path)
}

pub fn get_package_updates<C: HttpClient>(token:  &AccessToken,
                                          config: &OtaConfig) -> Result<Vec<UpdateRequestId>, Error> {

    let req = HttpRequest::get(vehicle_endpoint(&config, "/updates"))
        .with_header(Authorization(Bearer { token: token.access_token.clone() }));

    let body = try!(C::new().send_request(&req)
                    .map_err(|e| Error::ClientError(format!("Can't consult package updates: {}", e))));

    json::decode::<Vec<UpdateRequestId>>(&body)
        .map_err(|e| Error::ParseError(format!("Cannot parse response: {}. Got: {}", e, &body)))
}

pub fn post_packages<C: HttpClient>(token:  &AccessToken,
                                    config: &OtaConfig,
                                    pkgs:   &Vec<Package>) -> Result<(), Error> {

    let json = try!(json::encode(&pkgs)
                    .map_err(|_| Error::ParseError(String::from("JSON encoding error"))));

    let req = HttpRequest::post(vehicle_endpoint(config, "/updates"))
        .with_header(Authorization(Bearer { token: token.access_token.clone() }))
        .with_header(ContentType(Mime(
            TopLevel::Application,
            SubLevel::Json,
            vec![(Attr::Charset, Value::Utf8)])))
        .with_body(&json);

    let _: String = try!(C::new().send_request(&req));

    return Ok(())
}

#[cfg(test)]
mod tests {

    use std::io::Write;

    use super::*;
    use access_token::AccessToken;
    use bad_http_client::BadHttpClient;
    use config::OtaConfig;
    use error::Error;
    use http_client::{HttpRequest, HttpClient};
    use package::Package;

    fn test_token() -> AccessToken {
        AccessToken {
            access_token: "token".to_string(),
            token_type: "bar".to_string(),
            expires_in: 20,
            scope: vec![]
        }
    }

    fn test_package() -> Package {
        Package {
            name: "hey".to_string(),
            version: "1.2.3".to_string()
        }
    }

    struct MockClient;

    impl HttpClient for MockClient {

        fn new() -> MockClient {
            MockClient
        }

        fn send_request(&self, _: &HttpRequest) -> Result<String, Error> {
            return Ok("[\"pkgid\"]".to_string())
        }

        fn send_request_to<W: Write>(&self, _: &HttpRequest, _: W) -> Result<(), Error> {
            return Ok(())
        }

    }

    #[test]
    fn test_post_packages_sends_authentication() {
        assert_eq!(
            post_packages::<MockClient>(&test_token(), &OtaConfig::default(), &vec![test_package()])
                .unwrap(), ())
    }

    #[test]
    fn test_get_package_updates() {
        assert_eq!(get_package_updates::<MockClient>(&test_token(), &OtaConfig::default()).unwrap(),
                   vec!["pkgid".to_string()])
    }

    #[test]
    fn bad_packages_dir_download_package_update() {

        let mut config = OtaConfig::default();
        config = OtaConfig { packages_dir: "/".to_string(), .. config };

        assert_eq!(
            format!("{}",
                    download_package_update::<MockClient>(&test_token(), &config, &"0".to_string())
                    .unwrap_err()),
            r#"Ota error, failed to create file "/0.deb": Permission denied (os error 13)"#)
    }

    #[test]
    fn bad_client_download_package_update() {
        assert_eq!(
            format!("{}",
                    download_package_update::<BadHttpClient>
                    (&test_token(), &OtaConfig::default(), &"0".to_string())
                    .unwrap_err()),
            r#"Ota error, the request: GET http://127.0.0.1:8080/api/v1/vehicles/V1234567890123456/updates/0,
results in the following error: bad client."#)
    }

}
<commit_msg>Fix test.<commit_after>use hyper::Url;
use hyper::header::{Authorization, Bearer, ContentType};
use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value};
use rustc_serialize::json;
use std::fs::File;
use std::path::PathBuf;
use std::result::Result;

use access_token::AccessToken;
use config::OtaConfig;
use error::Error;
use error::OtaReason::{CreateFile, Client};
use http_client::{HttpClient, HttpRequest};
use package::Package;
use update_request::UpdateRequestId;

fn vehicle_endpoint(config: &OtaConfig, s: &str) -> Url {
    config.server.join(&format!("/api/v1/vehicles/{}{}", config.vin, s)).unwrap()
}

pub fn download_package_update<C: HttpClient>(token:  &AccessToken,
                                              config: &OtaConfig,
                                              id:     &UpdateRequestId) -> Result<PathBuf, Error> {

    let req = HttpRequest::get(vehicle_endpoint(config, &format!("/updates/{}/download", id)))
        .with_header(Authorization(Bearer { token: token.access_token.clone() }));

    let mut path = PathBuf::new();
    path.push(&config.packages_dir);
    path.push(id);
    path.set_extension("deb");

    let file = try!(File::create(path.as_path())
                    .map_err(|e| Error::Ota(CreateFile(path.clone(), e))));

    try!(C::new().send_request_to(&req, file)
         .map_err(|e| Error::Ota(Client(req.to_string(), format!("{}", e)))));

    return Ok(path)
}

pub fn get_package_updates<C: HttpClient>(token:  &AccessToken,
                                          config: &OtaConfig) -> Result<Vec<UpdateRequestId>, Error> {

    let req = HttpRequest::get(vehicle_endpoint(&config, "/updates"))
        .with_header(Authorization(Bearer { token: token.access_token.clone() }));

    let body = try!(C::new().send_request(&req)
                    .map_err(|e| Error::ClientError(format!("Can't consult package updates: {}", e))));

    json::decode::<Vec<UpdateRequestId>>(&body)
        .map_err(|e| Error::ParseError(format!("Cannot parse response: {}. Got: {}", e, &body)))
}

pub fn post_packages<C: HttpClient>(token:  &AccessToken,
                                    config: &OtaConfig,
                                    pkgs:   &Vec<Package>) -> Result<(), Error> {

    let json = try!(json::encode(&pkgs)
                    .map_err(|_| Error::ParseError(String::from("JSON encoding error"))));

    let req = HttpRequest::post(vehicle_endpoint(config, "/updates"))
        .with_header(Authorization(Bearer { token: token.access_token.clone() }))
        .with_header(ContentType(Mime(
            TopLevel::Application,
            SubLevel::Json,
            vec![(Attr::Charset, Value::Utf8)])))
        .with_body(&json);

    let _: String = try!(C::new().send_request(&req));

    return Ok(())
}

#[cfg(test)]
mod tests {

    use std::io::Write;

    use super::*;
    use access_token::AccessToken;
    use bad_http_client::BadHttpClient;
    use config::OtaConfig;
    use error::Error;
    use http_client::{HttpRequest, HttpClient};
    use package::Package;

    fn test_token() -> AccessToken {
        AccessToken {
            access_token: "token".to_string(),
            token_type: "bar".to_string(),
            expires_in: 20,
            scope: vec![]
        }
    }

    fn test_package() -> Package {
        Package {
            name: "hey".to_string(),
            version: "1.2.3".to_string()
        }
    }

    struct MockClient;

    impl HttpClient for MockClient {

        fn new() -> MockClient {
            MockClient
        }

        fn send_request(&self, _: &HttpRequest) -> Result<String, Error> {
            return Ok("[\"pkgid\"]".to_string())
        }

        fn send_request_to<W: Write>(&self, _: &HttpRequest, _: W) -> Result<(), Error> {
            return Ok(())
        }

    }

    #[test]
    fn test_post_packages_sends_authentication() {
        assert_eq!(
            post_packages::<MockClient>(&test_token(), &OtaConfig::default(), &vec![test_package()])
                .unwrap(), ())
    }

    #[test]
    fn test_get_package_updates() {
        assert_eq!(get_package_updates::<MockClient>(&test_token(), &OtaConfig::default()).unwrap(),
                   vec!["pkgid".to_string()])
    }

    #[test]
    fn bad_packages_dir_download_package_update() {

        let mut config = OtaConfig::default();
        config = OtaConfig { packages_dir: "/".to_string(), .. config };

        assert_eq!(
            format!("{}",
                    download_package_update::<MockClient>(&test_token(), &config, &"0".to_string())
                    .unwrap_err()),
            r#"Ota error, failed to create file "/0.deb": Permission denied (os error 13)"#)
    }

    #[test]
    fn bad_client_download_package_update() {
        assert_eq!(
            format!("{}",
                    download_package_update::<BadHttpClient>
                    (&test_token(), &OtaConfig::default(), &"0".to_string())
                    .unwrap_err()),
            r#"Ota error, the request: GET http://127.0.0.1:8080/api/v1/vehicles/V1234567890123456/updates/0/download,
results in the following error: bad client."#)
    }

}
<|endoftext|>


<commit_before>use std::io::{Read, Write};
use std::mem::size_of;
use std::net::{
    TcpStream,
    ToSocketAddrs
};

use byteorder::{ReadBytesExt, BigEndian, WriteBytesExt};
use conhash::Node;
use num::FromPrimitive;

use errors::BMemcachedError;

enum Type {
    Request = 0x80,
    Response = 0x81
}

#[derive(Debug)]
enum Command {
    Get = 0x00,
    Set = 0x01,
    Add = 0x02,
    Replace = 0x03,
    Delete = 0x04,
    Increment = 0x05,
    Decrement = 0x06,
    Quit = 0x07,
    Flush = 0x08,
    GetQ = 0x09,
    NoOp = 0x0A,
    Version = 0x0B,
    GetK = 0x0C,
    GetKQ = 0x0D,
    Append = 0x0E,
    Prepend = 0x0F,
    Stat = 0x10,
    SetQ = 0x11,
    AddQ = 0x12,
    ReplaceQ = 0x13,
    DeleteQ = 0x14,
    IncrementQ = 0x15,
    DecrementQ = 0x16,
    QuitQ = 0x17,
    FlushQ = 0x18,
    AppendQ = 0x19,
    PrependQ = 0x1A
}

enum_from_primitive! {
    #[derive(Debug, PartialEq)]
    pub enum Status {
        Success = 0x00,
        KeyNotFound = 0x01,
        KeyExists = 0x02,
        AuthError = 0x08,
        UnknownCommand = 0x81
    }
}

#[derive(Debug)]
pub struct Request {
    magic: u8,
    opcode: u8,
    key_length: u16,
    extras_length: u8,
    data_type: u8,
    reserved: u16,
    body_length: u32,
    opaque: u32,
    cas: u64
}

#[derive(Debug)]
pub struct Response {
    magic: u8,
    opcode: u8,
    key_length: u16,
    extras_length: u8,
    data_type: u8,
    status: u16,
    body_length: u32,
    opaque: u32,
    cas: u64
}

pub struct SetAddReplace {
    flags: u32,
    expiration: u32
}

#[derive(Debug)]
pub struct Protocol {
    connection: TcpStream
}

impl Protocol {
    pub fn connect<A: ToSocketAddrs>(addr: A) -> Result<Protocol, BMemcachedError> {
        Ok(Protocol{connection: try!(TcpStream::connect(addr))})
    }

    pub fn connection_info(&self) -> String {
        format!("{:?}", self.connection.peer_addr().unwrap())
    }

    fn build_request(command: Command, key_length: usize, value_length: usize, data_type: u8,
        extras_length: usize, cas: u64) -> Request {
        Request {
            magic: Type::Request as u8, opcode: command as u8,
            key_length: key_length as u16,
            extras_length: extras_length as u8,
            data_type: data_type, reserved: 0,
            body_length: (key_length + value_length + extras_length) as u32,
            opaque: 0, cas: cas
        }
    }

    fn write_request(&self, request: Request, final_payload: &[u8]) -> Result<(), BMemcachedError> {
        let mut buf = &self.connection;
        try!(buf.write_u8(request.magic));
        try!(buf.write_u8(request.opcode));
        try!(buf.write_u16::<BigEndian>(request.key_length));
        try!(buf.write_u8(request.extras_length));
        try!(buf.write_u8(request.data_type));
        try!(buf.write_u16::<BigEndian>(request.reserved));
        try!(buf.write_u32::<BigEndian>(request.body_length));
        try!(buf.write_u32::<BigEndian>(request.opaque));
        try!(buf.write_u64::<BigEndian>(request.cas));
        try!(buf.write(final_payload));
        Ok(())
    }

    fn read_response(&mut self) -> Result<Response, BMemcachedError> {
        let mut buf = &self.connection;
        let magic: u8 = try!(buf.read_u8());
        if magic != Type::Response as u8 {
            // TODO Consume the stream, disconnect or something?
            return Err(BMemcachedError::UnkownError("Server sent an unknown magi code"))
        }
        Ok(Response {
            magic: magic,
            opcode: try!(buf.read_u8()),
            key_length: try!(buf.read_u16::<BigEndian>()),
            extras_length: try!(buf.read_u8()),
            data_type: try!(buf.read_u8()),
            status: try!(buf.read_u16::<BigEndian>()),
            body_length: try!(buf.read_u32::<BigEndian>()),
            opaque: try!(buf.read_u32::<BigEndian>()),
            cas: try!(buf.read_u64::<BigEndian>())
        })
    }

    fn set_add_replace<K, V>(&mut self, command: Command, key: K, value: V, time: u32) -> Result<(), BMemcachedError>
        where K: AsRef<[u8]>, V: AsRef<[u8]> {
        let key = key.as_ref();
        let value = value.as_ref();
        let extras_length = size_of::<SetAddReplace>();
        let request = Protocol::build_request(command, key.len(), value.len(), 0x00, extras_length, 0x00);
        let mut final_payload = vec![];
        // Flags
        try!(final_payload.write_u32::<BigEndian>(0));
        try!(final_payload.write_u32::<BigEndian>(time));
        // After flags key and value
        try!(final_payload.write(key));
        try!(final_payload.write(value));
        let size = try!(self.write_request(request, final_payload.as_slice()));
        let response = try!(self.read_response());
        match Status::from_u16(response.status) {
            Some(Status::Success) => Ok(()),
            Some(rest) => Err(BMemcachedError::Status(rest)),
            None => Err(BMemcachedError::UnkownError("Server returned an unknown status code"))
        }
    }

    pub fn set<K, V>(&mut self, key: K, value: V, time: u32) -> Result<(), BMemcachedError>
        where K: AsRef<[u8]>, V: AsRef<[u8]> {
        self.set_add_replace(Command::Set, key, value, time)
    }

    pub fn add<K, V>(&mut self, key: K, value: V, time: u32) -> Result<(), BMemcachedError>
        where K: AsRef<[u8]>, V: AsRef<[u8]> {
        self.set_add_replace(Command::Add, key, value, time)
    }

    pub fn replace<K, V>(&mut self, key: K, value: V, time: u32) -> Result<(), BMemcachedError>
        where K: AsRef<[u8]>, V: AsRef<[u8]> {
        self.set_add_replace(Command::Replace, key, value, time)
    }

    pub fn get<K>(&mut self, key: K) -> Result<String, BMemcachedError> where K: AsRef<[u8]> {
        let key = key.as_ref();
        let request = Protocol::build_request(Command::Get, key.len(), 0 as usize, 0, 0, 0x00);
        self.write_request(request, key);
        let response = try!(self.read_response());
        match Status::from_u16(response.status) {
            Some(Status::Success) => {},
            Some(status) => return Err(BMemcachedError::Status(status)),
            None => return Err(BMemcachedError::UnkownError("Server sent an unknown status code"))
        };
        // Discard extras for now
        try!(self.connection.read_u32::<BigEndian>());
        let mut outbuf = vec![0; (response.body_length - response.extras_length as u32) as usize];
        try!(self.connection.read_exact(&mut outbuf));
        Ok(try!(String::from_utf8(outbuf)))
    }
}

#[test]
fn test_set_key() {
    let mut p = Protocol::connect("127.0.0.1:11211").unwrap();
    let key = "Hello";
    let value = "World";
    p.set(key, value, 100).unwrap()
}

#[test]
fn test_add_key() {
    let mut p = Protocol::connect("127.0.0.1:11211").unwrap();
    let key = "Hello Add";
    let value = "World";
    p.add(key, value, 1).unwrap();
    let result = p.add(key, value, 10);
    match result {
        Ok(()) => panic!("Add key should return error"),
        Err(BMemcachedError::Status(Status::KeyExists)) => return,
        Err(_) => panic!("Some strange error that should not happen")
    }
}

#[test]
fn test_get_key() {
    let mut p = Protocol::connect("127.0.0.1:11211").unwrap();
    let key = "Hello";
    let value = "World";
    p.set(key, value, 100).unwrap();
    assert_eq!(p.get(key).unwrap(),  value);
    match p.get("not found".to_string()) {
        Ok(_) => panic!("This key should not exist"),
        Err(BMemcachedError::Status(Status::KeyNotFound)) => return,
        Err(_) => panic!("This should return KeyNotFound")
    }
}
<commit_msg>Increase add time on tests<commit_after>use std::io::{Read, Write};
use std::mem::size_of;
use std::net::{
    TcpStream,
    ToSocketAddrs
};

use byteorder::{ReadBytesExt, BigEndian, WriteBytesExt};
use conhash::Node;
use num::FromPrimitive;

use errors::BMemcachedError;

enum Type {
    Request = 0x80,
    Response = 0x81
}

#[derive(Debug)]
enum Command {
    Get = 0x00,
    Set = 0x01,
    Add = 0x02,
    Replace = 0x03,
    Delete = 0x04,
    Increment = 0x05,
    Decrement = 0x06,
    Quit = 0x07,
    Flush = 0x08,
    GetQ = 0x09,
    NoOp = 0x0A,
    Version = 0x0B,
    GetK = 0x0C,
    GetKQ = 0x0D,
    Append = 0x0E,
    Prepend = 0x0F,
    Stat = 0x10,
    SetQ = 0x11,
    AddQ = 0x12,
    ReplaceQ = 0x13,
    DeleteQ = 0x14,
    IncrementQ = 0x15,
    DecrementQ = 0x16,
    QuitQ = 0x17,
    FlushQ = 0x18,
    AppendQ = 0x19,
    PrependQ = 0x1A
}

enum_from_primitive! {
    #[derive(Debug, PartialEq)]
    pub enum Status {
        Success = 0x00,
        KeyNotFound = 0x01,
        KeyExists = 0x02,
        AuthError = 0x08,
        UnknownCommand = 0x81
    }
}

#[derive(Debug)]
pub struct Request {
    magic: u8,
    opcode: u8,
    key_length: u16,
    extras_length: u8,
    data_type: u8,
    reserved: u16,
    body_length: u32,
    opaque: u32,
    cas: u64
}

#[derive(Debug)]
pub struct Response {
    magic: u8,
    opcode: u8,
    key_length: u16,
    extras_length: u8,
    data_type: u8,
    status: u16,
    body_length: u32,
    opaque: u32,
    cas: u64
}

pub struct SetAddReplace {
    flags: u32,
    expiration: u32
}

#[derive(Debug)]
pub struct Protocol {
    connection: TcpStream
}

impl Protocol {
    pub fn connect<A: ToSocketAddrs>(addr: A) -> Result<Protocol, BMemcachedError> {
        Ok(Protocol{connection: try!(TcpStream::connect(addr))})
    }

    pub fn connection_info(&self) -> String {
        format!("{:?}", self.connection.peer_addr().unwrap())
    }

    fn build_request(command: Command, key_length: usize, value_length: usize, data_type: u8,
        extras_length: usize, cas: u64) -> Request {
        Request {
            magic: Type::Request as u8, opcode: command as u8,
            key_length: key_length as u16,
            extras_length: extras_length as u8,
            data_type: data_type, reserved: 0,
            body_length: (key_length + value_length + extras_length) as u32,
            opaque: 0, cas: cas
        }
    }

    fn write_request(&self, request: Request, final_payload: &[u8]) -> Result<(), BMemcachedError> {
        let mut buf = &self.connection;
        try!(buf.write_u8(request.magic));
        try!(buf.write_u8(request.opcode));
        try!(buf.write_u16::<BigEndian>(request.key_length));
        try!(buf.write_u8(request.extras_length));
        try!(buf.write_u8(request.data_type));
        try!(buf.write_u16::<BigEndian>(request.reserved));
        try!(buf.write_u32::<BigEndian>(request.body_length));
        try!(buf.write_u32::<BigEndian>(request.opaque));
        try!(buf.write_u64::<BigEndian>(request.cas));
        try!(buf.write(final_payload));
        Ok(())
    }

    fn read_response(&mut self) -> Result<Response, BMemcachedError> {
        let mut buf = &self.connection;
        let magic: u8 = try!(buf.read_u8());
        if magic != Type::Response as u8 {
            // TODO Consume the stream, disconnect or something?
            return Err(BMemcachedError::UnkownError("Server sent an unknown magi code"))
        }
        Ok(Response {
            magic: magic,
            opcode: try!(buf.read_u8()),
            key_length: try!(buf.read_u16::<BigEndian>()),
            extras_length: try!(buf.read_u8()),
            data_type: try!(buf.read_u8()),
            status: try!(buf.read_u16::<BigEndian>()),
            body_length: try!(buf.read_u32::<BigEndian>()),
            opaque: try!(buf.read_u32::<BigEndian>()),
            cas: try!(buf.read_u64::<BigEndian>())
        })
    }

    fn set_add_replace<K, V>(&mut self, command: Command, key: K, value: V, time: u32) -> Result<(), BMemcachedError>
        where K: AsRef<[u8]>, V: AsRef<[u8]> {
        let key = key.as_ref();
        let value = value.as_ref();
        let extras_length = size_of::<SetAddReplace>();
        let request = Protocol::build_request(command, key.len(), value.len(), 0x00, extras_length, 0x00);
        let mut final_payload = vec![];
        // Flags
        try!(final_payload.write_u32::<BigEndian>(0));
        try!(final_payload.write_u32::<BigEndian>(time));
        // After flags key and value
        try!(final_payload.write(key));
        try!(final_payload.write(value));
        let size = try!(self.write_request(request, final_payload.as_slice()));
        let response = try!(self.read_response());
        match Status::from_u16(response.status) {
            Some(Status::Success) => Ok(()),
            Some(rest) => Err(BMemcachedError::Status(rest)),
            None => Err(BMemcachedError::UnkownError("Server returned an unknown status code"))
        }
    }

    pub fn set<K, V>(&mut self, key: K, value: V, time: u32) -> Result<(), BMemcachedError>
        where K: AsRef<[u8]>, V: AsRef<[u8]> {
        self.set_add_replace(Command::Set, key, value, time)
    }

    pub fn add<K, V>(&mut self, key: K, value: V, time: u32) -> Result<(), BMemcachedError>
        where K: AsRef<[u8]>, V: AsRef<[u8]> {
        self.set_add_replace(Command::Add, key, value, time)
    }

    pub fn replace<K, V>(&mut self, key: K, value: V, time: u32) -> Result<(), BMemcachedError>
        where K: AsRef<[u8]>, V: AsRef<[u8]> {
        self.set_add_replace(Command::Replace, key, value, time)
    }

    pub fn get<K>(&mut self, key: K) -> Result<String, BMemcachedError> where K: AsRef<[u8]> {
        let key = key.as_ref();
        let request = Protocol::build_request(Command::Get, key.len(), 0 as usize, 0, 0, 0x00);
        self.write_request(request, key);
        let response = try!(self.read_response());
        match Status::from_u16(response.status) {
            Some(Status::Success) => {},
            Some(status) => return Err(BMemcachedError::Status(status)),
            None => return Err(BMemcachedError::UnkownError("Server sent an unknown status code"))
        };
        // Discard extras for now
        try!(self.connection.read_u32::<BigEndian>());
        let mut outbuf = vec![0; (response.body_length - response.extras_length as u32) as usize];
        try!(self.connection.read_exact(&mut outbuf));
        Ok(try!(String::from_utf8(outbuf)))
    }
}

#[test]
fn test_set_key() {
    let mut p = Protocol::connect("127.0.0.1:11211").unwrap();
    let key = "Hello";
    let value = "World";
    p.set(key, value, 100).unwrap()
}

#[test]
fn test_add_key() {
    let mut p = Protocol::connect("127.0.0.1:11211").unwrap();
    let key = "Hello Add";
    let value = "World";
    p.add(key, value, 10).unwrap();
    let result = p.add(key, value, 10);
    match result {
        Ok(()) => panic!("Add key should return error"),
        Err(BMemcachedError::Status(Status::KeyExists)) => return,
        Err(_) => panic!("Some strange error that should not happen")
    }
}

#[test]
fn test_get_key() {
    let mut p = Protocol::connect("127.0.0.1:11211").unwrap();
    let key = "Hello";
    let value = "World";
    p.set(key, value, 100).unwrap();
    assert_eq!(p.get(key).unwrap(),  value);
    match p.get("not found".to_string()) {
        Ok(_) => panic!("This key should not exist"),
        Err(BMemcachedError::Status(Status::KeyNotFound)) => return,
        Err(_) => panic!("This should return KeyNotFound")
    }
}
<|endoftext|>


<commit_before>use std::io::{Read};
use std::fs::{self, File};
use std::path::{Path, PathBuf};
use std::collections::HashMap;

use tar::Archive;

pub type StaticMap = HashMap<String, Vec<u8>>;

pub trait StaticProvider: Sync + Send + 'static {
	fn get_content(&self, path: &str) -> Option<&Vec<u8>>;
}

impl StaticProvider for StaticMap {
	fn get_content(&self, path: &str) -> Option<&Vec<u8>> {
		self.get(path)
	}
}

pub fn provider_from_folder(path: &Path) -> StaticMap {
	let mut result = StaticMap::new();
	let path = PathBuf::from(path);
	read_dir_with_subdirs(path, "".to_owned(), &mut result);
	result
}

pub fn provider_from_tar(path: &Path) -> StaticMap {
	let mut result = StaticMap::new();
    let arch_file = File::open(path).unwrap();
    let arch = Archive::new(arch_file);

	for file in arch.files().unwrap() {
		let mut file = file.unwrap();

		match file.header().size() {
			Ok(0) => (),
			Ok(size) => {

				let str_path = {
					let mut pb = PathBuf::new();
					let file_path = file.header().path().unwrap();
	    	    	pb.push(file_path);
	    	    	let mut s = String::new();
	    	    	s.push_str(pb.to_str().unwrap());
	    	    	s.remove(0); // Drop first `.` in `./filename.ext`
	    	    	s
	    	    };
	    	    let mut content = Vec::with_capacity(size as usize);
    	    	file.read_to_end(&mut content).unwrap();
    	    	result.insert(str_path, content);
			},
			_ => ()
		}
	}
	result
}

fn read_file_to_vec(path: &Path) -> Vec<u8> {
	match File::open(path) {
		Ok(mut file) => {
			let mut content = Vec::new();
			file.read_to_end(&mut content).unwrap();
			content
		}
		Err(_) => {
			panic!("Can't read file.");
		},
	}
}

fn read_dir_with_subdirs(path: PathBuf, prefix: String, map: &mut StaticMap) {
	for entry in fs::read_dir(&path).unwrap() {
		let entry = entry.unwrap();
		let file_name = entry.file_name();
		let new_path = path.join(&file_name);

		let mut new_prefix = prefix.clone();
		new_prefix.push('/');
		new_prefix.push_str(&file_name.to_str().unwrap());

		let meta = entry.metadata().unwrap();
		if meta.is_dir() {
			read_dir_with_subdirs(new_path, new_prefix, map);
		} else if meta.is_file() {
			let content = read_file_to_vec(&new_path);
			map.insert(new_prefix, content);
		}
	}
}

<commit_msg>Fix indent in provider.rs<commit_after>use std::io::{Read};
use std::fs::{self, File};
use std::path::{Path, PathBuf};
use std::collections::HashMap;

use tar::Archive;

pub type StaticMap = HashMap<String, Vec<u8>>;

pub trait StaticProvider: Sync + Send + 'static {
	fn get_content(&self, path: &str) -> Option<&Vec<u8>>;
}

impl StaticProvider for StaticMap {
	fn get_content(&self, path: &str) -> Option<&Vec<u8>> {
		self.get(path)
	}
}

pub fn provider_from_folder(path: &Path) -> StaticMap {
	let mut result = StaticMap::new();
	let path = PathBuf::from(path);
	read_dir_with_subdirs(path, "".to_owned(), &mut result);
	result
}

pub fn provider_from_tar(path: &Path) -> StaticMap {
	let mut result = StaticMap::new();
	let arch_file = File::open(path).unwrap();
	let arch = Archive::new(arch_file);

	for file in arch.files().unwrap() {
		let mut file = file.unwrap();

		match file.header().size() {
			Ok(0) => (),
			Ok(size) => {

				let str_path = {
					let mut pb = PathBuf::new();
					let file_path = file.header().path().unwrap();
					pb.push(file_path);
					let mut s = String::new();
					s.push_str(pb.to_str().unwrap());
					s.remove(0); // Drop first `.` in `./filename.ext`
					s
				};
				let mut content = Vec::with_capacity(size as usize);
				file.read_to_end(&mut content).unwrap();
				result.insert(str_path, content);
			},
			_ => ()
		}
	}
	result
}

fn read_file_to_vec(path: &Path) -> Vec<u8> {
	match File::open(path) {
		Ok(mut file) => {
			let mut content = Vec::new();
			file.read_to_end(&mut content).unwrap();
			content
		}
		Err(_) => {
			panic!("Can't read file.");
		},
	}
}

fn read_dir_with_subdirs(path: PathBuf, prefix: String, map: &mut StaticMap) {
	for entry in fs::read_dir(&path).unwrap() {
		let entry = entry.unwrap();
		let file_name = entry.file_name();
		let new_path = path.join(&file_name);

		let mut new_prefix = prefix.clone();
		new_prefix.push('/');
		new_prefix.push_str(&file_name.to_str().unwrap());

		let meta = entry.metadata().unwrap();
		if meta.is_dir() {
			read_dir_with_subdirs(new_path, new_prefix, map);
		} else if meta.is_file() {
			let content = read_file_to_vec(&new_path);
			map.insert(new_prefix, content);
		}
	}
}

<|endoftext|>


<commit_before>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2014  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use wrap::Wrapper;

use std::mem;
use std::ops::Deref;

pub trait Refcount {
    unsafe fn inc_ref(&self);
    unsafe fn dec_ref(&self);
}

pub struct Ref<T> where T: Refcount {
    ptr: *const T
}

unsafe impl<T> Send for Ref<T> where T: Refcount + Send + Sync { }
unsafe impl<T> Sync for Ref<T> where T: Refcount + Send + Sync { }

impl<T> Ref<T> where T: Refcount {

    pub fn new(source: &T) -> Ref<T> {
        unsafe {
            source.inc_ref();
        }
        Ref { ptr: source as *const T }
    }
}

impl<T> Ref<T> where T: Refcount + Wrapper {

    pub unsafe fn from_raw(ptr: *mut <T as Wrapper>::Raw) -> Ref<T> {
        Ref { ptr: ptr as *const T }
    }
}

#[unsafe_destructor]
impl<T> Drop for Ref<T> where T: Refcount {
    fn drop(&mut self) {
        unsafe {
            self.dec_ref();
        }
    }
}

impl<T> Clone for Ref<T> where T: Refcount {

    fn clone(&self) -> Ref<T> {
        Ref::new(self.deref())
    }

    fn clone_from(&mut self, source: &Ref<T>) {
        unsafe {
            source.inc_ref();
            self.dec_ref();
        }
        self.ptr = source.ptr;
    }
}

impl<T> Deref for Ref<T> {

    type Target = T;

    fn deref(&self) -> &T {
        unsafe { mem::copy_lifetime(self, &*self.ptr) }
    }
}
<commit_msg>refcount: make Ref lower the Send and Sync bounds exactly onto deref type<commit_after>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2014  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use wrap::Wrapper;

use std::mem;
use std::ops::Deref;

pub trait Refcount {
    unsafe fn inc_ref(&self);
    unsafe fn dec_ref(&self);
}

pub struct Ref<T> where T: Refcount {
    ptr: *const T
}

unsafe impl<T> Send for Ref<T> where T: Refcount + Send { }
unsafe impl<T> Sync for Ref<T> where T: Refcount + Sync { }

impl<T> Ref<T> where T: Refcount {

    pub fn new(source: &T) -> Ref<T> {
        unsafe {
            source.inc_ref();
        }
        Ref { ptr: source as *const T }
    }
}

impl<T> Ref<T> where T: Refcount + Wrapper {

    pub unsafe fn from_raw(ptr: *mut <T as Wrapper>::Raw) -> Ref<T> {
        Ref { ptr: ptr as *const T }
    }
}

#[unsafe_destructor]
impl<T> Drop for Ref<T> where T: Refcount {
    fn drop(&mut self) {
        unsafe {
            self.dec_ref();
        }
    }
}

impl<T> Clone for Ref<T> where T: Refcount {

    fn clone(&self) -> Ref<T> {
        Ref::new(self.deref())
    }

    fn clone_from(&mut self, source: &Ref<T>) {
        unsafe {
            source.inc_ref();
            self.dec_ref();
        }
        self.ptr = source.ptr;
    }
}

impl<T> Deref for Ref<T> {

    type Target = T;

    fn deref(&self) -> &T {
        unsafe { mem::copy_lifetime(self, &*self.ptr) }
    }
}
<|endoftext|>


<commit_before>use std::num::ParseIntError;

use super::results::{CabotResult, CabotError};

#[derive(Debug)]
pub struct Response {
    status_code: usize,
    status_line: String,
    headers: Vec<String>,
    body: Option<Vec<u8>>,
}

impl Response {
    fn new(status_code: usize,
           status_line: String,
           headers: Vec<String>,
           body: Option<Vec<u8>>)
           -> Response {
        Response {
            status_code: status_code,
            status_line: status_line,
            headers: headers,
            body: body,
        }
    }

    pub fn status_code(&self) -> usize {
        self.status_code
    }

    pub fn status_line(&self) -> &str {
        self.status_line.as_str()
    }

    pub fn headers(&self) -> Vec<&str> {
        let headers: Vec<&str> = self.headers.iter().map(|s| s.as_ref()).collect();
        headers
    }

    pub fn body(&self) -> Option<&[u8]> {
        match self.body {
            None => None,
            Some(ref body) => {
                Some(body.as_slice())
            }
        }
    }

    pub fn body_as_string(&self) -> CabotResult<String> {
        let body = match self.body {
            None => "".to_owned(),
            Some(ref body) => {
                let mut body_vec: Vec<u8> = Vec::new();
                body_vec.extend_from_slice(body);
                let body_str = String::from_utf8(body_vec);
                if body_str.is_err() {
                    return Err(CabotError::EncodingError(format!("Cannot decode utf8: {}", body_str.unwrap_err())))
                }
                body_str.unwrap()
            }
        };
        Ok(body)
    }
}

#[derive(Debug)]
pub struct ResponseBuilder {
    status_line: Option<String>,
    headers: Vec<String>,
    body: Option<Vec<u8>>,
}

impl ResponseBuilder {
    pub fn new() -> Self {
        ResponseBuilder {
            status_line: None,
            headers: Vec::new(),
            body: None,
        }
    }

    pub fn set_status_line(mut self, status_line: &str) -> Self {
        self.status_line = Some(status_line.to_string());
        self
    }

    pub fn add_header(mut self, header: &str) -> Self {
        self.headers.push(header.to_owned());
        self
    }

    pub fn set_body(mut self, buf: &[u8]) -> Self {
        let mut body = Vec::with_capacity(buf.len());
        body.extend_from_slice(buf);
        self.body = Some(body);
        self
    }

    pub fn build(&self) -> CabotResult<Response> {
        if self.status_line.is_none() {
            return Err(CabotError::HttpResponseParseError("No Status Line".to_owned()));
        }

        let status_line = self.status_line.as_ref().unwrap();
        let mut vec_status_line: Vec<&str> = status_line.splitn(3, " ").collect();

        if vec_status_line.len() != 3 {
            return Err(CabotError::HttpResponseParseError(format!("Malformed Status Line: {}", status_line)));
        }

        let http_version = vec_status_line.remove(0);
        if !http_version.starts_with("HTTP/") {
            return Err(CabotError::HttpResponseParseError(format!("Unkown Protocol in Status Line: {}", status_line)));
        }

        let status_code = vec_status_line.get(0).unwrap();
        let status_code: Result<usize, ParseIntError> = status_code.parse();
        if status_code.is_err() {
            return Err(CabotError::HttpResponseParseError(format!("Malformed status code: {}", status_line)));
        }
        let status_code = status_code.unwrap();
        let status_line = vec_status_line.as_slice().join(" ");

        Ok(Response::new(status_code,
                         status_line,
                         self.headers.to_owned(),
                         self.body.to_owned()))
    }
}

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

    #[test]
    fn test_response_ok() {
        let response = Response::new(
            200,
            "200 Ok".to_owned(),
            vec!["Content-Type: application/json".to_owned()],
            Some(vec![123, 125]));

        assert_eq!(response.status_code(), 200);
        assert_eq!(response.status_line(), "200 Ok");
        assert_eq!(response.headers(), &["Content-Type: application/json"]);
        let body: &[u8] = &[123, 125];
        assert_eq!(response.body(), Some(body));
        assert_eq!(response.body_as_string().unwrap(), "{}");
    }

    #[test]
    fn test_response_ok_no_body() {
        let response = Response::new(
            204,
            "204 No Content".to_owned(),
            vec![],
            None);

        assert_eq!(response.status_code(), 204);
        assert_eq!(response.status_line(), "204 No Content");
        let headers: &[&str] = &[];
        assert_eq!(response.headers(), headers);
        assert_eq!(response.body(), None);
        assert_eq!(response.body_as_string().unwrap(), "".to_string());
    }

    #[test]
    fn test_build_response_ok() {
        let response = ResponseBuilder::new()
            .set_status_line("HTTP/1.1 200 Ok")
            .add_header("Content-Type: application/json")
            .set_body(&[123, 125])
            .build()
            .unwrap();

        assert_eq!(response.status_code(), 200);
        assert_eq!(response.status_line(), "200 Ok");
        assert_eq!(response.headers(), &["Content-Type: application/json"]);
        let body: &[u8] = &[123, 125];
        assert_eq!(response.body(), Some(body));
        assert_eq!(response.body_as_string().unwrap(), "{}");
    }

}<commit_msg>Keep the http version and expose it in the response<commit_after>use std::num::ParseIntError;

use super::results::{CabotResult, CabotError};

#[derive(Debug)]
pub struct Response {
    http_version: String,
    status_code: usize,
    status_line: String,
    headers: Vec<String>,
    body: Option<Vec<u8>>,
}

impl Response {
    fn new(http_version:String,
           status_code: usize,
           status_line: String,
           headers: Vec<String>,
           body: Option<Vec<u8>>)
           -> Response {
        Response {
            http_version: http_version,
            status_code: status_code,
            status_line: status_line,
            headers: headers,
            body: body,
        }
    }

    pub fn http_version(&self) -> &str {
        self.http_version.as_str()
    }

    pub fn status_code(&self) -> usize {
        self.status_code
    }

    pub fn status_line(&self) -> &str {
        self.status_line.as_str()
    }

    pub fn headers(&self) -> Vec<&str> {
        let headers: Vec<&str> = self.headers.iter().map(|s| s.as_ref()).collect();
        headers
    }

    pub fn body(&self) -> Option<&[u8]> {
        match self.body {
            None => None,
            Some(ref body) => {
                Some(body.as_slice())
            }
        }
    }

    pub fn body_as_string(&self) -> CabotResult<String> {
        let body = match self.body {
            None => "".to_owned(),
            Some(ref body) => {
                let mut body_vec: Vec<u8> = Vec::new();
                body_vec.extend_from_slice(body);
                let body_str = String::from_utf8(body_vec);
                if body_str.is_err() {
                    return Err(CabotError::EncodingError(format!("Cannot decode utf8: {}", body_str.unwrap_err())))
                }
                body_str.unwrap()
            }
        };
        Ok(body)
    }
}

#[derive(Debug)]
pub struct ResponseBuilder {
    status_line: Option<String>,
    headers: Vec<String>,
    body: Option<Vec<u8>>,
}

impl ResponseBuilder {
    pub fn new() -> Self {
        ResponseBuilder {
            status_line: None,
            headers: Vec::new(),
            body: None,
        }
    }

    pub fn set_status_line(mut self, status_line: &str) -> Self {
        self.status_line = Some(status_line.to_string());
        self
    }

    pub fn add_header(mut self, header: &str) -> Self {
        self.headers.push(header.to_owned());
        self
    }

    pub fn set_body(mut self, buf: &[u8]) -> Self {
        let mut body = Vec::with_capacity(buf.len());
        body.extend_from_slice(buf);
        self.body = Some(body);
        self
    }

    pub fn build(&self) -> CabotResult<Response> {
        if self.status_line.is_none() {
            return Err(CabotError::HttpResponseParseError("No Status Line".to_owned()));
        }

        let status_line = self.status_line.as_ref().unwrap();
        let mut vec_status_line: Vec<&str> = status_line.splitn(3, " ").collect();

        if vec_status_line.len() != 3 {
            return Err(CabotError::HttpResponseParseError(format!("Malformed Status Line: {}", status_line)));
        }

        let http_version = vec_status_line.remove(0);
        if !http_version.starts_with("HTTP/") {
            return Err(CabotError::HttpResponseParseError(format!("Unkown Protocol in Status Line: {}", status_line)));
        }

        let status_code = vec_status_line.get(0).unwrap();
        let status_code: Result<usize, ParseIntError> = status_code.parse();
        if status_code.is_err() {
            return Err(CabotError::HttpResponseParseError(format!("Malformed status code: {}", status_line)));
        }
        let status_code = status_code.unwrap();
        let status_line = vec_status_line.as_slice().join(" ");

        Ok(Response::new(http_version.to_owned(),
                         status_code,
                         status_line,
                         self.headers.to_owned(),
                         self.body.to_owned()))
    }
}

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

    #[test]
    fn test_response_ok() {
        let response = Response::new(
            "HTTP/1.1".to_owned(),
            200,
            "200 Ok".to_owned(),
            vec!["Content-Type: application/json".to_owned()],
            Some(vec![123, 125]));

        assert_eq!(response.http_version(), "HTTP/1.1");
        assert_eq!(response.status_code(), 200);
        assert_eq!(response.status_line(), "200 Ok");
        assert_eq!(response.headers(), &["Content-Type: application/json"]);
        let body: &[u8] = &[123, 125];
        assert_eq!(response.body(), Some(body));
        assert_eq!(response.body_as_string().unwrap(), "{}");
    }

    #[test]
    fn test_response_ok_no_body() {
        let response = Response::new(
            "HTTP/1.1".to_owned(),
            204,
            "204 No Content".to_owned(),
            vec![],
            None);

        assert_eq!(response.http_version(), "HTTP/1.1");
        assert_eq!(response.status_code(), 204);
        assert_eq!(response.status_line(), "204 No Content");
        let headers: &[&str] = &[];
        assert_eq!(response.headers(), headers);
        assert_eq!(response.body(), None);
        assert_eq!(response.body_as_string().unwrap(), "".to_string());
    }

    #[test]
    fn test_build_response_ok() {
        let response = ResponseBuilder::new()
            .set_status_line("HTTP/1.1 200 Ok")
            .add_header("Content-Type: application/json")
            .set_body(&[123, 125])
            .build()
            .unwrap();

        assert_eq!(response.http_version(), "HTTP/1.1");
        assert_eq!(response.status_code(), 200);
        assert_eq!(response.status_line(), "200 Ok");
        assert_eq!(response.headers(), &["Content-Type: application/json"]);
        let body: &[u8] = &[123, 125];
        assert_eq!(response.body(), Some(body));
        assert_eq!(response.body_as_string().unwrap(), "{}");
    }

}<|endoftext|>


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

//! The standard RNG

use crate::{CryptoRng, Error, RngCore, SeedableRng};

#[cfg(all(any(test, feature = "std"), not(target_os = "emscripten")))]
pub(crate) use rand_chacha::ChaCha12Core as Core;
#[cfg(all(any(test, feature = "std"), target_os = "emscripten"))]
pub(crate) use rand_hc::Hc128Core as Core;

#[cfg(not(target_os = "emscripten"))] use rand_chacha::ChaCha12Rng as Rng;
#[cfg(target_os = "emscripten")] use rand_hc::Hc128Rng as Rng;

/// The standard RNG. The PRNG algorithm in `StdRng` is chosen to be efficient
/// on the current platform, to be statistically strong and unpredictable
/// (meaning a cryptographically secure PRNG).
///
/// The current algorithm used is the ChaCha block cipher with 20 rounds.
/// This may change as new evidence of cipher security and performance
/// becomes available.
///
/// The algorithm is deterministic but should not be considered reproducible
/// due to dependence on configuration and possible replacement in future
/// library versions. For a secure reproducible generator, we recommend use of
/// the [rand_chacha] crate directly.
///
/// [rand_chacha]: https://crates.io/crates/rand_chacha
#[cfg_attr(doc_cfg, doc(cfg(feature = "std_rng")))]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct StdRng(Rng);

impl RngCore for StdRng {
    #[inline(always)]
    fn next_u32(&mut self) -> u32 {
        self.0.next_u32()
    }

    #[inline(always)]
    fn next_u64(&mut self) -> u64 {
        self.0.next_u64()
    }

    #[inline(always)]
    fn fill_bytes(&mut self, dest: &mut [u8]) {
        self.0.fill_bytes(dest);
    }

    #[inline(always)]
    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
        self.0.try_fill_bytes(dest)
    }
}

impl SeedableRng for StdRng {
    type Seed = <Rng as SeedableRng>::Seed;

    #[inline(always)]
    fn from_seed(seed: Self::Seed) -> Self {
        StdRng(Rng::from_seed(seed))
    }

    #[inline(always)]
    fn from_rng<R: RngCore>(rng: R) -> Result<Self, Error> {
        Rng::from_rng(rng).map(StdRng)
    }
}

impl CryptoRng for StdRng {}

#[cfg(test)]
mod test {
    use crate::rngs::StdRng;
    use crate::{RngCore, SeedableRng};

    #[test]
    fn test_stdrng_construction() {
        // Test value-stability of StdRng. This is expected to break any time
        // the algorithm is changed.
        #[rustfmt::skip]
        let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0,
                    0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];

        let target = [10719222850664546238, 14064965282130556830];

        let mut rng0 = StdRng::from_seed(seed);
        let x0 = rng0.next_u64();

        let mut rng1 = StdRng::from_rng(rng0).unwrap();
        let x1 = rng1.next_u64();

        assert_eq!([x0, x1], target);
    }
}
<commit_msg>Modified the StdRng documentation<commit_after>// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The standard RNG

use crate::{CryptoRng, Error, RngCore, SeedableRng};

#[cfg(all(any(test, feature = "std"), not(target_os = "emscripten")))]
pub(crate) use rand_chacha::ChaCha12Core as Core;
#[cfg(all(any(test, feature = "std"), target_os = "emscripten"))]
pub(crate) use rand_hc::Hc128Core as Core;

#[cfg(not(target_os = "emscripten"))] use rand_chacha::ChaCha12Rng as Rng;
#[cfg(target_os = "emscripten")] use rand_hc::Hc128Rng as Rng;

/// The standard RNG. The PRNG algorithm in `StdRng` is chosen to be efficient
/// on the current platform, to be statistically strong and unpredictable
/// (meaning a cryptographically secure PRNG).
///
/// The current algorithm used is the ChaCha block cipher with 12 rounds. Please
/// see this relevant [rand issue] for the discussion. This may change as new
/// evidence of cipher security and performance becomes available.
///
/// The algorithm is deterministic but should not be considered reproducible
/// due to dependence on configuration and possible replacement in future
/// library versions. For a secure reproducible generator, we recommend use of
/// the [rand_chacha] crate directly.
///
/// [rand_chacha]: https://crates.io/crates/rand_chacha
/// [rand issue]: https://github.com/rust-random/rand/issues/932
#[cfg_attr(doc_cfg, doc(cfg(feature = "std_rng")))]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct StdRng(Rng);

impl RngCore for StdRng {
    #[inline(always)]
    fn next_u32(&mut self) -> u32 {
        self.0.next_u32()
    }

    #[inline(always)]
    fn next_u64(&mut self) -> u64 {
        self.0.next_u64()
    }

    #[inline(always)]
    fn fill_bytes(&mut self, dest: &mut [u8]) {
        self.0.fill_bytes(dest);
    }

    #[inline(always)]
    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
        self.0.try_fill_bytes(dest)
    }
}

impl SeedableRng for StdRng {
    type Seed = <Rng as SeedableRng>::Seed;

    #[inline(always)]
    fn from_seed(seed: Self::Seed) -> Self {
        StdRng(Rng::from_seed(seed))
    }

    #[inline(always)]
    fn from_rng<R: RngCore>(rng: R) -> Result<Self, Error> {
        Rng::from_rng(rng).map(StdRng)
    }
}

impl CryptoRng for StdRng {}

#[cfg(test)]
mod test {
    use crate::rngs::StdRng;
    use crate::{RngCore, SeedableRng};

    #[test]
    fn test_stdrng_construction() {
        // Test value-stability of StdRng. This is expected to break any time
        // the algorithm is changed.
        #[rustfmt::skip]
        let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0,
                    0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];

        let target = [10719222850664546238, 14064965282130556830];

        let mut rng0 = StdRng::from_seed(seed);
        let x0 = rng0.next_u64();

        let mut rng1 = StdRng::from_rng(rng0).unwrap();
        let x1 = rng1.next_u64();

        assert_eq!([x0, x1], target);
    }
}
<|endoftext|>


<commit_before>extern crate rand;

use std::io;
use rand::Rng;

fn main() {
    println!("Guess the number!");

    let secret_number = rand::thread_rng().gen_range(1, 101);

    println!("The secret number is: {}", secret_number);

    println!("Please input your guess.");

    let mut guess = String::new();

    io::stdin().read_line(&mut guess)
        .expect("Failed to read line");

    println!("You guessed: {}", guess);
}
<commit_msg>Compare input and rand<commit_after>extern crate rand;

use std::io;
use std::cmp::Ordering;
use rand::Rng;

fn main() {
    println!("Guess the number!");

    let secret_number = rand::thread_rng().gen_range(1, 101);

    println!("The secret number is: {}", secret_number);

    println!("Please input your guess.");

    let mut guess = String::new();

    io::stdin().read_line(&mut guess)
        .expect("Failed to read line");

    let guess: u32 = guess.trim().parse()
        .expect("Please type a number!");

    println!("You guessed: {}", guess);

    match guess.cmp(&secret_number) {
        Ordering::Less    => println!("Too small!"),
        Ordering::Greater => println!("Too big!"),
        Ordering::Equal   => println!("You win!"),
    }
}
<|endoftext|>