<commit_before>extern crate core;

use core::num::FromPrimitive;
use core::fmt;

use std::rand::random;

use Direction::{SpinUp, SpinDown, SpinSuper};
use Plan::{Trivial, OddBall};

#[derive(Copy)]
#[derive(Show)]
enum Direction {
    SpinUp,
    SpinDown,
    SpinSuper,
}

impl fmt::String for Direction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let r = match self {
            &SpinUp => "SpinUp",
            &SpinDown => "SpinDown",
            &SpinSuper => "SpinSuper"
        };
        write!(f, "{}", r)
    }
}

impl fmt::String for Detector {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use Detector::{D12, D3, D9};
        let r = match self {
            &D12 => "12 oclock",
            &D3 => "3 oclock",
            &D9 => "9 oclock"
        };
        write!(f, "{}", r)
    }
}

struct Pair<T> {
    lhs: T,
    rhs: T
}

struct Particle {
    spin: Direction
}

enum Plan {
    Trivial, // up-up-up -> down-down-down
    OddBall  // up-down-up -> down-up-down
}

#[derive(Show)]
enum Detector {
    D12, // 12 o'clock
    D3, // 3 o'clock
    D9, // 9 o' clock
}

impl Particle {
    fn new_pair () -> Pair<Particle> {
        let d1 = SpinSuper;
        let d2 = SpinSuper;
        let p1 = Particle{spin: d1};
        let p2 = Particle{spin: d2};

        return Pair{lhs: p1, rhs: p2};
    }

    pub fn measure (&mut self, theta: isize) {
        // TODO theta = 60degrees use 3/4th and 1/4th
        // TODO theta = 0 SpinUp
        // TODO theta = 180 SpinDown
    }

    // NOTE on spooky and premeditated only if measured in the same
    // direction must the spins be opposite

    // measure with with a message
    pub fn spooky (&mut self, friend: &mut Particle) -> Pair<Direction> {

        let spin = match self.spin {
            SpinUp => SpinDown,
            SpinDown => SpinUp,
            SpinSuper => SpinUp
        };
        friend.spin = spin;

        let spin = match friend.spin {
            SpinUp => SpinDown,
            SpinDown => SpinUp,
            _ => panic!("broke the universe")
        };
        self.spin = spin;

        return Pair{lhs: self.spin, rhs: friend.spin};
    }

    fn get_detector_direction () -> Detector {
        let rnd = random::<f32>();

        let detector;
        if rnd < 0.33 {
            detector = Detector::D12;
        } else if rnd >= 0.33 && rnd < 0.66 {
            detector = Detector::D3;
        } else {
            detector = Detector::D9;
        }
        println!("d1 {}", detector);

        return detector;
    }

    pub fn premeditated (&mut self, friend: &mut Particle, plan: Plan) -> Pair<Direction> {

        let rnd = random::<f32>();

        let detector = Particle::get_detector_direction();
        let spin = match plan {
            Trivial => SpinUp,
            OddBall => match detector {
                Detector::D3 => SpinDown,
                _ => SpinUp
            }
        };
        friend.spin = spin;

        let detector = Particle::get_detector_direction();
        let spin = match plan {
            Trivial => SpinDown,
            OddBall => match detector {
                Detector::D3 => SpinUp,
                _ => SpinDown
            }
        };
        self.spin = spin;

        return Pair{lhs: self.spin, rhs: friend.spin};
    }
}

fn main () {

    let particles = Particle::new_pair();

    let mut lhs = particles.lhs;
    let mut rhs = particles.rhs;

    lhs.spooky(&mut rhs);

    println!("lhs.spin {}, rhs.spin {}", lhs.spin, rhs.spin);

    // premeditated should give +55.6% difference, spooky would give 50%

    let particles = Particle::new_pair();

    let mut lhs = particles.lhs;
    let mut rhs = particles.rhs;
    lhs.premeditated(&mut rhs, OddBall);
    println!("lhs.spin {}, rhs.spin {}", lhs.spin, rhs.spin);

}
<commit_msg>rename premeditated to hidden_information to be more descriptive<commit_after>extern crate core;

use core::num::FromPrimitive;
use core::fmt;

use std::rand::random;

use Direction::{SpinUp, SpinDown, SpinSuper};
use Plan::{Trivial, OddBall};

#[derive(Copy)]
#[derive(Show)]
enum Direction {
    SpinUp,
    SpinDown,
    SpinSuper,
}

impl fmt::String for Direction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let r = match self {
            &SpinUp => "SpinUp",
            &SpinDown => "SpinDown",
            &SpinSuper => "SpinSuper"
        };
        write!(f, "{}", r)
    }
}

impl fmt::String for Detector {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use Detector::{D12, D3, D9};
        let r = match self {
            &D12 => "12 oclock",
            &D3 => "3 oclock",
            &D9 => "9 oclock"
        };
        write!(f, "{}", r)
    }
}

struct Pair<T> {
    lhs: T,
    rhs: T
}

struct Particle {
    spin: Direction
}

enum Plan {
    Trivial, // up-up-up -> down-down-down
    OddBall  // up-down-up -> down-up-down
}

#[derive(Show)]
enum Detector {
    D12, // 12 o'clock
    D3, // 3 o'clock
    D9, // 9 o' clock
}

impl Particle {
    fn new_pair () -> Pair<Particle> {
        let d1 = SpinSuper;
        let d2 = SpinSuper;
        let p1 = Particle{spin: d1};
        let p2 = Particle{spin: d2};

        return Pair{lhs: p1, rhs: p2};
    }

    pub fn measure (&mut self, theta: isize) {
        // TODO theta = 60degrees use 3/4th and 1/4th
        // TODO theta = 0 SpinUp
        // TODO theta = 180 SpinDown
    }

    // NOTE on spooky and premeditated only if measured in the same
    // direction must the spins be opposite

    // measure with with a message
    pub fn spooky (&mut self, friend: &mut Particle) -> Pair<Direction> {

        let spin = match self.spin {
            SpinUp => SpinDown,
            SpinDown => SpinUp,
            SpinSuper => SpinUp
        };
        friend.spin = spin;

        let spin = match friend.spin {
            SpinUp => SpinDown,
            SpinDown => SpinUp,
            _ => panic!("broke the universe")
        };
        self.spin = spin;

        return Pair{lhs: self.spin, rhs: friend.spin};
    }

    fn get_detector_direction () -> Detector {
        let rnd = random::<f32>();

        let detector;
        if rnd < 0.33 {
            detector = Detector::D12;
        } else if rnd >= 0.33 && rnd < 0.66 {
            detector = Detector::D3;
        } else {
            detector = Detector::D9;
        }
        println!("d1 {}", detector);

        return detector;
    }

    pub fn hidden_information (&mut self, friend: &mut Particle, plan: Plan) -> Pair<Direction> {

        let rnd = random::<f32>();

        let detector = Particle::get_detector_direction();
        let spin = match plan {
            Trivial => SpinUp,
            OddBall => match detector {
                Detector::D3 => SpinDown,
                _ => SpinUp
            }
        };
        friend.spin = spin;

        let detector = Particle::get_detector_direction();
        let spin = match plan {
            Trivial => SpinDown,
            OddBall => match detector {
                Detector::D3 => SpinUp,
                _ => SpinDown
            }
        };
        self.spin = spin;

        return Pair{lhs: self.spin, rhs: friend.spin};
    }
}

fn main () {

    let particles = Particle::new_pair();

    let mut lhs = particles.lhs;
    let mut rhs = particles.rhs;

    lhs.spooky(&mut rhs);

    println!("lhs.spin {}, rhs.spin {}", lhs.spin, rhs.spin);

    // hidden_information should give +55.6% difference, spooky would give 50%

    let particles = Particle::new_pair();

    let mut lhs = particles.lhs;
    let mut rhs = particles.rhs;
    lhs.hidden_information(&mut rhs, OddBall);
    println!("lhs.spin {}, rhs.spin {}", lhs.spin, rhs.spin);

}
<|endoftext|>


<commit_before>mod entryline;
mod displayarea;
pub mod window;

use std::sync::mpsc::{Sender, Receiver};

use ncurses::*;

use self::entryline::EntryLine;
use self::window::Windows;

use event::ChatEvent;
use irc::command::Command;

pub struct Tui {
    entry_line: EntryLine,
    event_rx: Receiver<ChatEvent>,
    irc_tx: Sender<Command>,
    windows: Windows,
    running: bool,
}

impl Drop for Tui {
    fn drop(&mut self) {
        endwin();
    }
}

impl Tui {
    pub fn new(event_rx: Receiver<ChatEvent>, irc_tx: Sender<Command>) -> Tui {
        setlocale(LcCategory::all, "");
        initscr();
        keypad(stdscr, true);
        raw();
        noecho();
        nonl();
        start_color();
        timeout(50);
        let entry_line = EntryLine::new();
        Tui {
            entry_line: entry_line,
            event_rx: event_rx,
            irc_tx: irc_tx,
            windows: Windows::new(),
            running: true,
        }
    }

    pub fn event_loop(&mut self) {
        'main_loop:
        loop {
            if let Some(ch) = get_wch() {
                if let Some(line) = self.entry_line.key_input(ch) {
                    self.handle_line(line);
                }
            }
            if !self.running { break; }
            loop {
                use std::sync::mpsc::TryRecvError::*;
                match self.event_rx.try_recv() {
                    Ok(event) => self.windows.handle_event(event),
                    Err(Empty) => break,
                    Err(Disconnected) => break 'main_loop,
                }
            }
            self.windows.draw();
            self.entry_line.draw();
            doupdate();
        }
    }

    fn handle_line(&mut self, line: String) {
        if line.len() == 0 {
            return;
        }
        if line.chars().nth(0) == Some('/') {
            let mut line = line[1..].splitn(1, ' ');
            let command = line.next().unwrap_or("");
            let body = line.next().unwrap_or("");
            self.handle_command(command, body);
            return;
        }
        if let Some(target) = self.windows.current_target() {
            target.self_message(&line);
            let target = String::from(target.id().name().expect("tui::handle_line target not found"));
            self.irc_tx.send(Command::PrivMsg { target: target, message: line }).unwrap();
        } else {
            // TODO: Show error
        }
    }

    fn handle_command(&mut self, command: &str, body: &str) {
        match command {
            "join" => self.irc_tx.send(Command::Join { channel: String::from(body) }).unwrap(),
            "part" => {
                use self::window::WindowId::*;
                let channel = match *self.windows.current_window().id() {
                    Channel { ref name, .. } => Some(name),
                    _ => None,
                };
                if let Some(channel) = channel {
                    self.irc_tx.send(Command::Part { channel: channel.clone(), message: Some(String::from(body)) }).unwrap();
                }
            }
            "quit" => {
                self.irc_tx.send(unimplemented!()).unwrap();
                self.running = false;
            },
            "win" | "w" => {
                if let Some(number) = body.parse::<usize>().ok() {
                    self.windows.change_to(number);
                }
            }
            _ => {} // TODO: Handle unknown command
        }
    }
}
<commit_msg>Fix /command splitting<commit_after>mod entryline;
mod displayarea;
pub mod window;

use std::sync::mpsc::{Sender, Receiver};

use ncurses::*;

use self::entryline::EntryLine;
use self::window::Windows;

use event::ChatEvent;
use irc::command::Command;

pub struct Tui {
    entry_line: EntryLine,
    event_rx: Receiver<ChatEvent>,
    irc_tx: Sender<Command>,
    windows: Windows,
    running: bool,
}

impl Drop for Tui {
    fn drop(&mut self) {
        endwin();
    }
}

impl Tui {
    pub fn new(event_rx: Receiver<ChatEvent>, irc_tx: Sender<Command>) -> Tui {
        setlocale(LcCategory::all, "");
        initscr();
        keypad(stdscr, true);
        raw();
        noecho();
        nonl();
        start_color();
        timeout(50);
        let entry_line = EntryLine::new();
        Tui {
            entry_line: entry_line,
            event_rx: event_rx,
            irc_tx: irc_tx,
            windows: Windows::new(),
            running: true,
        }
    }

    pub fn event_loop(&mut self) {
        'main_loop:
        loop {
            if let Some(ch) = get_wch() {
                if let Some(line) = self.entry_line.key_input(ch) {
                    self.handle_line(line);
                }
            }
            if !self.running { break; }
            loop {
                use std::sync::mpsc::TryRecvError::*;
                match self.event_rx.try_recv() {
                    Ok(event) => self.windows.handle_event(event),
                    Err(Empty) => break,
                    Err(Disconnected) => break 'main_loop,
                }
            }
            self.windows.draw();
            self.entry_line.draw();
            doupdate();
        }
    }

    fn handle_line(&mut self, line: String) {
        if line.len() == 0 {
            return;
        }
        if line.chars().nth(0) == Some('/') {
            let mut line = line[1..].splitn(2, ' ');
            let command = line.next().unwrap_or("");
            let body = line.next().unwrap_or("");
            self.handle_command(command, body);
            return;
        }
        if let Some(target) = self.windows.current_target() {
            target.self_message(&line);
            let target = String::from(target.id().name().expect("tui::handle_line target not found"));
            self.irc_tx.send(Command::PrivMsg { target: target, message: line }).unwrap();
        } else {
            // TODO: Show error
        }
    }

    fn handle_command(&mut self, command: &str, body: &str) {
        match command {
            "join" => self.irc_tx.send(Command::Join { channel: String::from(body) }).unwrap(),
            "part" => {
                use self::window::WindowId::*;
                let channel = match *self.windows.current_window().id() {
                    Channel { ref name, .. } => Some(name),
                    _ => None,
                };
                if let Some(channel) = channel {
                    self.irc_tx.send(Command::Part { channel: channel.clone(), message: Some(String::from(body)) }).unwrap();
                }
            }
            "quit" => {
                self.irc_tx.send(unimplemented!()).unwrap();
                self.running = false;
            },
            "win" | "w" => {
                if let Some(number) = body.parse::<usize>().ok() {
                    self.windows.change_to(number);
                }
            }
            _ => {} // TODO: Handle unknown command
        }
    }
}
<|endoftext|>


<commit_before>#![feature(test)]
extern crate test;
extern crate gutenberg;
extern crate tempdir;

use std::env;

use tempdir::TempDir;
use gutenberg::{Site, populate_previous_and_next_pages};

// TODO: add bench with ~1000 pages for all cases

#[bench]
fn bench_loading_test_site(b: &mut test::Bencher) {
    let mut path = env::current_dir().unwrap().to_path_buf();
    path.push("test_site");
    let mut site = Site::new(&path, "config.toml").unwrap();

    b.iter(|| site.load().unwrap());
}

#[bench]
fn bench_building_test_site(b: &mut test::Bencher) {
    let mut path = env::current_dir().unwrap().to_path_buf();
    path.push("test_site");
    let mut site = Site::new(&path, "config.toml").unwrap();
    site.load().unwrap();
    let tmp_dir = TempDir::new("example").expect("create temp dir");
    let public = &tmp_dir.path().join("public");
    site.set_output_path(&public);

    b.iter(|| site.build().unwrap());
}

#[bench]
fn bench_populate_previous_and_next_pages(b: &mut test::Bencher) {
    let mut path = env::current_dir().unwrap().to_path_buf();
    path.push("test_site");
    let mut site = Site::new(&path, "config.toml").unwrap();
    site.load().unwrap();
    let pages = site.pages.values().cloned().collect::<Vec<_>>();

    b.iter(|| populate_previous_and_next_pages(pages.as_slice()));
}
<commit_msg>Add loading benches<commit_after>#![feature(test)]
extern crate test;
extern crate gutenberg;
extern crate tempdir;

use std::env;

use tempdir::TempDir;
use gutenberg::Site;

#[bench]
fn bench_loading_small_blog(b: &mut test::Bencher) {
    let mut path = env::current_dir().unwrap().to_path_buf();
    path.push("benches");
    path.push("small-blog");
    let mut site = Site::new(&path, "config.toml").unwrap();

    b.iter(|| site.load().unwrap());
}

#[bench]
fn bench_loading_small_blog_with_syntax_highlighting(b: &mut test::Bencher) {
    let mut path = env::current_dir().unwrap().to_path_buf();
    path.push("benches");
    path.push("small-blog");
    let mut site = Site::new(&path, "config.toml").unwrap();
    site.config.highlight_code = Some(true);

    b.iter(|| site.load().unwrap());
}

#[bench]
fn bench_loading_medium_blog(b: &mut test::Bencher) {
    let mut path = env::current_dir().unwrap().to_path_buf();
    path.push("benches");
    path.push("medium-blog");
    let mut site = Site::new(&path, "config.toml").unwrap();

    b.iter(|| site.load().unwrap());
}

#[bench]
fn bench_loading_medium_blog_with_syntax_highlighting(b: &mut test::Bencher) {
    let mut path = env::current_dir().unwrap().to_path_buf();
    path.push("benches");
    path.push("medium-blog");
    let mut site = Site::new(&path, "config.toml").unwrap();
    site.config.highlight_code = Some(true);

    b.iter(|| site.load().unwrap());
}

#[bench]
fn bench_loading_big_blog(b: &mut test::Bencher) {
    let mut path = env::current_dir().unwrap().to_path_buf();
    path.push("benches");
    path.push("big-blog");
    let mut site = Site::new(&path, "config.toml").unwrap();

    b.iter(|| site.load().unwrap());
}

#[bench]
fn bench_loading_big_blog_with_syntax_highlighting(b: &mut test::Bencher) {
    let mut path = env::current_dir().unwrap().to_path_buf();
    path.push("benches");
    path.push("big-blog");
    let mut site = Site::new(&path, "config.toml").unwrap();
    site.config.highlight_code = Some(true);

    b.iter(|| site.load().unwrap());
}

#[bench]
fn bench_loading_huge_blog(b: &mut test::Bencher) {
    let mut path = env::current_dir().unwrap().to_path_buf();
    path.push("benches");
    path.push("huge-blog");
    let mut site = Site::new(&path, "config.toml").unwrap();

    b.iter(|| site.load().unwrap());
}

#[bench]
fn bench_loading_huge_blog_with_syntax_highlighting(b: &mut test::Bencher) {
    let mut path = env::current_dir().unwrap().to_path_buf();
    path.push("benches");
    path.push("huge-blog");
    let mut site = Site::new(&path, "config.toml").unwrap();
    site.config.highlight_code = Some(true);

    b.iter(|| site.load().unwrap());
}

#[bench]
fn bench_loading_small_kb(b: &mut test::Bencher) {
    let mut path = env::current_dir().unwrap().to_path_buf();
    path.push("benches");
    path.push("small-kb");
    let mut site = Site::new(&path, "config.toml").unwrap();

    b.iter(|| site.load().unwrap());
}

#[bench]
fn bench_loading_small_kb_with_syntax_highlighting(b: &mut test::Bencher) {
    let mut path = env::current_dir().unwrap().to_path_buf();
    path.push("benches");
    path.push("small-kb");
    let mut site = Site::new(&path, "config.toml").unwrap();
    site.config.highlight_code = Some(true);

    b.iter(|| site.load().unwrap());
}

#[bench]
fn bench_loading_medium_kb(b: &mut test::Bencher) {
    let mut path = env::current_dir().unwrap().to_path_buf();
    path.push("benches");
    path.push("medium-kb");
    let mut site = Site::new(&path, "config.toml").unwrap();

    b.iter(|| site.load().unwrap());
}

#[bench]
fn bench_loading_medium_kb_with_syntax_highlighting(b: &mut test::Bencher) {
    let mut path = env::current_dir().unwrap().to_path_buf();
    path.push("benches");
    path.push("medium-kb");
    let mut site = Site::new(&path, "config.toml").unwrap();
    site.config.highlight_code = Some(true);

    b.iter(|| site.load().unwrap());
}

#[bench]
fn bench_loading_huge_kb(b: &mut test::Bencher) {
    let mut path = env::current_dir().unwrap().to_path_buf();
    path.push("benches");
    path.push("huge-kb");
    let mut site = Site::new(&path, "config.toml").unwrap();

    b.iter(|| site.load().unwrap());
}

#[bench]
fn bench_loading_huge_kb_with_syntax_highlighting(b: &mut test::Bencher) {
    let mut path = env::current_dir().unwrap().to_path_buf();
    path.push("benches");
    path.push("huge-kb");
    let mut site = Site::new(&path, "config.toml").unwrap();
    site.config.highlight_code = Some(true);

    b.iter(|| site.load().unwrap());
}
<|endoftext|>


<commit_before>
extern mod core;

use core::vec::Vec;
use core::option::{Option, Some, None};
use core::fail::abort;
use control::Ep0_Handler;
use stream::Stream_Handler;

static mut USB_MODULE: Option<Usb_Module> = None;

pub enum Endpoint_Type {
    Control,
    Tx_Only,
    Rx_Only,
    Tx_Rx,
    Isochronous_Tx,
    Isochronous_Rx
}

/// The trait for the low level USB peripheral
pub trait Usb_Peripheral {
    fn init(&self);
    fn attach(&self);
    fn reset(&self);

    fn poll(&self);

    fn max_endpoints(&self) -> uint;

    fn queue_next(&mut self, uint, bool, &Stream_Handler);
    fn set_address(&self, u8);
    fn ep_enable(&self, uint, Endpoint_Type);
    fn ep_stall(&self, uint);
    fn ep_unstall(&self, uint);
}

/// The trait for the endpoint handlers
pub trait Endpoint_Handler {
//    fn handle_setup(&self, &Usb_Module, uint, uint) -> bool;
//    fn handle_out(&self, &Usb_Module, uint, uint) -> bool;
//    fn handle_in(&self, &Usb_Module, uint, uint) -> bool;

    fn on_reset(&mut self, &'static mut Usb_Module);

    fn on_token(&mut self, &'static mut Usb_Module, uint, bool, Token_Pid, uint);
}

/// Enum for USB state machine
enum Usb_State {
    Unattached,
    Attached,
    Default,
    Set_Address,
    Address,
    Configured,
    Suspended
}

pub struct Usb_Module {
    peripheral: ~Usb_Peripheral,
    state: Usb_State,
    handler: Ep0_Handler,
}

impl Usb_Module {
    pub fn new(peripheral: ~Usb_Peripheral) -> &'static mut Usb_Module {
        // Abort if already initialised
        if Usb_Module::is_ready() {
            abort();
        }

        // Create struct and store as singleton
        let module = Usb_Module {
            peripheral: peripheral,
            state: Unattached,
            handler: Ep0_Handler::new(64)
        };
        unsafe {
            USB_MODULE = Some(module);
        }

        Usb_Module::get()
    }

    /// Return true if the singleton is ready
    pub fn is_ready() -> bool {
        unsafe {
            match USB_MODULE {
                Some(_) => true,
                None => false
            }
        }
    }

    /// Get the singleton object
    pub fn get() -> &'static mut Usb_Module {
        unsafe {
            match USB_MODULE {
                Some(ref mut module) => module,
                None => abort()
            }
        }
    }

    /// Enable and setup USB device
    pub fn init(&mut self) {
        // Initialise the low level device
        self.peripheral.init();

        // Attach and wait for reset
        self.peripheral.attach();

        // Set state to attached
        self.state = Attached;
    }

    /// React to USB bus reset
    pub fn on_reset(&'static mut self) {
        // Reset peripheral
        self.peripheral.reset();

        // Prepare endpoint 0
        self.handler.on_reset(self);

        // Set state to default
        self.state = Default;
    }

    /// Handle after STALL has been sent
    pub fn on_stall(&'static mut self) {
        // Ensure EP0 isn't stalled

        // Pass stall event to other handlers
        // Prepare endpoint 0 (if ep0 has stalled)
        // TODO: Add call for EP0 here
    }

    /// Handle transaction
    pub fn on_token(&'static mut self, endpoint: uint, is_tx: bool, pid: uint, length: uint) {
        // Get the handler for the endpoint
        // TODO: Support more than EP0
        let handler = &mut self.handler;

        // Convert pid into enum
        let pid = Token_Pid::from_u8(pid as u8);

        // Pass info to handler
        handler.on_token(self, endpoint, is_tx, pid, length);
    }

    /// Enable the endpoint for given transactions
    pub fn enable_ep(&mut self, endpoint: uint, transfer: Endpoint_Type) {
        // Tell peripheral to enable the endpoint
        self.peripheral.ep_enable(endpoint, transfer);
    }

    /// Set the STALL flag on an endpoint
    pub fn stall_ep(&self, endpoint: uint) {
        self.peripheral.ep_stall(endpoint);
    }

    /// Prepare to receive transaction on endpoint
    /// Takes endpoint number and stream handler
    pub fn queue_rx(&mut self, endpoint: uint, stream: &Stream_Handler) {
        // Pass to peripheral
        self.peripheral.queue_next(endpoint, false, stream);
    }

    /// Prepare to transmit transaction on endpoint
    pub fn queue_tx(&self, endpoint: uint, data1: bool, buf: &mut [u8]) {

    }
}

/// Prepare endpoint 0
fn setup() {

}

/// Struct with endpoint info
pub struct Ep_State {
    ep: u8,
    is_setup: bool,
    data: ~Vec<u8>,
    remaining: u16,
    max_size: u16,
    callback: fn (~Vec<u8>)
}

/// PIDs for tokens
pub enum Token_Pid {
    Out         = 0b0001,
    In          = 0b1001,
    Sof         = 0b0101,
    Setup       = 0b1101,

    Data0       = 0b0011,
    Data1       = 0b1011,
    Data2       = 0b0111,
    Mdata       = 0b1111,

    Ack         = 0b0010,
    Nak         = 0b1010,
    Stall       = 0b1110,
    Nyet        = 0b0110,

    Pre         = 0b1100,
    Split       = 0b1000,
    Ping        = 0b0100,
    Reserved    = 0b0000,
}

impl Token_Pid {
    pub fn from_u8(num: u8) -> Token_Pid {
        unsafe {
            core::mem::transmute(num & 0xF)
        }
    }
}

/// Handle a transaction (called after TOKDNE set)
pub fn handle_transaction(ep: u8, tx: bool, odd: bool, pid: u8, len: u16) {
    // Retrieve endpoint info struct
    let ep_state = match get_ep_state(ep, tx, odd) {
        Some(state) => state,
        None        => core::fail::abort()
    };

}

/// Handles a setup token
fn handle_setup(state: &mut Ep_State, len: u16) {
    // Check ep state is expecting a SETUP
    if state.is_setup {
        // Queue data same as an out token
        handle_out(state, len);
    } else {
        stall_ep(state.ep);
    }

    // Tell the peripheral to resume
    //freescale::usb::resume();
}

/// Handles an out token
fn handle_out(state: &mut Ep_State, len: u16) {
    // Toggle data01

    // Subtract remaining bytes
    state.remaining -= len;

    // Decide if more bytes are expected
    if state.remaining <= 9 || len < state.max_size {
        // Toggle data01
        // Update buffer address/copy data out
        queue_next(state);
    } else {
        // Call the closure/function
        //state.callback(state.data);
    }
}

/// Handles an in token
fn handle_in(state: &mut Ep_State, len: u16) {

}

/// Setup the state and BDT ready for OUT/SETUP token
pub fn prepare_out(state: &mut Ep_State, buf: ~[u8], len: u16, callback: fn (~[u8], u16)) {

}

/// Transfer the information in the state struct to the BDT
fn queue_next(state: &mut Ep_State) {

}

/// Gets the state for the specified endpoint
pub fn get_ep_state(ep: u8, tx: bool, odd: bool) -> Option<&mut Ep_State> {
    None
}

/// Stall the selected endpoint
fn stall_ep(ep: u8) {
    //freescale::usb::stall_ep(ep);
}
<commit_msg>Modify Usb_Module::new to accept static pointer to peripheral<commit_after>
extern mod core;

use core::vec::Vec;
use core::option::{Option, Some, None};
use core::fail::abort;
use control::Ep0_Handler;
use stream::Stream_Handler;

static mut USB_MODULE: Option<Usb_Module> = None;

pub enum Endpoint_Type {
    Control,
    Tx_Only,
    Rx_Only,
    Tx_Rx,
    Isochronous_Tx,
    Isochronous_Rx
}

/// The trait for the low level USB peripheral
pub trait Usb_Peripheral {
    fn init(&self);
    fn attach(&self);
    fn reset(&self);

    fn poll(&self);

    fn max_endpoints(&self) -> uint;

    fn queue_next(&mut self, uint, bool, &Stream_Handler);
    fn set_address(&self, u8);
    fn ep_enable(&self, uint, Endpoint_Type);
    fn ep_stall(&self, uint);
    fn ep_unstall(&self, uint);
}

/// The trait for the endpoint handlers
pub trait Endpoint_Handler {
//    fn handle_setup(&self, &Usb_Module, uint, uint) -> bool;
//    fn handle_out(&self, &Usb_Module, uint, uint) -> bool;
//    fn handle_in(&self, &Usb_Module, uint, uint) -> bool;

    fn on_reset(&mut self, &'static mut Usb_Module);

    fn on_token(&mut self, &'static mut Usb_Module, uint, bool, Token_Pid, uint);
}

/// Enum for USB state machine
enum Usb_State {
    Unattached,
    Attached,
    Default,
    Set_Address,
    Address,
    Configured,
    Suspended
}

pub struct Usb_Module {
    peripheral: &'static mut Usb_Peripheral,
    state: Usb_State,
    handler: Ep0_Handler,
}

impl Usb_Module {
    pub fn new(peripheral: &'static mut Usb_Peripheral) -> &'static mut Usb_Module {
        // Abort if already initialised
        if Usb_Module::is_ready() {
            abort();
        }

        // Create struct and store as singleton
        let module = Usb_Module {
            peripheral: peripheral,
            state: Unattached,
            handler: Ep0_Handler::new(64)
        };
        unsafe {
            USB_MODULE = Some(module);
        }

        Usb_Module::get()
    }

    /// Return true if the singleton is ready
    pub fn is_ready() -> bool {
        unsafe {
            match USB_MODULE {
                Some(_) => true,
                None => false
            }
        }
    }

    /// Get the singleton object
    pub fn get() -> &'static mut Usb_Module {
        unsafe {
            match USB_MODULE {
                Some(ref mut module) => module,
                None => abort()
            }
        }
    }

    /// Enable and setup USB device
    pub fn init(&mut self) {
        // Initialise the low level device
        self.peripheral.init();

        // Attach and wait for reset
        self.peripheral.attach();

        // Set state to attached
        self.state = Attached;
    }

    /// React to USB bus reset
    pub fn on_reset(&'static mut self) {
        // Reset peripheral
        self.peripheral.reset();

        // Prepare endpoint 0
        self.handler.on_reset(self);

        // Set state to default
        self.state = Default;
    }

    /// Handle after STALL has been sent
    pub fn on_stall(&'static mut self) {
        // Ensure EP0 isn't stalled

        // Pass stall event to other handlers
        // Prepare endpoint 0 (if ep0 has stalled)
        // TODO: Add call for EP0 here
    }

    /// Handle transaction
    pub fn on_token(&'static mut self, endpoint: uint, is_tx: bool, pid: uint, length: uint) {
        // Get the handler for the endpoint
        // TODO: Support more than EP0
        let handler = &mut self.handler;

        // Convert pid into enum
        let pid = Token_Pid::from_u8(pid as u8);

        // Pass info to handler
        handler.on_token(self, endpoint, is_tx, pid, length);
    }

    /// Enable the endpoint for given transactions
    pub fn enable_ep(&mut self, endpoint: uint, transfer: Endpoint_Type) {
        // Tell peripheral to enable the endpoint
        self.peripheral.ep_enable(endpoint, transfer);
    }

    /// Set the STALL flag on an endpoint
    pub fn stall_ep(&self, endpoint: uint) {
        self.peripheral.ep_stall(endpoint);
    }

    /// Prepare to receive transaction on endpoint
    /// Takes endpoint number and stream handler
    pub fn queue_rx(&mut self, endpoint: uint, stream: &Stream_Handler) {
        // Pass to peripheral
        self.peripheral.queue_next(endpoint, false, stream);
    }

    /// Prepare to transmit transaction on endpoint
    pub fn queue_tx(&self, endpoint: uint, data1: bool, buf: &mut [u8]) {

    }
}

/// Prepare endpoint 0
fn setup() {

}

/// Struct with endpoint info
pub struct Ep_State {
    ep: u8,
    is_setup: bool,
    data: ~Vec<u8>,
    remaining: u16,
    max_size: u16,
    callback: fn (~Vec<u8>)
}

/// PIDs for tokens
pub enum Token_Pid {
    Out         = 0b0001,
    In          = 0b1001,
    Sof         = 0b0101,
    Setup       = 0b1101,

    Data0       = 0b0011,
    Data1       = 0b1011,
    Data2       = 0b0111,
    Mdata       = 0b1111,

    Ack         = 0b0010,
    Nak         = 0b1010,
    Stall       = 0b1110,
    Nyet        = 0b0110,

    Pre         = 0b1100,
    Split       = 0b1000,
    Ping        = 0b0100,
    Reserved    = 0b0000,
}

impl Token_Pid {
    pub fn from_u8(num: u8) -> Token_Pid {
        unsafe {
            core::mem::transmute(num & 0xF)
        }
    }
}

/// Handle a transaction (called after TOKDNE set)
pub fn handle_transaction(ep: u8, tx: bool, odd: bool, pid: u8, len: u16) {
    // Retrieve endpoint info struct
    let ep_state = match get_ep_state(ep, tx, odd) {
        Some(state) => state,
        None        => core::fail::abort()
    };

}

/// Handles a setup token
fn handle_setup(state: &mut Ep_State, len: u16) {
    // Check ep state is expecting a SETUP
    if state.is_setup {
        // Queue data same as an out token
        handle_out(state, len);
    } else {
        stall_ep(state.ep);
    }

    // Tell the peripheral to resume
    //freescale::usb::resume();
}

/// Handles an out token
fn handle_out(state: &mut Ep_State, len: u16) {
    // Toggle data01

    // Subtract remaining bytes
    state.remaining -= len;

    // Decide if more bytes are expected
    if state.remaining <= 9 || len < state.max_size {
        // Toggle data01
        // Update buffer address/copy data out
        queue_next(state);
    } else {
        // Call the closure/function
        //state.callback(state.data);
    }
}

/// Handles an in token
fn handle_in(state: &mut Ep_State, len: u16) {

}

/// Setup the state and BDT ready for OUT/SETUP token
pub fn prepare_out(state: &mut Ep_State, buf: ~[u8], len: u16, callback: fn (~[u8], u16)) {

}

/// Transfer the information in the state struct to the BDT
fn queue_next(state: &mut Ep_State) {

}

/// Gets the state for the specified endpoint
pub fn get_ep_state(ep: u8, tx: bool, odd: bool) -> Option<&mut Ep_State> {
    None
}

/// Stall the selected endpoint
fn stall_ep(ep: u8) {
    //freescale::usb::stall_ep(ep);
}
<|endoftext|>


<commit_before>namespace {
  // before struct
  pub struct MyStruct {
    member : i32 // member line
  } // last struct line

  // before impl MyStruct
  impl MyStruct {} // newline between { and }
  // some line

  // before impl MyStruct
  impl MyStruct {} // newline after }
  // some line
}<commit_msg>added more auto indent test<commit_after>namespace {
  // before struct
  pub struct MyStruct {
    member : i32 // member line
  } // last struct line

  // before impl MyStruct
  impl MyStruct {} // newline between { and }
  // some line

  // before impl MyStruct
  impl MyStruct {} // newline after }
  // some line
}

fn main() {
    let c = Circle { x: 0.0, y: 0.0, radius: 2.0 };
    println!("{}", c.area());
}<|endoftext|>


<commit_before>use std::collections::HashMap;

use conduit::{Request, Response};
use conduit_router::RequestParams;
use pg::GenericConnection;
use pg::rows::Row;
use rustc_serialize::json;
use semver;
use time::Duration;
use time::Timespec;
use url;

use {Model, Crate, User};
use app::RequestApp;
use db::RequestTransaction;
use dependency::{Dependency, EncodableDependency, Kind};
use download::{VersionDownload, EncodableVersionDownload};
use git;
use upload;
use user::RequestUser;
use owner::{rights, Rights};
use util::{RequestUtils, CargoResult, ChainError, internal, human};

#[derive(Clone)]
pub struct Version {
    pub id: i32,
    pub crate_id: i32,
    pub num: semver::Version,
    pub updated_at: Timespec,
    pub created_at: Timespec,
    pub downloads: i32,
    pub features: HashMap<String, Vec<String>>,
    pub yanked: bool,
}

pub enum Author {
    User(User),
    Name(String),
}

#[derive(RustcEncodable, RustcDecodable)]
pub struct EncodableVersion {
    pub id: i32,
    pub krate: String,
    pub num: String,
    pub dl_path: String,
    pub updated_at: String,
    pub created_at: String,
    pub downloads: i32,
    pub features: HashMap<String, Vec<String>>,
    pub yanked: bool,
    pub links: VersionLinks,
}

#[derive(RustcEncodable, RustcDecodable)]
pub struct VersionLinks {
    pub dependencies: String,
    pub version_downloads: String,
    pub authors: String,
}

impl Version {
    pub fn find_by_num(conn: &GenericConnection,
                       crate_id: i32,
                       num: &semver::Version)
                       -> CargoResult<Option<Version>> {
        let num = num.to_string();
        let stmt = conn.prepare("SELECT * FROM versions \
                                      WHERE crate_id = $1 AND num = $2")?;
        let rows = stmt.query(&[&crate_id, &num])?;
        Ok(rows.iter().next().map(|r| Model::from_row(&r)))
    }

    pub fn insert(conn: &GenericConnection,
                  crate_id: i32,
                  num: &semver::Version,
                  features: &HashMap<String, Vec<String>>,
                  authors: &[String])
                  -> CargoResult<Version> {
        let num = num.to_string();
        let features = json::encode(features).unwrap();
        let stmt = conn.prepare("INSERT INTO versions \
                                      (crate_id, num, features) \
                                      VALUES ($1, $2, $3) \
                                      RETURNING *")?;
        let rows = stmt.query(&[&crate_id, &num, &features])?;
        let ret: Version = Model::from_row(&rows.iter().next().chain_error(|| {
            internal("no version returned")
        })?);
        for author in authors.iter() {
            ret.add_author(conn, &author)?;
        }
        Ok(ret)
    }

    pub fn valid(version: &str) -> bool {
        semver::Version::parse(version).is_ok()
    }

    pub fn encodable(self, crate_name: &str) -> EncodableVersion {
        let Version { id, crate_id: _, num, updated_at, created_at,
                      downloads, features, yanked } = self;
        let num = num.to_string();
        EncodableVersion {
            dl_path: format!("/api/v1/crates/{}/{}/download", crate_name, num),
            num: num.clone(),
            id: id,
            krate: crate_name.to_string(),
            updated_at: ::encode_time(updated_at),
            created_at: ::encode_time(created_at),
            downloads: downloads,
            features: features,
            yanked: yanked,
            links: VersionLinks {
                dependencies: format!("/api/v1/crates/{}/{}/dependencies",
                                      crate_name, num),
                version_downloads: format!("/api/v1/crates/{}/{}/downloads",
                                           crate_name, num),
                authors: format!("/api/v1/crates/{}/{}/authors", crate_name, num),
            },
        }
    }

    /// Add a dependency to this version, returning both the dependency and the
    /// crate that the dependency points to
    pub fn add_dependency(&mut self,
                          conn: &GenericConnection,
                          dep: &upload::CrateDependency)
                          -> CargoResult<(Dependency, Crate)> {
        let name = &dep.name;
        let krate = Crate::find_by_name(conn, name).map_err(|_| {
            human(format!("no known crate named `{}`", &**name))
        })?;
        if dep.version_req.0 == semver::VersionReq::parse("*").unwrap() {
            return Err(human(format!("wildcard (`*`) dependency constraints are not allowed \
                                      on crates.io. See http://doc.crates.io/faq.html#can-\
                                      libraries-use--as-a-version-for-their-dependencies for more \
                                      information")));
        }
        let features: Vec<String> = dep.features.iter().map(|s| {
            s[..].to_string()
        }).collect();
        let dep = Dependency::insert(conn, self.id, krate.id,
                                     &*dep.version_req,
                                     dep.kind.unwrap_or(Kind::Normal),
                                     dep.optional,
                                     dep.default_features,
                                     &features,
                                     &dep.target)?;
        Ok((dep, krate))
    }

    /// Returns (dependency, crate dependency name)
    pub fn dependencies(&self, conn: &GenericConnection)
                        -> CargoResult<Vec<(Dependency, String)>> {
        let stmt = conn.prepare("SELECT dependencies.*,
                                             crates.name AS crate_name
                                      FROM dependencies
                                      LEFT JOIN crates
                                        ON crates.id = dependencies.crate_id
                                      WHERE dependencies.version_id = $1")?;
        let rows = stmt.query(&[&self.id])?;
        Ok(rows.iter().map(|r| {
            (Model::from_row(&r), r.get("crate_name"))
        }).collect())
    }

    pub fn authors(&self, conn: &GenericConnection) -> CargoResult<Vec<Author>> {
        let stmt = conn.prepare("SELECT * FROM version_authors
                                       WHERE version_id = $1")?;
        let rows = stmt.query(&[&self.id])?;
        let mut authors = rows.into_iter().map(|row| {
            let user_id: Option<i32> = row.get("user_id");
            let name: String = row.get("name");
            Ok(match user_id {
                Some(id) => Author::User(User::find(conn, id)?),
                None => Author::Name(name),
            })
        }).collect::<CargoResult<Vec<Author>>>()?;
        authors.sort_by(|ref a, ref b| a.name().cmp(&b.name()));
        Ok(authors)
    }

    pub fn add_author(&self,
                      conn: &GenericConnection,
                      name: &str) -> CargoResult<()> {
        println!("add author: {}", name);
        // TODO: at least try to link `name` to a pre-existing user
        conn.execute("INSERT INTO version_authors (version_id, name)
                           VALUES ($1, $2)", &[&self.id, &name])?;
        Ok(())
    }

    pub fn yank(&self, conn: &GenericConnection, yanked: bool) -> CargoResult<()> {
        conn.execute("UPDATE versions SET yanked = $1 WHERE id = $2",
                     &[&yanked, &self.id])?;
        Ok(())
    }
}

impl Model for Version {
    fn from_row(row: &Row) -> Version {
        let num: String = row.get("num");
        let features: Option<String> = row.get("features");
        let features = features.map(|s| {
            json::decode(&s).unwrap()
        }).unwrap_or_else(|| HashMap::new());
        Version {
            id: row.get("id"),
            crate_id: row.get("crate_id"),
            num: semver::Version::parse(&num).unwrap(),
            updated_at: row.get("updated_at"),
            created_at: row.get("created_at"),
            downloads: row.get("downloads"),
            features: features,
            yanked: row.get("yanked"),
        }
    }
    fn table_name(_: Option<Version>) -> &'static str { "versions" }
}

impl Author {
    fn name(&self) -> Option<&str> {
        match self {
            &Author::Name(ref n) => {Some(&n)},
            &Author::User(ref u) => {u.name.as_ref().map(String::as_str)}
        }
    }
}

/// Handles the `GET /versions` route.
pub fn index(req: &mut Request) -> CargoResult<Response> {
    let conn = req.tx()?;

    // Extract all ids requested.
    let query = url::form_urlencoded::parse(req.query_string().unwrap_or("")
                                               .as_bytes());
    let ids = query.filter_map(|(ref a, ref b)| {
        if *a == "ids[]" {
            b.parse().ok()
        } else {
            None
        }
    }).collect::<Vec<i32>>();

    // Load all versions
    //
    // TODO: can rust-postgres do this for us?
    let mut versions = Vec::new();
    if ids.len() > 0 {
        let stmt = conn.prepare("\
            SELECT versions.*, crates.name AS crate_name
              FROM versions
            LEFT JOIN crates ON crates.id = versions.crate_id
            WHERE versions.id = ANY($1)
        ")?;
        for row in stmt.query(&[&ids])?.iter() {
            let v: Version = Model::from_row(&row);
            let crate_name: String = row.get("crate_name");
            versions.push(v.encodable(&crate_name));
        }
    }

    #[derive(RustcEncodable)]
    struct R { versions: Vec<EncodableVersion> }
    Ok(req.json(&R { versions: versions }))
}

/// Handles the `GET /versions/:version_id` route.
pub fn show(req: &mut Request) -> CargoResult<Response> {
    let (version, krate) = match req.params().find("crate_id") {
        Some(..) => version_and_crate(req)?,
        None => {
            let id = &req.params()["version_id"];
            let id = id.parse().unwrap_or(0);
            let conn = req.tx()?;
            let version = Version::find(&*conn, id)?;
            let krate = Crate::find(&*conn, version.crate_id)?;
            (version, krate)
        }
    };

    #[derive(RustcEncodable)]
    struct R { version: EncodableVersion }
    Ok(req.json(&R { version: version.encodable(&krate.name) }))
}

fn version_and_crate(req: &mut Request) -> CargoResult<(Version, Crate)> {
    let crate_name = &req.params()["crate_id"];
    let semver = &req.params()["version"];
    let semver = semver::Version::parse(semver).map_err(|_| {
        human(format!("invalid semver: {}", semver))
    })?;
    let tx = req.tx()?;
    let krate = Crate::find_by_name(tx, crate_name)?;
    let version = Version::find_by_num(tx, krate.id, &semver)?;
    let version = version.chain_error(|| {
        human(format!("crate `{}` does not have a version `{}`",
                      crate_name, semver))
    })?;
    Ok((version, krate))
}

/// Handles the `GET /crates/:crate_id/:version/dependencies` route.
pub fn dependencies(req: &mut Request) -> CargoResult<Response> {
    let (version, _) = version_and_crate(req)?;
    let tx = req.tx()?;
    let deps = version.dependencies(tx)?;
    let deps = deps.into_iter().map(|(dep, crate_name)| {
        dep.encodable(&crate_name, None)
    }).collect();

    #[derive(RustcEncodable)]
    struct R { dependencies: Vec<EncodableDependency> }
    Ok(req.json(&R{ dependencies: deps }))
}

/// Handles the `GET /crates/:crate_id/:version/downloads` route.
pub fn downloads(req: &mut Request) -> CargoResult<Response> {
    let (version, _) = version_and_crate(req)?;

    let tx = req.tx()?;
    let cutoff_date = ::now() + Duration::days(-90);
    let stmt = tx.prepare("SELECT * FROM version_downloads
                                WHERE date > $1 AND version_id = $2
                                ORDER BY date ASC")?;
    let mut downloads = Vec::new();
    for row in stmt.query(&[&cutoff_date, &version.id])?.iter() {
        let download: VersionDownload = Model::from_row(&row);
        downloads.push(download.encodable());
    }

    #[derive(RustcEncodable)]
    struct R { version_downloads: Vec<EncodableVersionDownload> }
    Ok(req.json(&R{ version_downloads: downloads }))
}

/// Handles the `GET /crates/:crate_id/:version/authors` route.
pub fn authors(req: &mut Request) -> CargoResult<Response> {
    let (version, _) = version_and_crate(req)?;
    let tx = req.tx()?;
    let (mut users, mut names) = (Vec::new(), Vec::new());
    for author in version.authors(tx)?.into_iter() {
        match author {
            Author::User(u) => users.push(u.encodable()),
            Author::Name(n) => names.push(n),
        }
    }

    #[derive(RustcEncodable)]
    struct R { users: Vec<::user::EncodableUser>, meta: Meta }
    #[derive(RustcEncodable)]
    struct Meta { names: Vec<String> }
    Ok(req.json(&R{ users: users, meta: Meta { names: names } }))
}

/// Handles the `DELETE /crates/:crate_id/:version/yank` route.
pub fn yank(req: &mut Request) -> CargoResult<Response> {
    modify_yank(req, true)
}

/// Handles the `PUT /crates/:crate_id/:version/unyank` route.
pub fn unyank(req: &mut Request) -> CargoResult<Response> {
    modify_yank(req, false)
}

fn modify_yank(req: &mut Request, yanked: bool) -> CargoResult<Response> {
    let (version, krate) = version_and_crate(req)?;
    let user = req.user()?;
    let tx = req.tx()?;
    let owners = krate.owners(tx)?;
    if rights(req.app(), &owners, &user)? < Rights::Publish {
        return Err(human("must already be an owner to yank or unyank"))
    }

    if version.yanked != yanked {
        version.yank(tx, yanked)?;
        git::yank(&**req.app(), &krate.name, &version.num, yanked)?;
    }

    #[derive(RustcEncodable)]
    struct R { ok: bool }
    Ok(req.json(&R{ ok: true }))
}
<commit_msg>Sort authors in sql add a todo for why this works<commit_after>use std::collections::HashMap;

use conduit::{Request, Response};
use conduit_router::RequestParams;
use pg::GenericConnection;
use pg::rows::Row;
use rustc_serialize::json;
use semver;
use time::Duration;
use time::Timespec;
use url;

use {Model, Crate, User};
use app::RequestApp;
use db::RequestTransaction;
use dependency::{Dependency, EncodableDependency, Kind};
use download::{VersionDownload, EncodableVersionDownload};
use git;
use upload;
use user::RequestUser;
use owner::{rights, Rights};
use util::{RequestUtils, CargoResult, ChainError, internal, human};

#[derive(Clone)]
pub struct Version {
    pub id: i32,
    pub crate_id: i32,
    pub num: semver::Version,
    pub updated_at: Timespec,
    pub created_at: Timespec,
    pub downloads: i32,
    pub features: HashMap<String, Vec<String>>,
    pub yanked: bool,
}

pub enum Author {
    User(User), //TODO: not used. this should be removed.
    Name(String),
}

#[derive(RustcEncodable, RustcDecodable)]
pub struct EncodableVersion {
    pub id: i32,
    pub krate: String,
    pub num: String,
    pub dl_path: String,
    pub updated_at: String,
    pub created_at: String,
    pub downloads: i32,
    pub features: HashMap<String, Vec<String>>,
    pub yanked: bool,
    pub links: VersionLinks,
}

#[derive(RustcEncodable, RustcDecodable)]
pub struct VersionLinks {
    pub dependencies: String,
    pub version_downloads: String,
    pub authors: String,
}

impl Version {
    pub fn find_by_num(conn: &GenericConnection,
                       crate_id: i32,
                       num: &semver::Version)
                       -> CargoResult<Option<Version>> {
        let num = num.to_string();
        let stmt = conn.prepare("SELECT * FROM versions \
                                      WHERE crate_id = $1 AND num = $2")?;
        let rows = stmt.query(&[&crate_id, &num])?;
        Ok(rows.iter().next().map(|r| Model::from_row(&r)))
    }

    pub fn insert(conn: &GenericConnection,
                  crate_id: i32,
                  num: &semver::Version,
                  features: &HashMap<String, Vec<String>>,
                  authors: &[String])
                  -> CargoResult<Version> {
        let num = num.to_string();
        let features = json::encode(features).unwrap();
        let stmt = conn.prepare("INSERT INTO versions \
                                      (crate_id, num, features) \
                                      VALUES ($1, $2, $3) \
                                      RETURNING *")?;
        let rows = stmt.query(&[&crate_id, &num, &features])?;
        let ret: Version = Model::from_row(&rows.iter().next().chain_error(|| {
            internal("no version returned")
        })?);
        for author in authors.iter() {
            ret.add_author(conn, &author)?;
        }
        Ok(ret)
    }

    pub fn valid(version: &str) -> bool {
        semver::Version::parse(version).is_ok()
    }

    pub fn encodable(self, crate_name: &str) -> EncodableVersion {
        let Version { id, crate_id: _, num, updated_at, created_at,
                      downloads, features, yanked } = self;
        let num = num.to_string();
        EncodableVersion {
            dl_path: format!("/api/v1/crates/{}/{}/download", crate_name, num),
            num: num.clone(),
            id: id,
            krate: crate_name.to_string(),
            updated_at: ::encode_time(updated_at),
            created_at: ::encode_time(created_at),
            downloads: downloads,
            features: features,
            yanked: yanked,
            links: VersionLinks {
                dependencies: format!("/api/v1/crates/{}/{}/dependencies",
                                      crate_name, num),
                version_downloads: format!("/api/v1/crates/{}/{}/downloads",
                                           crate_name, num),
                authors: format!("/api/v1/crates/{}/{}/authors", crate_name, num),
            },
        }
    }

    /// Add a dependency to this version, returning both the dependency and the
    /// crate that the dependency points to
    pub fn add_dependency(&mut self,
                          conn: &GenericConnection,
                          dep: &upload::CrateDependency)
                          -> CargoResult<(Dependency, Crate)> {
        let name = &dep.name;
        let krate = Crate::find_by_name(conn, name).map_err(|_| {
            human(format!("no known crate named `{}`", &**name))
        })?;
        if dep.version_req.0 == semver::VersionReq::parse("*").unwrap() {
            return Err(human(format!("wildcard (`*`) dependency constraints are not allowed \
                                      on crates.io. See http://doc.crates.io/faq.html#can-\
                                      libraries-use--as-a-version-for-their-dependencies for more \
                                      information")));
        }
        let features: Vec<String> = dep.features.iter().map(|s| {
            s[..].to_string()
        }).collect();
        let dep = Dependency::insert(conn, self.id, krate.id,
                                     &*dep.version_req,
                                     dep.kind.unwrap_or(Kind::Normal),
                                     dep.optional,
                                     dep.default_features,
                                     &features,
                                     &dep.target)?;
        Ok((dep, krate))
    }

    /// Returns (dependency, crate dependency name)
    pub fn dependencies(&self, conn: &GenericConnection)
                        -> CargoResult<Vec<(Dependency, String)>> {
        let stmt = conn.prepare("SELECT dependencies.*,
                                             crates.name AS crate_name
                                      FROM dependencies
                                      LEFT JOIN crates
                                        ON crates.id = dependencies.crate_id
                                      WHERE dependencies.version_id = $1")?;
        let rows = stmt.query(&[&self.id])?;
        Ok(rows.iter().map(|r| {
            (Model::from_row(&r), r.get("crate_name"))
        }).collect())
    }

    pub fn authors(&self, conn: &GenericConnection) -> CargoResult<Vec<Author>> {
        let stmt = conn.prepare("SELECT * FROM version_authors
                                       WHERE version_id = $1
                                       ORDER BY name ASC")?;
        let rows = stmt.query(&[&self.id])?;
        rows.into_iter().map(|row| {
            let user_id: Option<i32> = row.get("user_id");
            let name: String = row.get("name");
            Ok(match user_id {
                Some(id) => Author::User(User::find(conn, id)?),
                None => Author::Name(name),
            })
        }).collect()
    }

    pub fn add_author(&self,
                      conn: &GenericConnection,
                      name: &str) -> CargoResult<()> {
        conn.execute("INSERT INTO version_authors (version_id, name)
                           VALUES ($1, $2)", &[&self.id, &name])?;
        Ok(())
    }

    pub fn yank(&self, conn: &GenericConnection, yanked: bool) -> CargoResult<()> {
        conn.execute("UPDATE versions SET yanked = $1 WHERE id = $2",
                     &[&yanked, &self.id])?;
        Ok(())
    }
}

impl Model for Version {
    fn from_row(row: &Row) -> Version {
        let num: String = row.get("num");
        let features: Option<String> = row.get("features");
        let features = features.map(|s| {
            json::decode(&s).unwrap()
        }).unwrap_or_else(|| HashMap::new());
        Version {
            id: row.get("id"),
            crate_id: row.get("crate_id"),
            num: semver::Version::parse(&num).unwrap(),
            updated_at: row.get("updated_at"),
            created_at: row.get("created_at"),
            downloads: row.get("downloads"),
            features: features,
            yanked: row.get("yanked"),
        }
    }
    fn table_name(_: Option<Version>) -> &'static str { "versions" }
}

/// Handles the `GET /versions` route.
pub fn index(req: &mut Request) -> CargoResult<Response> {
    let conn = req.tx()?;

    // Extract all ids requested.
    let query = url::form_urlencoded::parse(req.query_string().unwrap_or("")
                                               .as_bytes());
    let ids = query.filter_map(|(ref a, ref b)| {
        if *a == "ids[]" {
            b.parse().ok()
        } else {
            None
        }
    }).collect::<Vec<i32>>();

    // Load all versions
    //
    // TODO: can rust-postgres do this for us?
    let mut versions = Vec::new();
    if ids.len() > 0 {
        let stmt = conn.prepare("\
            SELECT versions.*, crates.name AS crate_name
              FROM versions
            LEFT JOIN crates ON crates.id = versions.crate_id
            WHERE versions.id = ANY($1)
        ")?;
        for row in stmt.query(&[&ids])?.iter() {
            let v: Version = Model::from_row(&row);
            let crate_name: String = row.get("crate_name");
            versions.push(v.encodable(&crate_name));
        }
    }

    #[derive(RustcEncodable)]
    struct R { versions: Vec<EncodableVersion> }
    Ok(req.json(&R { versions: versions }))
}

/// Handles the `GET /versions/:version_id` route.
pub fn show(req: &mut Request) -> CargoResult<Response> {
    let (version, krate) = match req.params().find("crate_id") {
        Some(..) => version_and_crate(req)?,
        None => {
            let id = &req.params()["version_id"];
            let id = id.parse().unwrap_or(0);
            let conn = req.tx()?;
            let version = Version::find(&*conn, id)?;
            let krate = Crate::find(&*conn, version.crate_id)?;
            (version, krate)
        }
    };

    #[derive(RustcEncodable)]
    struct R { version: EncodableVersion }
    Ok(req.json(&R { version: version.encodable(&krate.name) }))
}

fn version_and_crate(req: &mut Request) -> CargoResult<(Version, Crate)> {
    let crate_name = &req.params()["crate_id"];
    let semver = &req.params()["version"];
    let semver = semver::Version::parse(semver).map_err(|_| {
        human(format!("invalid semver: {}", semver))
    })?;
    let tx = req.tx()?;
    let krate = Crate::find_by_name(tx, crate_name)?;
    let version = Version::find_by_num(tx, krate.id, &semver)?;
    let version = version.chain_error(|| {
        human(format!("crate `{}` does not have a version `{}`",
                      crate_name, semver))
    })?;
    Ok((version, krate))
}

/// Handles the `GET /crates/:crate_id/:version/dependencies` route.
pub fn dependencies(req: &mut Request) -> CargoResult<Response> {
    let (version, _) = version_and_crate(req)?;
    let tx = req.tx()?;
    let deps = version.dependencies(tx)?;
    let deps = deps.into_iter().map(|(dep, crate_name)| {
        dep.encodable(&crate_name, None)
    }).collect();

    #[derive(RustcEncodable)]
    struct R { dependencies: Vec<EncodableDependency> }
    Ok(req.json(&R{ dependencies: deps }))
}

/// Handles the `GET /crates/:crate_id/:version/downloads` route.
pub fn downloads(req: &mut Request) -> CargoResult<Response> {
    let (version, _) = version_and_crate(req)?;

    let tx = req.tx()?;
    let cutoff_date = ::now() + Duration::days(-90);
    let stmt = tx.prepare("SELECT * FROM version_downloads
                                WHERE date > $1 AND version_id = $2
                                ORDER BY date ASC")?;
    let mut downloads = Vec::new();
    for row in stmt.query(&[&cutoff_date, &version.id])?.iter() {
        let download: VersionDownload = Model::from_row(&row);
        downloads.push(download.encodable());
    }

    #[derive(RustcEncodable)]
    struct R { version_downloads: Vec<EncodableVersionDownload> }
    Ok(req.json(&R{ version_downloads: downloads }))
}

/// Handles the `GET /crates/:crate_id/:version/authors` route.
pub fn authors(req: &mut Request) -> CargoResult<Response> {
    let (version, _) = version_and_crate(req)?;
    let tx = req.tx()?;
    let (mut users, mut names) = (Vec::new(), Vec::new());
    for author in version.authors(tx)?.into_iter() {
        match author {
            Author::User(u) => users.push(u.encodable()),
            Author::Name(n) => names.push(n),
        }
    }

    #[derive(RustcEncodable)]
    struct R { users: Vec<::user::EncodableUser>, meta: Meta }
    #[derive(RustcEncodable)]
    struct Meta { names: Vec<String> }
    Ok(req.json(&R{ users: users, meta: Meta { names: names } }))
}

/// Handles the `DELETE /crates/:crate_id/:version/yank` route.
pub fn yank(req: &mut Request) -> CargoResult<Response> {
    modify_yank(req, true)
}

/// Handles the `PUT /crates/:crate_id/:version/unyank` route.
pub fn unyank(req: &mut Request) -> CargoResult<Response> {
    modify_yank(req, false)
}

fn modify_yank(req: &mut Request, yanked: bool) -> CargoResult<Response> {
    let (version, krate) = version_and_crate(req)?;
    let user = req.user()?;
    let tx = req.tx()?;
    let owners = krate.owners(tx)?;
    if rights(req.app(), &owners, &user)? < Rights::Publish {
        return Err(human("must already be an owner to yank or unyank"))
    }

    if version.yanked != yanked {
        version.yank(tx, yanked)?;
        git::yank(&**req.app(), &krate.name, &version.num, yanked)?;
    }

    #[derive(RustcEncodable)]
    struct R { ok: bool }
    Ok(req.json(&R{ ok: true }))
}
<|endoftext|>


<commit_before>use memmem::{Searcher, TwoWaySearcher};
use crossbeam::sync::MsQueue;

const XML_PREFIX: &'static [u8] = b"<?xml version=";
const XML_SUFFIX: &'static [u8] = b"</plist>";

pub struct BuffersPool {
    queue: MsQueue<Vec<u8>>,
}

impl BuffersPool {
    pub fn acquire(&self) -> Vec<u8> {
        if let Some(mut vec) = self.queue.try_pop() {
            vec.clear();
            vec
        } else {
            Vec::new()
        }
    }

    pub fn release(&self, vec: Vec<u8>) {
        self.queue.push(vec);
    }
}

impl Default for BuffersPool {
    fn default() -> Self {
        BuffersPool { queue: MsQueue::new() }
    }
}

pub struct Context {
    prefix_searcher: TwoWaySearcher<'static>,
    suffix_searcher: TwoWaySearcher<'static>,
    pub buffers_pool: BuffersPool,
}

impl Context {
    /// Returns a plist content in a `data`.
    pub fn find_plist<'b>(&self, data: &'b [u8]) -> Option<&'b [u8]> {
        let start_i = self.prefix_searcher.search_in(data);
        let end_i = self.suffix_searcher.search_in(data).map(|i| i + XML_SUFFIX.len());

        if let (Some(start_i), Some(end_i)) = (start_i, end_i) {
            if end_i <= data.len() {
                return Some(&data[start_i..end_i]);
            }
        }

        None
    }
}

impl Default for Context {
    fn default() -> Self {
        Context {
            prefix_searcher: TwoWaySearcher::new(XML_PREFIX),
            suffix_searcher: TwoWaySearcher::new(XML_SUFFIX),
            buffers_pool: BuffersPool::default(),
        }
    }
}

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

    #[test]
    fn test_find_plist() {
        let context = Context::default();
        let data: &[u8] = b"<?xml version=</plist>";
        expect!(context.find_plist(&data)).to(be_some().value(data));

        let data: &[u8] = b"   <?xml version=</plist>   ";
        expect!(context.find_plist(&data)).to(be_some().value(b"<?xml version=</plist>"));
    }

    #[test]
    fn test_buffers_pool() {
        let pool = BuffersPool::default();
        let mut buf = pool.acquire();
        expect!(buf.iter()).to(be_empty());
        buf.push(1);
        buf.push(2);
        expect!(buf.iter()).to(have_count(2));
        pool.release(buf);

        let buf = pool.acquire();
        expect!(buf.iter()).to(be_empty());
        expect!(buf.capacity()).to(be_greater_than(0));
    }
}
<commit_msg>Replace 'XML_' by 'PLIST_'.<commit_after>use memmem::{Searcher, TwoWaySearcher};
use crossbeam::sync::MsQueue;

const PLIST_PREFIX: &'static [u8] = b"<?xml version=";
const PLIST_SUFFIX: &'static [u8] = b"</plist>";

pub struct BuffersPool {
    queue: MsQueue<Vec<u8>>,
}

impl BuffersPool {
    pub fn acquire(&self) -> Vec<u8> {
        if let Some(mut vec) = self.queue.try_pop() {
            vec.clear();
            vec
        } else {
            Vec::new()
        }
    }

    pub fn release(&self, vec: Vec<u8>) {
        self.queue.push(vec);
    }
}

impl Default for BuffersPool {
    fn default() -> Self {
        BuffersPool { queue: MsQueue::new() }
    }
}

pub struct Context {
    prefix_searcher: TwoWaySearcher<'static>,
    suffix_searcher: TwoWaySearcher<'static>,
    pub buffers_pool: BuffersPool,
}

impl Context {
    /// Returns a plist content in a `data`.
    pub fn find_plist<'b>(&self, data: &'b [u8]) -> Option<&'b [u8]> {
        let start_i = self.prefix_searcher.search_in(data);
        let end_i = self.suffix_searcher.search_in(data).map(|i| i + PLIST_SUFFIX.len());

        if let (Some(start_i), Some(end_i)) = (start_i, end_i) {
            if end_i <= data.len() {
                return Some(&data[start_i..end_i]);
            }
        }

        None
    }
}

impl Default for Context {
    fn default() -> Self {
        Context {
            prefix_searcher: TwoWaySearcher::new(PLIST_PREFIX),
            suffix_searcher: TwoWaySearcher::new(PLIST_SUFFIX),
            buffers_pool: BuffersPool::default(),
        }
    }
}

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

    #[test]
    fn test_find_plist() {
        let context = Context::default();
        let data: &[u8] = b"<?xml version=</plist>";
        expect!(context.find_plist(&data)).to(be_some().value(data));

        let data: &[u8] = b"   <?xml version=</plist>   ";
        expect!(context.find_plist(&data)).to(be_some().value(b"<?xml version=</plist>"));
    }

    #[test]
    fn test_buffers_pool() {
        let pool = BuffersPool::default();
        let mut buf = pool.acquire();
        expect!(buf.iter()).to(be_empty());
        buf.push(1);
        buf.push(2);
        expect!(buf.iter()).to(have_count(2));
        pool.release(buf);

        let buf = pool.acquire();
        expect!(buf.iter()).to(be_empty());
        expect!(buf.capacity()).to(be_greater_than(0));
    }
}
<|endoftext|>


<commit_before>use std::cmp;
use std::collections::TrieMap;

use Crdt;

/// A grow-only counter.
///
/// `GCounter` monotonically increases across increment operations.
#[deriving(Show)]
pub struct GCounter {
    replica_id: uint,
    counts: TrieMap<u64>
}

pub struct GCounterIncrement {
    replica_id: uint,
    amount: u64
}

impl GCounter {

    /// Create a new grow-only counter with the provided replica id and an
    /// initial count of 0.
    ///
    /// ##### Example
    ///
    /// ```
    /// use crdt::counter::GCounter;
    ///
    /// let mut counter = GCounter::new(42);
    /// assert_eq!(0, counter.count());
    /// ```
    pub fn new(replica_id: uint) -> GCounter {
        GCounter { replica_id: replica_id, counts: TrieMap::new() }
    }

    /// Get the current count of the counter.
    ///
    /// ##### Example
    ///
    /// ```
    /// # use crdt::counter::GCounter;
    /// let counter = GCounter::new(42);
    /// println!("Current counter value: {}", counter.count());
    /// ```
    pub fn count(& self) -> u64 {
        self.counts.values().fold(0, |a, &b| a + b)
    }

    /// Increment the counter by `amount`.
    ///
    /// ##### Example
    ///
    /// ```
    /// # use crdt::counter::GCounter;
    /// let mut counter = GCounter::new(42);
    /// assert_eq!(0, counter.count());
    /// counter.increment(13);
    /// assert_eq!(13, counter.count());
    /// ```
    ///
    /// ##### Overflow
    ///
    /// `GCounter` can overflow exactly as if it were a `u64`, e.g.
    ///
    /// ```
    /// # use std::u64;
    /// # use crdt::counter::GCounter;
    /// let mut counter = GCounter::new(42);
    /// counter.increment(u64::MAX);
    /// assert_eq!(u64::MAX, counter.count());
    /// counter.increment(1);
    /// assert_eq!(0, counter.count());
    /// ```
    pub fn increment(&mut self, amount: u64) -> GCounterIncrement {
        let operation = GCounterIncrement { replica_id: self.replica_id, amount: amount };
        self.apply(&operation);
        operation
    }
}

impl Crdt<GCounterIncrement> for GCounter {

    /// Merge a replica into this counter.
    ///
    /// This method is used to perform state-based replication.
    ///
    /// ##### Example
    ///
    /// ```
    /// # use crdt::counter::GCounter;
    /// use crdt::Crdt;
    ///
    /// let mut local = GCounter::new(42);
    /// let mut remote = GCounter::new(43);
    ///
    /// local.increment(12);
    /// remote.increment(13);
    ///
    /// local.merge(&remote);
    /// assert_eq!(25, local.count());
    /// ```
    fn merge(&mut self, other: &GCounter) {
        for (replica_id, other_count) in other.counts.iter() {
            let count = match self.counts.find_mut(&replica_id) {
                Some(self_count) => cmp::max(*self_count, *other_count),
                None => *other_count
            };
            self.counts.insert(replica_id, count);
        }
    }

    /// Apply an increment operation to this counter.
    ///
    /// This method is used to perform operation-based replication.
    ///
    /// ##### Example
    ///
    /// ```
    /// # use crdt::counter::GCounter;
    /// # use crdt::Crdt;
    /// let mut local = GCounter::new(42);
    /// let mut remote = GCounter::new(43);
    ///
    /// let op = remote.increment(13);
    ///
    /// local.apply(&op);
    /// assert_eq!(13, local.count());
    /// ```
    fn apply(&mut self, operation: &GCounterIncrement) {
        let count = match self.counts.find_mut(&operation.replica_id) {
            Some(self_count) => *self_count + operation.amount,
            None => operation.amount
        };
        self.counts.insert(operation.replica_id, count);
    }

    fn replica_id(&self) -> uint {
        self.replica_id
    }
}

impl PartialEq for GCounter {
    fn eq(&self, other: &GCounter) -> bool {
        self.counts == other.counts
    }
}

impl Eq for GCounter {}

impl PartialOrd for GCounter {
    fn partial_cmp(&self, other: &GCounter) -> Option<Ordering> {

        /// Compares `a` to `b` based on replica counts.
        ///
        /// Precondition: `a.counts.len() <= b.counts.len()`
        fn a_gt_b(a: &GCounter, b: &GCounter) -> bool {
            for (replica_id, a_count) in a.counts.iter() {
                match b.counts.find(&replica_id) {
                    Some(b_count) if a_count > b_count => return true,
                    None => return true,
                    _ => ()
                }
            }
            false
        }

        let (self_gt_other, other_gt_self) =
            match self.counts.len().cmp(&other.counts.len()) {
                Less    => (a_gt_b(self, other), true),
                Greater => (true, a_gt_b(other, self)),
                Equal   => (a_gt_b(self, other), a_gt_b(other, self))
            };

        match (self_gt_other, other_gt_self) {
            (true, true)   => None,
            (true, false)  => Some(Greater),
            (false, true)  => Some(Less),
            (false, false) => Some(Equal)
        }
    }
}

#[deriving(Show)]
pub struct PNCounter {
    replica_id: uint,
    counts: TrieMap<(u32, u32)>
}

pub struct PNCounterOperation {
    replica_id: uint,
    amount: i64
}

impl PNCounter {

    pub fn new(replica_id: uint) -> PNCounter {
        PNCounter { replica_id: replica_id, counts: TrieMap::new() }
    }

    pub fn count(& self) -> i64 {
        self.counts.values().fold(0, |acc, &(p, n)| acc + (p as i64 - n as i64))
    }

    pub fn increment(&mut self, amount: i64) -> PNCounterOperation {
        let operation = PNCounterOperation { replica_id: self.replica_id, amount: amount };
        self.apply(&operation);
        operation
    }

    pub fn merge(&mut self, other: &PNCounter) {
        for (replica_id, other_count) in other.counts.iter() {
            let count = match self.counts.find_mut(&replica_id) {
                Some(self_count) => cmp::max(*self_count, *other_count),
                None => *other_count
            };
            self.counts.insert(replica_id, count);
        }
    }

    pub fn apply(&mut self, operation: &PNCounterOperation) {
        let (p_amount, n_amount) =
            if operation.amount > 0 { (operation.amount as u32, 0) } else { (0, (-operation.amount) as u32) };

        let count = match self.counts.find_mut(&operation.replica_id) {
            Some(&(self_p, self_n)) => (self_p + p_amount, self_n + n_amount),
            None => (p_amount, n_amount)
        };
        self.counts.insert(operation.replica_id, count);
    }
}

#[cfg(test)]
mod test {

    use Crdt;
    use counter::GCounter;

    #[test]
    fn g_counter_create() {
        let counter = GCounter::new(0);
        assert_eq!(0, counter.count());
    }

    #[test]
    fn g_counter_increment() {
        let mut counter = GCounter::new(42);
        assert_eq!(0, counter.count());
        counter.increment(1);
        assert_eq!(1, counter.count());
        counter.increment(2);
        assert_eq!(3, counter.count());
        counter.increment(3);
        assert_eq!(6, counter.count());
    }

    #[test]
    fn g_counter_merge() {
        let mut a = GCounter::new(1);
        let mut b = GCounter::new(2);

        a.increment(13);
        b.increment(17);

        a.merge(&b);
        b.merge(&a);
        assert_eq!(30, a.count());
        assert_eq!(30, b.count());
    }

    #[test]
    fn g_counter_apply() {
        let mut a = GCounter::new(1);
        let mut b = GCounter::new(2);

        let ref a_op_1 = a.increment(5);
        let ref a_op_2 = a.increment(8);
        let ref b_op = b.increment(17);

        a.apply(b_op);
        b.apply(a_op_1);
        b.apply(a_op_2);
        assert_eq!(30, a.count());
        assert_eq!(30, b.count());
    }

    #[test]
    fn g_counter_overflow() {
        //let mut a = GCounter::new(13);
        //let mut b = GCounter::new(2);

        //let ref a_op_1 = a.increment(5);
        //let ref a_op_2 = a.increment(8);
        //let ref b_op = b.increment(17);

        //a.apply(b_op);
        //b.apply(a_op_1);
        //b.apply(a_op_2);
        //assert_eq!(30, a.count());
        //assert_eq!(30, b.count());
    }
}
<commit_msg>Add PNCounter<commit_after>use std::cmp;
use std::collections::TrieMap;

use Crdt;

/// A grow-only counter.
///
/// `GCounter` monotonically increases across increment operations.
#[deriving(Show)]
pub struct GCounter {
    replica_id: uint,
    counts: TrieMap<u64>
}

/// An increment operation over `GCounter` CRDTs.
pub struct GCounterIncrement {
    replica_id: uint,
    amount: u64
}

impl GCounter {

    /// Create a new grow-only counter with the provided replica id and an
    /// initial count of 0.
    ///
    /// ##### Example
    ///
    /// ```
    /// use crdt::counter::GCounter;
    ///
    /// let mut counter = GCounter::new(42);
    /// assert_eq!(0, counter.count());
    /// ```
    pub fn new(replica_id: uint) -> GCounter {
        GCounter { replica_id: replica_id, counts: TrieMap::new() }
    }

    /// Get the current count of the counter.
    ///
    /// ##### Example
    ///
    /// ```
    /// # use crdt::counter::GCounter;
    /// let counter = GCounter::new(42);
    /// assert_eq!(0, counter.count());
    /// ```
    pub fn count(& self) -> u64 {
        self.counts.values().fold(0, |a, &b| a + b)
    }

    /// Increment the counter by `amount`.
    ///
    /// ##### Example
    ///
    /// ```
    /// # use crdt::counter::GCounter;
    /// let mut counter = GCounter::new(42);
    /// assert_eq!(0, counter.count());
    /// counter.increment(13);
    /// assert_eq!(13, counter.count());
    /// ```
    ///
    /// ##### Overflow
    ///
    /// Incrementing the count by more than `u64::MAX` is undefined behavior.
    /// The increment limit is globally shared across all replicas, and thus
    /// is not checked during local operations.
    ///
    /// ```
    /// # use std::u64;
    /// # use crdt::counter::GCounter;
    /// # use crdt::Crdt;
    /// let mut replica1 = GCounter::new(42);
    /// let mut replica2 = GCounter::new(43);
    ///
    /// replica1.increment(u64::MAX);   // OK
    /// replica2.increment(1);          // OK
    ///
    /// replica1.merge(&replica2);      // replica1 is in an undefined state
    /// replica2.merge(&replica1);      // replica2 is in an undefined state
    /// ```
    pub fn increment(&mut self, amount: u64) -> GCounterIncrement {
        let operation = GCounterIncrement { replica_id: self.replica_id, amount: amount };
        self.apply(&operation);
        operation
    }
}

impl Crdt<GCounterIncrement> for GCounter {

    /// Merge a replica into this counter.
    ///
    /// This method is used to perform state-based replication.
    ///
    /// ##### Example
    ///
    /// ```
    /// # use crdt::counter::GCounter;
    /// use crdt::Crdt;
    ///
    /// let mut local = GCounter::new(42);
    /// let mut remote = GCounter::new(43);
    ///
    /// local.increment(12);
    /// remote.increment(13);
    ///
    /// local.merge(&remote);
    /// assert_eq!(25, local.count());
    /// ```
    fn merge(&mut self, other: &GCounter) {
        for (replica_id, other_count) in other.counts.iter() {
            let count = match self.counts.find_mut(&replica_id) {
                Some(self_count) => cmp::max(*self_count, *other_count),
                None => *other_count
            };
            self.counts.insert(replica_id, count);
        }
    }

    /// Apply an increment operation to this counter.
    ///
    /// This method is used to perform operation-based replication.
    ///
    /// ##### Example
    ///
    /// ```
    /// # use crdt::counter::GCounter;
    /// # use crdt::Crdt;
    /// let mut local = GCounter::new(42);
    /// let mut remote = GCounter::new(43);
    ///
    /// let op = remote.increment(13);
    ///
    /// local.apply(&op);
    /// assert_eq!(13, local.count());
    /// ```
    fn apply(&mut self, operation: &GCounterIncrement) {
        let count = match self.counts.find_mut(&operation.replica_id) {
            Some(self_count) => *self_count + operation.amount,
            None => operation.amount
        };
        self.counts.insert(operation.replica_id, count);
    }

    fn replica_id(&self) -> uint {
        self.replica_id
    }
}

impl PartialEq for GCounter {
    fn eq(&self, other: &GCounter) -> bool {
        self.counts == other.counts
    }
}

impl Eq for GCounter {}

impl PartialOrd for GCounter {
    fn partial_cmp(&self, other: &GCounter) -> Option<Ordering> {

        /// Compares `a` to `b` based on replica counts.
        ///
        /// Precondition: `a.counts.len() <= b.counts.len()`
        fn a_gt_b(a: &GCounter, b: &GCounter) -> bool {
            for (replica_id, a_count) in a.counts.iter() {
                match b.counts.find(&replica_id) {
                    Some(b_count) if a_count > b_count => return true,
                    None => return true,
                    _ => ()
                }
            }
            false
        }

        let (self_gt_other, other_gt_self) =
            match self.counts.len().cmp(&other.counts.len()) {
                Less    => (a_gt_b(self, other), true),
                Greater => (true, a_gt_b(other, self)),
                Equal   => (a_gt_b(self, other), a_gt_b(other, self))
            };

        match (self_gt_other, other_gt_self) {
            (true, true)   => None,
            (true, false)  => Some(Greater),
            (false, true)  => Some(Less),
            (false, false) => Some(Equal)
        }
    }
}

/// A incrementable and decrementable counter.
#[deriving(Show)]
pub struct PNCounter {
    replica_id: uint,
    counts: TrieMap<(u64, u64)>
}

/// An increment or decrement operation over `PNCounter` CRDTs.
pub struct PNCounterIncrement {
    replica_id: uint,
    amount: i64
}

impl PNCounter {

    /// Create a new counter with the provided replica id and an initial count
    /// of 0.
    ///
    /// ##### Example
    ///
    /// ```
    /// use crdt::counter::PNCounter;
    ///
    /// let mut counter = PNCounter::new(42);
    /// assert_eq!(0, counter.count());
    /// ```
    pub fn new(replica_id: uint) -> PNCounter {
        PNCounter { replica_id: replica_id, counts: TrieMap::new() }
    }

    /// Get the current count of the counter.
    ///
    /// ##### Example
    ///
    /// ```
    /// # use crdt::counter::PNCounter;
    /// let counter = PNCounter::new(42);
    /// assert_eq!(0, counter.count());
    /// ```
    pub fn count(& self) -> i64 {
        self.counts.values().fold(0, |acc, &(p, n)| acc + (p as i64 - n as i64))
    }

    /// Increment the counter by `amount`. If `amount` is negative, then the
    /// counter will be decremented.
    ///
    /// ##### Example
    ///
    /// ```
    /// # use crdt::counter::PNCounter;
    /// let mut counter = PNCounter::new(42);
    /// assert_eq!(0, counter.count());
    /// counter.increment(-13);
    /// assert_eq!(-13, counter.count());
    /// ```
    ///
    /// ##### Overflow
    ///
    /// Incrementing the count by more than `i64::MAX` or decrementing by more
    /// than `i64::MIN` is undefined behavior. Decrements do not 'cancel out'
    /// increments for the purposes of these limits. The increment and
    /// decrement limit is globally shared across all replicas, and thus is not
    /// checked during local operations.
    ///
    /// ```
    /// # use std::i64;
    /// # use crdt::counter::PNCounter;
    /// # use crdt::Crdt;
    /// let mut replica1 = PNCounter::new(42);
    /// let mut replica2 = PNCounter::new(43);
    ///
    /// replica1.increment(i64::MAX);   // OK
    /// replica2.increment(1);          // OK
    ///
    /// replica2.merge(&replica1);      // replica2 is in an undefined state
    ///
    /// replica1.increment(i64::MIN);   // OK
    /// replica1.increment(-1);         // replica1 is in an undefined state
    /// ```
    pub fn increment(&mut self, amount: i64) -> PNCounterIncrement {
        let operation = PNCounterIncrement { replica_id: self.replica_id, amount: amount };
        self.apply(&operation);
        operation
    }
}

impl Crdt<PNCounterIncrement> for PNCounter {

    /// Merge a replica into this counter.
    ///
    /// This method is used to perform state-based replication.
    ///
    /// ##### Example
    ///
    /// ```
    /// # use crdt::counter::PNCounter;
    /// use crdt::Crdt;
    ///
    /// let mut local = PNCounter::new(42);
    /// let mut remote = PNCounter::new(43);
    ///
    /// local.increment(-12);
    /// remote.increment(13);
    ///
    /// local.merge(&remote);
    /// assert_eq!(1, local.count());
    /// ```
    fn merge(&mut self, other: &PNCounter) {
        for (replica_id, other_count) in other.counts.iter() {
            let count = match self.counts.find_mut(&replica_id) {
                Some(self_count) => cmp::max(*self_count, *other_count),
                None => *other_count
            };
            self.counts.insert(replica_id, count);
        }
    }

    /// Apply an increment operation to this counter.
    ///
    /// This method is used to perform operation-based replication.
    ///
    /// ##### Example
    ///
    /// ```
    /// # use crdt::counter::PNCounter;
    /// # use crdt::Crdt;
    /// let mut local = PNCounter::new(42);
    /// let mut remote = PNCounter::new(43);
    ///
    /// let op = remote.increment(-12);
    ///
    /// local.apply(&op);
    /// assert_eq!(-12, local.count());
    /// ```
    fn apply(&mut self, operation: &PNCounterIncrement) {
        let (p_amount, n_amount) =
            if operation.amount > 0 {
                (operation.amount as u64, 0)
            } else {
                (0, (-operation.amount) as u64)
            };

        let count = match self.counts.find_mut(&operation.replica_id) {
            Some(&(self_p, self_n)) => (self_p + p_amount, self_n + n_amount),
            None => (p_amount, n_amount)
        };

        self.counts.insert(operation.replica_id, count);
    }

    fn replica_id(&self) -> uint {
        self.replica_id
    }
}

impl PartialEq for PNCounter {
    fn eq(&self, other: &PNCounter) -> bool {
        self.counts == other.counts
    }
}

impl Eq for PNCounter {}

impl PartialOrd for PNCounter {
    fn partial_cmp(&self, other: &PNCounter) -> Option<Ordering> {

        /// Compares `a` to `b` based on replica counts.
        ///
        /// Precondition: `a.counts.len() <= b.counts.len()`
        fn a_gt_b(a: &PNCounter, b: &PNCounter) -> bool {
            for (replica_id, &(a_p_count, a_n_count)) in a.counts.iter() {
                match b.counts.find(&replica_id) {
                    Some(&(b_p_count, b_n_count))
                        if a_p_count > b_p_count || a_n_count > b_n_count => return true,
                    None => return true,
                    _ => ()
                }
            }
            false
        }

        let (self_gt_other, other_gt_self) =
            match self.counts.len().cmp(&other.counts.len()) {
                Less    => (a_gt_b(self, other), true),
                Greater => (true, a_gt_b(other, self)),
                Equal   => (a_gt_b(self, other), a_gt_b(other, self))
            };

        match (self_gt_other, other_gt_self) {
            (true, true)   => None,
            (true, false)  => Some(Greater),
            (false, true)  => Some(Less),
            (false, false) => Some(Equal)
        }
    }
}

#[cfg(test)]
mod test {

    use Crdt;
    use counter::GCounter;

    #[test]
    fn g_counter_create() {
        let counter = GCounter::new(0);
        assert_eq!(0, counter.count());
    }

    #[test]
    fn g_counter_increment() {
        let mut counter = GCounter::new(42);
        assert_eq!(0, counter.count());
        counter.increment(1);
        assert_eq!(1, counter.count());
        counter.increment(2);
        assert_eq!(3, counter.count());
        counter.increment(3);
        assert_eq!(6, counter.count());
    }

    #[test]
    fn g_counter_merge() {
        let mut a = GCounter::new(1);
        let mut b = GCounter::new(2);

        a.increment(13);
        b.increment(17);

        a.merge(&b);
        b.merge(&a);
        assert_eq!(30, a.count());
        assert_eq!(30, b.count());
    }

    #[test]
    fn g_counter_apply() {
        let mut a = GCounter::new(1);
        let mut b = GCounter::new(2);

        let ref a_op_1 = a.increment(5);
        let ref a_op_2 = a.increment(8);
        let ref b_op = b.increment(17);

        a.apply(b_op);
        b.apply(a_op_1);
        b.apply(a_op_2);
        assert_eq!(30, a.count());
        assert_eq!(30, b.count());
    }
}
<|endoftext|>


<commit_before>use std::fmt::{self, Debug, Display};
use std::mem;

use nom::{self, le_u32};
use quick_error::ResultExt;

// Generated with ./mk_vsl_tag from Varnish headers: include/tbl/vsl_tags.h include/tbl/vsl_tags_http.h include/vsl_int.h
// https://github.com/varnishcache/varnish-cache/blob/master/include/vapi/vsl_int.h
// https://github.com/varnishcache/varnish-cache/blob/master/include/tbl/vsl_tags.h
// https://github.com/varnishcache/varnish-cache/blob/master/include/tbl/vsl_tags_http.h
mod tag_e;
pub use self::tag_e::VSL_tag_e as VslRecordTag;

mod message_parsers;
pub use self::message_parsers::*;

mod maybe_string;
pub use self::maybe_string::{MaybeStr, MaybeString};

mod store;
pub use self::store::VslStore;

/*
 * Shared memory log format
 *
 * The log member points to an array of 32bit unsigned integers containing
 * log records.
 *
 * Each logrecord consist of:
 *    [n]               = ((type & 0xff) << 24) | (length & 0xffff)
 *    [n + 1]           = ((marker & 0x03) << 30) | (identifier & 0x3fffffff)
 *    [n + 2] ... [m]   = content (NUL-terminated)
 *
 * Logrecords are NUL-terminated so that string functions can be run
 * directly on the shmlog data.
 *
 * Notice that the constants in these macros cannot be changed without
 * changing corresponding magic numbers in varnishd/cache/cache_shmlog.c
 */

const VSL_LENOFFSET: u32 = 24;
const VSL_LENMASK: u32 = 0xffff;
const VSL_IDENTOFFSET: u8 = 30;
const VSL_IDENTMASK: u32 = !(0b0000_0011 << VSL_IDENTOFFSET);

/*
* VSL_CLIENT(ptr)
*   Non-zero if this is a client transaction
*
* VSL_BACKEND(ptr)
*   Non-zero if this is a backend transaction
*/

bitflags! {
    pub flags Marker: u8 {
        const VSL_CLIENTMARKER  = 0b0000_0001,
        const VSL_BACKENDMARKER = 0b0000_0010,
    }
}

impl Display for Marker {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "[{}{}]",
               if self.contains(VSL_CLIENTMARKER) { "C" } else { " " },
               if self.contains(VSL_BACKENDMARKER) { "B" } else { " " })
    }
}

pub type VslIdent = u32;

named!(pub binary_vsl_tag<&[u8], Option<&[u8]> >, opt!(complete!(tag!(b"VSL\0"))));

#[derive(Debug)]
struct VslRecordHeader {
    tag: u8,
    len: u16,
    marker: Marker,
    ident: VslIdent,
}

fn vsl_record_header<'b>(input: &'b[u8]) -> nom::IResult<&'b[u8], VslRecordHeader, u32> {
    chain!(
        input, r1: le_u32 ~ r2: le_u32,
        || {
            VslRecordHeader {
                tag: (r1 >> VSL_LENOFFSET) as u8,
                len: (r1 & VSL_LENMASK) as u16,
                marker: Marker::from_bits_truncate(((r2 & !VSL_IDENTMASK) >> VSL_IDENTOFFSET) as u8),
                ident: r2 & VSL_IDENTMASK,
            }
        })
}

pub struct VslRecord<'b> {
    pub tag: VslRecordTag,
    pub marker: Marker,
    pub ident: VslIdent,
    pub data: &'b[u8],
}

quick_error! {
    #[derive(Debug)]
    pub enum VslRecordParseError {
        Nom(nom_err: String, tag: VslRecordTag, record: String) {
            context(record: &'a VslRecord<'a>, err: nom::Err<&'a [u8]>) -> (format!("{}", err), record.tag, format!("{}", record))
            display("Nom parser failed on {}: {}", record, nom_err)
        }
    }
}

impl<'b> VslRecord<'b> {
    pub fn parse_data<T, P>(&'b self, parser: P) -> Result<T, VslRecordParseError> where
    P: Fn(&'b [u8]) -> nom::IResult<&'b [u8], T> {
        // Note: need type annotaion for the u32 error type as the output IResult has no Error
        // variant that would help to infer it
        let result: nom::IResult<_, Result<T, _>, u32> = opt_res!(self.data, complete!(parser));
        // unwrap here is safe as complete! eliminates Incomplete variant and opt_res! remaining Error variant
        result.unwrap().1.context(self).map_err(|err| From::from(err))
    }

    pub fn is_client(&self) -> bool {
        self.marker.contains(VSL_CLIENTMARKER)
    }

    pub fn is_backend(&self) -> bool {
        self.marker.contains(VSL_BACKENDMARKER)
    }

    #[cfg(test)]
    pub fn from_str<'s>(tag: VslRecordTag, ident: VslIdent, message: &'s str) -> VslRecord<'s> {
        VslRecord {
            tag: tag,
            marker: VSL_CLIENTMARKER,
            ident: ident,
            data: message.as_ref()
        }
    }
}

impl<'b> Debug for VslRecord<'b> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        f.debug_struct("VSL Record")
            .field("tag", &self.tag)
            .field("marker", &self.marker)
            .field("ident", &self.ident)
            .field("data", &MaybeStr::from_bytes(&self.data))
            .finish()
    }
}

impl<'b> Display for VslRecord<'b> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let tag = format!("{:?}", self.tag);

        if f.alternate() {
            write!(f, "{} {:5} {:18} {}", self.marker, self.ident, tag, MaybeStr::from_bytes(self.data))
        } else {
            write!(f, "VSL record (marker: {} ident: {} tag: {} data: {:?})", self.marker, self.ident, tag, MaybeStr::from_bytes(self.data))
        }
    }
}

fn to_vsl_record_tag(num: u8) -> VslRecordTag {
    // Tend to work even for missing tags as they end up as SLT__Bogus (0)
    unsafe { mem::transmute(num as u32) }
}

pub fn vsl_record_v4<'b>(input: &'b[u8]) -> nom::IResult<&'b[u8], VslRecord<'b>, u32> {
    chain!(
        input,
        header: vsl_record_header ~ data: take!(header.len - 1) ~ take!(1) ~ take!((4 - header.len % 4) % 4),
        || VslRecord {
        tag: to_vsl_record_tag(header.tag),
        marker: header.marker,
        ident: header.ident,
        data: data
    })
}
<commit_msg>formatting<commit_after>use std::fmt::{self, Debug, Display};
use std::mem;

use nom::{self, le_u32};
use quick_error::ResultExt;

// Generated with ./mk_vsl_tag from Varnish headers: include/tbl/vsl_tags.h include/tbl/vsl_tags_http.h include/vsl_int.h
// https://github.com/varnishcache/varnish-cache/blob/master/include/vapi/vsl_int.h
// https://github.com/varnishcache/varnish-cache/blob/master/include/tbl/vsl_tags.h
// https://github.com/varnishcache/varnish-cache/blob/master/include/tbl/vsl_tags_http.h
mod tag_e;
pub use self::tag_e::VSL_tag_e as VslRecordTag;

mod message_parsers;
pub use self::message_parsers::*;

mod maybe_string;
pub use self::maybe_string::{MaybeStr, MaybeString};

mod store;
pub use self::store::VslStore;

/*
 * Shared memory log format
 *
 * The log member points to an array of 32bit unsigned integers containing
 * log records.
 *
 * Each logrecord consist of:
 *    [n]               = ((type & 0xff) << 24) | (length & 0xffff)
 *    [n + 1]           = ((marker & 0x03) << 30) | (identifier & 0x3fffffff)
 *    [n + 2] ... [m]   = content (NUL-terminated)
 *
 * Logrecords are NUL-terminated so that string functions can be run
 * directly on the shmlog data.
 *
 * Notice that the constants in these macros cannot be changed without
 * changing corresponding magic numbers in varnishd/cache/cache_shmlog.c
 */

const VSL_LENOFFSET: u32 = 24;
const VSL_LENMASK: u32 = 0xffff;
const VSL_IDENTOFFSET: u8 = 30;
const VSL_IDENTMASK: u32 = !(0b0000_0011 << VSL_IDENTOFFSET);

/*
* VSL_CLIENT(ptr)
*   Non-zero if this is a client transaction
*
* VSL_BACKEND(ptr)
*   Non-zero if this is a backend transaction
*/

bitflags! {
    pub flags Marker: u8 {
        const VSL_CLIENTMARKER  = 0b0000_0001,
        const VSL_BACKENDMARKER = 0b0000_0010,
    }
}

impl Display for Marker {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "[{}{}]",
               if self.contains(VSL_CLIENTMARKER) { "C" } else { " " },
               if self.contains(VSL_BACKENDMARKER) { "B" } else { " " })
    }
}

pub type VslIdent = u32;

named!(pub binary_vsl_tag<&[u8], Option<&[u8]> >, opt!(complete!(tag!(b"VSL\0"))));

#[derive(Debug)]
struct VslRecordHeader {
    tag: u8,
    len: u16,
    marker: Marker,
    ident: VslIdent,
}

fn vsl_record_header<'b>(input: &'b[u8]) -> nom::IResult<&'b[u8], VslRecordHeader, u32> {
    chain!(
        input, r1: le_u32 ~ r2: le_u32,
        || VslRecordHeader {
            tag: (r1 >> VSL_LENOFFSET) as u8,
            len: (r1 & VSL_LENMASK) as u16,
            marker: Marker::from_bits_truncate(((r2 & !VSL_IDENTMASK) >> VSL_IDENTOFFSET) as u8),
            ident: r2 & VSL_IDENTMASK,
        })
}

pub struct VslRecord<'b> {
    pub tag: VslRecordTag,
    pub marker: Marker,
    pub ident: VslIdent,
    pub data: &'b[u8],
}

quick_error! {
    #[derive(Debug)]
    pub enum VslRecordParseError {
        Nom(nom_err: String, tag: VslRecordTag, record: String) {
            context(record: &'a VslRecord<'a>, err: nom::Err<&'a [u8]>) -> (format!("{}", err), record.tag, format!("{}", record))
            display("Nom parser failed on {}: {}", record, nom_err)
        }
    }
}

impl<'b> VslRecord<'b> {
    pub fn parse_data<T, P>(&'b self, parser: P) -> Result<T, VslRecordParseError> where
    P: Fn(&'b [u8]) -> nom::IResult<&'b [u8], T> {
        // Note: need type annotaion for the u32 error type as the output IResult has no Error
        // variant that would help to infer it
        let result: nom::IResult<_, Result<T, _>, u32> = opt_res!(self.data, complete!(parser));
        // unwrap here is safe as complete! eliminates Incomplete variant and opt_res! remaining Error variant
        result.unwrap().1.context(self).map_err(|err| From::from(err))
    }

    pub fn is_client(&self) -> bool {
        self.marker.contains(VSL_CLIENTMARKER)
    }

    pub fn is_backend(&self) -> bool {
        self.marker.contains(VSL_BACKENDMARKER)
    }

    #[cfg(test)]
    pub fn from_str<'s>(tag: VslRecordTag, ident: VslIdent, message: &'s str) -> VslRecord<'s> {
        VslRecord {
            tag: tag,
            marker: VSL_CLIENTMARKER,
            ident: ident,
            data: message.as_ref()
        }
    }
}

impl<'b> Debug for VslRecord<'b> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        f.debug_struct("VSL Record")
            .field("tag", &self.tag)
            .field("marker", &self.marker)
            .field("ident", &self.ident)
            .field("data", &MaybeStr::from_bytes(&self.data))
            .finish()
    }
}

impl<'b> Display for VslRecord<'b> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let tag = format!("{:?}", self.tag);

        if f.alternate() {
            write!(f, "{} {:5} {:18} {}", self.marker, self.ident, tag, MaybeStr::from_bytes(self.data))
        } else {
            write!(f, "VSL record (marker: {} ident: {} tag: {} data: {:?})", self.marker, self.ident, tag, MaybeStr::from_bytes(self.data))
        }
    }
}

fn to_vsl_record_tag(num: u8) -> VslRecordTag {
    // Tend to work even for missing tags as they end up as SLT__Bogus (0)
    unsafe { mem::transmute(num as u32) }
}

pub fn vsl_record_v4<'b>(input: &'b[u8]) -> nom::IResult<&'b[u8], VslRecord<'b>, u32> {
    chain!(
        input,
        header: vsl_record_header ~
        data: take!(header.len - 1) ~ take!(1) ~ take!((4 - header.len % 4) % 4),
        || VslRecord {
            tag: to_vsl_record_tag(header.tag),
            marker: header.marker,
            ident: header.ident,
            data: data
        })
}
<|endoftext|>