<commit_before>use std::{cmp, ptr};

use self::ApplyResult::*;
use super::Leading::{self, Top, Bot};

const BCNT: u8 = 5;
const BCNT_: usize = BCNT as usize;

#[derive(Copy, Clone)]
struct SPart(u64);

#[derive(Copy, Clone)]
pub struct SPair {
    a: SPart,
    b: SPart,
}

/// A variable length pair.
#[derive(Copy, Clone)]
pub struct VPair {
    data: [u64; BCNT_],
    /// Who is leading.
    leading: Leading,
    /// How many bits of the first block are shared.
    prefix: u8,
    /// How many bits of the last block are used.
    used: u8,
    /// which block is last used one
    tail: u8,
}

#[derive(Copy, Clone)]
struct VHead {
    data: u64,
    /// How many bits are shared
    prefix: u8,
    /// How many bits are used
    used: u8,
}

impl VPair {
    pub fn new() -> VPair {
        VPair {
            data: [0; BCNT_],
            prefix: 0,
            used: 0,
            leading: Top,
            tail: 0,
        }
    }

    pub fn len(&self) -> usize {
        self.tail as usize + 1
    }

    pub fn is_complete(&self) -> bool {
        self.tail == 0 && self.used == 0
    }

    pub fn apply(&self, p: &SPair) -> Option<VPair> {
        let (mut lead, mut follow) = match self.leading {
            Top => (p.a, p.b),
            Bot => (p.b, p.a),
        };

        let mut head = self.head();

        match head.apply(&mut follow, &mut lead) {
            Mismatch => None,
            Match => Some(self.with_offset_prefix_and_add_lead(0, head.prefix, lead)),
            LeadSwitch => Some(self.switched_with_new_lead(follow)),
            MatchRemaining => {
                let mut head2 = self.head2();

                match head2.apply(&mut follow, &mut lead) {
                    Mismatch => None,
                    Match => Some(self.with_offset_prefix_and_add_lead(1, head2.prefix, lead)),
                    LeadSwitch => Some(self.switched_with_new_lead(follow)),
                    MatchRemaining => unreachable!("SPairs contain at most 56 bit, which always fit in 64 bit"),
                }
            }
        }
    }

    fn with_offset_prefix_and_add_lead(&self, offset: u8, prefix: u8, lead: SPart) -> VPair {
        let mut p = VPair {
            data: [0; BCNT_],
            prefix: prefix,
            used: self.used,
            leading: self.leading,
            tail: self.tail - offset
        };

        unsafe {
            ptr::copy_nonoverlapping(&self.data[offset as usize], &mut p.data[0], BCNT_ - offset as usize)

        }

        p.apply_lead(lead);

        p
    }

    fn switched_with_new_lead(&self, lead: SPart) -> VPair {
        let mut p = VPair {
            data: [0; BCNT_],
            prefix: 0,
            used: lead.len(),
            leading: self.leading.switched(),
            tail: 0,
        };

        p.data[0] = lead.data();

        p
    }

    fn apply_lead(&mut self, mut lead: SPart) {
        let pushable;

        { // make the borrowchecker happy
            let last = &mut self.data[self.tail as usize];

            // push all we can into the current byte
            pushable = cmp::min(64 - self.used, lead.len());
            *last |= lead.shift_data(pushable) << self.used;
        }

        let new_used = self.used + pushable;

        // if new_used is 64 need to open a new block
        if lead.len() == 0 && new_used < 64 {
            self.used = new_used;
        } else {
            self.push(lead.data());
            self.used = lead.len();
        }

        debug_assert!(self.used != 64);
    }

    fn push(&mut self, block: u64) {
        assert!(self.tail + 1 < BCNT, "lead too long, increase BCNT");
        self.tail += 1;
        self.data[self.tail as usize] = block;
    }

    fn head(&self) -> VHead {
        debug_assert!(self.used != 64);

        VHead {
            data: self.data[0],
            prefix: self.prefix,
            used: if self.tail > 0 { 64 } else { self.used },
        }
    }

    fn head2(&self) -> VHead {
        debug_assert!(self.tail > 0);

        VHead {
            data: self.data[1],
            prefix: 0,
            used: if self.tail > 1 { 64 } else { self. used },
        }
    }
}

#[derive(Copy, Clone)]
enum ApplyResult {
    /// No match
    Mismatch,
    /// Completely matched, bits in lead need to be appended
    Match,
    /// Matched but end of block reached, repeat with second block
    MatchRemaining,
    /// Completely caught up, bits in follow make up a new block
    LeadSwitch,
}

impl SPart {
    fn data(&self) -> u64 {
        self.0 & 0x00FF_FFFF_FFFF_FFFF
    }

    fn len(&self) -> u8 {
        (self.0 >> 56) as u8
    }

    fn shift(&mut self, shift: u8) {
        let new_len = self.len() - shift;
        let new_val = self.data() >> shift;
        self.0 = ((new_len as u64) << 56) | new_val;
    }

    fn shift_data(&mut self, shift: u8) -> u64 {
        let data = self.0 & mask(shift);
        self.shift(shift);
        data
    }

    fn shift_prefix(a: &mut SPart, b: &mut SPart) {
        // after the xor the first mismatched bit is a one
        // theres no need for masking data since we need to use the min of the
        // lens and prefix anyway
        let prefix = (a.0 ^ b.0).trailing_zeros() as u8; // 0-64 always fit in an u8
        let prefix = cmp::min(prefix, cmp::min(a.len(), b.len()));
        a.shift(prefix);
        b.shift(prefix);
    }
}

impl VHead {
    fn apply(&mut self, follow: &mut SPart, lead: &mut SPart) -> ApplyResult {
        // fist, check that overlapping follows are equal
        let overlap = cmp::min(self.used - self.prefix, follow.len());

        // check
        let m = mask(overlap);
        let h = (self.data >> self.prefix) & m;
        let p = follow.data() & m;

        if h != p { return Mismatch; }

        // update
        self.prefix += overlap;
        follow.shift(overlap);

        if self.prefix == 64 {
            debug_assert!(self.used == 64);
            return MatchRemaining; // Reached the end of block, needs to be removed
        }

        // at this point follow has caught up to lead, so we can eliminate any common prefix from follow and lead
        SPart::shift_prefix(follow, lead);

        match (follow.len() == 0, lead.len() == 0) {
            (_, true) => LeadSwitch, // lead is empty, start a new block with follow
            (false, false) => Mismatch, // both have non matching bits remaining
            (true, false) => Match, // follow is empty
        }
    }
}

/// Create a bitmask of which the lower `cnt` bits are set.
fn mask(cnt: u8) -> u64 {
    (1 << cnt) - 1
}

impl<'a> From<&'a str> for SPart {
    fn from(s: &'a str) -> SPart {
        let mut val = 0u64;
        let mut len = 0u64;

        for b in s.bytes().rev() {
            len += 1;
            val <<= 1;

            match b {
                b'0' => (),
                b'1' => val |= 1,
                _ => panic!("invalid input byte: {}", b),
            }
        }

        assert!(len <= 56, "invalid input: too long");

        SPart((len << 56) | val)
    }
}

impl<'a> From<(&'a str, &'a str)> for SPair {
    fn from((a, b): (&'a str, &'a str)) -> SPair {
        SPair {
            a: a.into(),
            b: b.into(),
        }
    }
}
<commit_msg>make block sizes easily changeable<commit_after>use std::{cmp, ptr};

use self::ApplyResult::*;
use super::Leading::{self, Top, Bot};

type blk = u64;
const BCNT: u8 = 5;
const BLK_BITS: u8 = 64;

const BCNT_: usize = BCNT as usize;
const VAL_BITS: u8 = BLK_BITS - 8;
const VAL_MASK: blk = (1 << VAL_BITS) - 1;

#[derive(Copy, Clone)]
struct SPart(blk);

#[derive(Copy, Clone)]
pub struct SPair {
    a: SPart,
    b: SPart,
}

/// A variable length pair.
#[derive(Copy, Clone)]
pub struct VPair {
    data: [blk; BCNT_],
    /// Who is leading.
    leading: Leading,
    /// How many bits of the first block are shared.
    prefix: u8,
    /// How many bits of the last block are used.
    used: u8,
    /// which block is last used one
    tail: u8,
}

#[derive(Copy, Clone)]
struct VHead {
    data: blk,
    /// How many bits are shared
    prefix: u8,
    /// How many bits are used
    used: u8,
}

impl VPair {
    pub fn new() -> VPair {
        VPair {
            data: [0; BCNT_],
            prefix: 0,
            used: 0,
            leading: Top,
            tail: 0,
        }
    }

    pub fn len(&self) -> usize {
        self.tail as usize + 1
    }

    pub fn is_complete(&self) -> bool {
        self.tail == 0 && self.used == 0
    }

    pub fn apply(&self, p: &SPair) -> Option<VPair> {
        let (mut lead, mut follow) = match self.leading {
            Top => (p.a, p.b),
            Bot => (p.b, p.a),
        };

        let mut head = self.head();

        match head.apply(&mut follow, &mut lead) {
            Mismatch => None,
            Match => Some(self.with_offset_prefix_and_add_lead(0, head.prefix, lead)),
            LeadSwitch => Some(self.switched_with_new_lead(follow)),
            MatchRemaining => {
                let mut head2 = self.head2();

                match head2.apply(&mut follow, &mut lead) {
                    Mismatch => None,
                    Match => Some(self.with_offset_prefix_and_add_lead(1, head2.prefix, lead)),
                    LeadSwitch => Some(self.switched_with_new_lead(follow)),
                    MatchRemaining => unreachable!("SPairs contain at most VAL_BITS bit, which always fit in BITS bit"),
                }
            }
        }
    }

    fn with_offset_prefix_and_add_lead(&self, offset: u8, prefix: u8, lead: SPart) -> VPair {
        let mut p = VPair {
            data: [0; BCNT_],
            prefix: prefix,
            used: self.used,
            leading: self.leading,
            tail: self.tail - offset
        };

        unsafe {
            ptr::copy_nonoverlapping(&self.data[offset as usize], &mut p.data[0], BCNT_ - offset as usize)

        }

        p.apply_lead(lead);

        p
    }

    fn switched_with_new_lead(&self, lead: SPart) -> VPair {
        let mut p = VPair {
            data: [0; BCNT_],
            prefix: 0,
            used: lead.len(),
            leading: self.leading.switched(),
            tail: 0,
        };

        p.data[0] = lead.data();

        p
    }

    fn apply_lead(&mut self, mut lead: SPart) {
        let pushable;

        { // make the borrowchecker happy
            let last = &mut self.data[self.tail as usize];

            // push all we can into the current byte
            pushable = cmp::min(BLK_BITS - self.used, lead.len());
            *last |= lead.shift_data(pushable) << self.used;
        }

        let new_used = self.used + pushable;

        // if new_used is 64 need to open a new block
        if lead.len() == 0 && new_used < BLK_BITS {
            self.used = new_used;
        } else {
            self.push(lead.data());
            self.used = lead.len();
        }

        debug_assert!(self.used != BLK_BITS);
    }

    fn push(&mut self, block: blk) {
        assert!(self.tail + 1 < BCNT, "lead too long, increase BCNT");
        self.tail += 1;
        self.data[self.tail as usize] = block;
    }

    fn head(&self) -> VHead {
        debug_assert!(self.used != BLK_BITS);

        VHead {
            data: self.data[0],
            prefix: self.prefix,
            used: if self.tail > 0 { BLK_BITS } else { self.used },
        }
    }

    fn head2(&self) -> VHead {
        debug_assert!(self.tail > 0);

        VHead {
            data: self.data[1],
            prefix: 0,
            used: if self.tail > 1 { BLK_BITS } else { self. used },
        }
    }
}

#[derive(Copy, Clone)]
enum ApplyResult {
    /// No match
    Mismatch,
    /// Completely matched, bits in lead need to be appended
    Match,
    /// Matched but end of block reached, repeat with second block
    MatchRemaining,
    /// Completely caught up, bits in follow make up a new block
    LeadSwitch,
}

impl SPart {
    fn data(&self) -> blk {
        self.0 & VAL_MASK
    }

    fn len(&self) -> u8 {
        (self.0 >> VAL_BITS) as u8
    }

    fn shift(&mut self, shift: u8) {
        let new_len = self.len() - shift;
        let new_val = self.data() >> shift;
        self.0 = ((new_len as blk) << VAL_BITS) | new_val;
    }

    fn shift_data(&mut self, shift: u8) -> blk {
        let data = self.0 & mask(shift);
        self.shift(shift);
        data
    }

    fn shift_prefix(a: &mut SPart, b: &mut SPart) {
        // after the xor the first mismatched bit is a one
        // theres no need for masking data since we need to use the min of the
        // lens and prefix anyway
        let prefix = (a.0 ^ b.0).trailing_zeros() as u8; // 0-64 always fit in an u8
        let prefix = cmp::min(prefix, cmp::min(a.len(), b.len()));
        a.shift(prefix);
        b.shift(prefix);
    }
}

impl VHead {
    fn apply(&mut self, follow: &mut SPart, lead: &mut SPart) -> ApplyResult {
        // fist, check that overlapping follows are equal
        let overlap = cmp::min(self.used - self.prefix, follow.len());

        // check
        let m = mask(overlap);
        let h = (self.data >> self.prefix) & m;
        let p = follow.data() & m;

        if h != p { return Mismatch; }

        // update
        self.prefix += overlap;
        follow.shift(overlap);

        if self.prefix == BLK_BITS {
            debug_assert!(self.used == BLK_BITS);
            return MatchRemaining; // Reached the end of block, needs to be removed
        }

        // at this point follow has caught up to lead, so we can eliminate any common prefix from follow and lead
        SPart::shift_prefix(follow, lead);

        match (follow.len() == 0, lead.len() == 0) {
            (_, true) => LeadSwitch, // lead is empty, start a new block with follow
            (false, false) => Mismatch, // both have non matching bits remaining
            (true, false) => Match, // follow is empty
        }
    }
}

/// Create a bitmask of which the lower `cnt` bits are set.
fn mask(cnt: u8) -> blk {
    (1 << cnt) - 1
}

impl<'a> From<&'a str> for SPart {
    fn from(s: &'a str) -> SPart {
        let mut val: blk = 0;
        let mut len: blk = 0;

        for b in s.bytes().rev() {
            len += 1;
            val <<= 1;

            match b {
                b'0' => (),
                b'1' => val |= 1,
                _ => panic!("invalid input byte: {}", b),
            }
        }

        assert!(len <= VAL_BITS as blk, "invalid input: too long");

        SPart((len << VAL_BITS) | val)
    }
}

impl<'a> From<(&'a str, &'a str)> for SPair {
    fn from((a, b): (&'a str, &'a str)) -> SPair {
        SPair {
            a: a.into(),
            b: b.into(),
        }
    }
}
<|endoftext|>


<commit_before>use crate::callback::CallbackSubscription;
use crate::callback::SubscribableCallback;
use crate::shared_memory::SharedMemory;

#[cfg(target_arch = "arm")]
pub fn yieldk() {
    // Note: A process stops yielding when there is a callback ready to run,
    // which the kernel executes by modifying the stack frame pushed by the
    // hardware. The kernel copies the PC value from the stack frame to the LR
    // field, and sets the PC value to callback to run. When this frame is
    // unstacked during the interrupt return, the effectively clobbers the LR
    // register.
    //
    // At this point, the callback function is now executing, which may itself
    // clobber any of the other caller-saved registers. Thus we mark this
    // inline assembly as conservatively clobbering all caller-saved registers,
    // forcing yield to save any live registers.
    //
    // Upon direct observation of this function, the LR is the only register
    // that is live across the SVC invocation, however, if the yield call is
    // inlined, it is possible that the LR won't be live at all (commonly seen
    // for the `loop { yieldk(); }` idiom) or that other registers are live,
    // thus it is important to let the compiler do the work here.
    //
    // According to the AAPCS: A subroutine must preserve the contents of the
    // registers r4-r8, r10, r11 and SP (and r9 in PCS variants that designate
    // r9 as v6) As our compilation flags mark r9 as the PIC base register, it
    // does not need to be saved. Thus we must clobber r0-3, r12, and LR
    unsafe {
        asm!(
            "svc 0"
            :
            :
            : "memory", "r0", "r1", "r2", "r3", "r12", "lr"
            : "volatile");
    }
}

#[cfg(target_arch = "riscv32")]
pub fn yieldk() {
    /* TODO: Stop yielding */
    unsafe {
        asm! (
            "li    a0, 0
            ecall"
            :
            :
            : "memory", "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
            "t0", "t1", "t2", "t3", "t4", "t5", "t6", "ra"
            : "volatile");
    }
}

pub fn yieldk_for<F: Fn() -> bool>(cond: F) {
    while !cond() {
        yieldk();
    }
}

pub fn subscribe<CB: SubscribableCallback>(
    driver_number: usize,
    subscribe_number: usize,
    callback: &mut CB,
) -> Result<CallbackSubscription, isize> {
    let return_code = unsafe {
        subscribe_ptr(
            driver_number,
            subscribe_number,
            c_callback::<CB> as *const _,
            callback as *mut CB as usize,
        )
    };

    if return_code == 0 {
        Ok(CallbackSubscription::new(driver_number, subscribe_number))
    } else {
        Err(return_code)
    }
}

extern "C" fn c_callback<CB: SubscribableCallback>(
    arg0: usize,
    arg1: usize,
    arg2: usize,
    userdata: usize,
) {
    let callback = unsafe { &mut *(userdata as *mut CB) };
    callback.call_rust(arg0, arg1, arg2);
}

#[cfg(target_arch = "arm")]
pub unsafe fn subscribe_ptr(
    major: usize,
    minor: usize,
    cb: *const unsafe extern "C" fn(usize, usize, usize, usize),
    ud: usize,
) -> isize {
    let res;
    asm!("svc 1" : "={r0}"(res)
                 : "{r0}"(major) "{r1}"(minor) "{r2}"(cb) "{r3}"(ud)
                 : "memory"
                 : "volatile");
    res
}

#[cfg(target_arch = "riscv32")]
pub unsafe fn subscribe_ptr(
    major: usize,
    minor: usize,
    cb: *const unsafe extern "C" fn(usize, usize, usize, usize),
    ud: usize,
) -> isize {
    let res;
    asm!("li    a0, 1
          ecall"
         : "=r" (res)
         : "r" (major), "r" (minor), "r" (cb), "r" (ud)
         : "memory"
         : "volatile" );
    res
}

#[cfg(target_arch = "arm")]
pub unsafe fn command(major: usize, minor: usize, arg1: usize, arg2: usize) -> isize {
    let res;
    asm!("svc 2" : "={r0}"(res)
                 : "{r0}"(major) "{r1}"(minor) "{r2}"(arg1) "{r3}"(arg2)
                 : "memory"
                 : "volatile");
    res
}

#[cfg(target_arch = "riscv32")]
pub unsafe fn command(major: usize, minor: usize, arg1: usize, arg2: usize) -> isize {
    let res;
    asm!("li    a0, 2
          ecall"
         : "=r" (res)
         : "r" (major), "r" (minor), "r" (arg1), "r" (arg2)
         : "memory"
         : "volatile");
    res
}

pub fn allow(
    driver_number: usize,
    allow_number: usize,
    buffer_to_share: &mut [u8],
) -> Result<SharedMemory, isize> {
    let len = buffer_to_share.len();
    let return_code = unsafe {
        allow_ptr(
            driver_number,
            allow_number,
            buffer_to_share.as_mut_ptr(),
            len,
        )
    };
    if return_code == 0 {
        Ok(SharedMemory::new(
            driver_number,
            allow_number,
            buffer_to_share,
        ))
    } else {
        Err(return_code)
    }
}

#[cfg(target_arch = "arm")]
pub unsafe fn allow_ptr(major: usize, minor: usize, slice: *mut u8, len: usize) -> isize {
    let res;
    asm!("svc 3" : "={r0}"(res)
                 : "{r0}"(major) "{r1}"(minor) "{r2}"(slice) "{r3}"(len)
                 : "memory"
                 : "volatile");
    res
}

#[cfg(target_arch = "riscv32")]
pub unsafe fn allow_ptr(major: usize, minor: usize, slice: *mut u8, len: usize) -> isize {
    let res;
    asm!("li    a0, 3
          ecall"
         : "=r" (res)
         : "r" (major), "r" (minor), "r" (slice), "r" (len)
         : "memory"
         : "volatile");
    res
}

#[cfg(target_arch = "arm")]
pub unsafe fn memop(major: u32, arg1: usize) -> isize {
    let res;
    asm!("svc 4" : "={r0}"(res)
                 : "{r0}"(major) "{r1}"(arg1)
                 : "memory"
                 : "volatile");
    res
}

#[cfg(target_arch = "riscv32")]
pub unsafe fn memop(major: u32, arg1: usize) -> isize {
    let res;
    asm!("li    a0, 4
          ecall"
         : "=r" (res)
         : "r" (major), "r" (arg1)
         : "memory"
         : "volatile");
    res
}
<commit_msg>syscalls: Hardcode syscall registers for RISC-V 32<commit_after>use crate::callback::CallbackSubscription;
use crate::callback::SubscribableCallback;
use crate::shared_memory::SharedMemory;

#[cfg(target_arch = "arm")]
pub fn yieldk() {
    // Note: A process stops yielding when there is a callback ready to run,
    // which the kernel executes by modifying the stack frame pushed by the
    // hardware. The kernel copies the PC value from the stack frame to the LR
    // field, and sets the PC value to callback to run. When this frame is
    // unstacked during the interrupt return, the effectively clobbers the LR
    // register.
    //
    // At this point, the callback function is now executing, which may itself
    // clobber any of the other caller-saved registers. Thus we mark this
    // inline assembly as conservatively clobbering all caller-saved registers,
    // forcing yield to save any live registers.
    //
    // Upon direct observation of this function, the LR is the only register
    // that is live across the SVC invocation, however, if the yield call is
    // inlined, it is possible that the LR won't be live at all (commonly seen
    // for the `loop { yieldk(); }` idiom) or that other registers are live,
    // thus it is important to let the compiler do the work here.
    //
    // According to the AAPCS: A subroutine must preserve the contents of the
    // registers r4-r8, r10, r11 and SP (and r9 in PCS variants that designate
    // r9 as v6) As our compilation flags mark r9 as the PIC base register, it
    // does not need to be saved. Thus we must clobber r0-3, r12, and LR
    unsafe {
        asm!(
            "svc 0"
            :
            :
            : "memory", "r0", "r1", "r2", "r3", "r12", "lr"
            : "volatile");
    }
}

#[cfg(target_arch = "riscv32")]
pub fn yieldk() {
    /* TODO: Stop yielding */
    unsafe {
        asm! (
            "li    a0, 0
            ecall"
            :
            :
            : "memory", "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
            "t0", "t1", "t2", "t3", "t4", "t5", "t6", "ra"
            : "volatile");
    }
}

pub fn yieldk_for<F: Fn() -> bool>(cond: F) {
    while !cond() {
        yieldk();
    }
}

pub fn subscribe<CB: SubscribableCallback>(
    driver_number: usize,
    subscribe_number: usize,
    callback: &mut CB,
) -> Result<CallbackSubscription, isize> {
    let return_code = unsafe {
        subscribe_ptr(
            driver_number,
            subscribe_number,
            c_callback::<CB> as *const _,
            callback as *mut CB as usize,
        )
    };

    if return_code == 0 {
        Ok(CallbackSubscription::new(driver_number, subscribe_number))
    } else {
        Err(return_code)
    }
}

extern "C" fn c_callback<CB: SubscribableCallback>(
    arg0: usize,
    arg1: usize,
    arg2: usize,
    userdata: usize,
) {
    let callback = unsafe { &mut *(userdata as *mut CB) };
    callback.call_rust(arg0, arg1, arg2);
}

#[cfg(target_arch = "arm")]
pub unsafe fn subscribe_ptr(
    major: usize,
    minor: usize,
    cb: *const unsafe extern "C" fn(usize, usize, usize, usize),
    ud: usize,
) -> isize {
    let res;
    asm!("svc 1" : "={r0}"(res)
                 : "{r0}"(major) "{r1}"(minor) "{r2}"(cb) "{r3}"(ud)
                 : "memory"
                 : "volatile");
    res
}

#[cfg(target_arch = "riscv32")]
pub unsafe fn subscribe_ptr(
    major: usize,
    minor: usize,
    cb: *const unsafe extern "C" fn(usize, usize, usize, usize),
    ud: usize,
) -> isize {
    let res;
    asm!("li    a0, 1
          ecall"
         : "={x10}" (res)
         : "{x11}" (major), "{x12}" (minor), "{x13}" (cb), "{x14}" (ud)
         : "memory"
         : "volatile" );
    res
}

#[cfg(target_arch = "arm")]
pub unsafe fn command(major: usize, minor: usize, arg1: usize, arg2: usize) -> isize {
    let res;
    asm!("svc 2" : "={r0}"(res)
                 : "{r0}"(major) "{r1}"(minor) "{r2}"(arg1) "{r3}"(arg2)
                 : "memory"
                 : "volatile");
    res
}

#[cfg(target_arch = "riscv32")]
pub unsafe fn command(major: usize, minor: usize, arg1: usize, arg2: usize) -> isize {
    let res;
    asm!("li    a0, 2
          ecall"
         : "={x10}" (res)
         : "{x11}" (major), "{x12}" (minor), "{x13}" (arg1), "{x14}" (arg2)
         : "memory"
         : "volatile");
    res
}

pub fn allow(
    driver_number: usize,
    allow_number: usize,
    buffer_to_share: &mut [u8],
) -> Result<SharedMemory, isize> {
    let len = buffer_to_share.len();
    let return_code = unsafe {
        allow_ptr(
            driver_number,
            allow_number,
            buffer_to_share.as_mut_ptr(),
            len,
        )
    };
    if return_code == 0 {
        Ok(SharedMemory::new(
            driver_number,
            allow_number,
            buffer_to_share,
        ))
    } else {
        Err(return_code)
    }
}

#[cfg(target_arch = "arm")]
pub unsafe fn allow_ptr(major: usize, minor: usize, slice: *mut u8, len: usize) -> isize {
    let res;
    asm!("svc 3" : "={r0}"(res)
                 : "{r0}"(major) "{r1}"(minor) "{r2}"(slice) "{r3}"(len)
                 : "memory"
                 : "volatile");
    res
}

#[cfg(target_arch = "riscv32")]
pub unsafe fn allow_ptr(major: usize, minor: usize, slice: *mut u8, len: usize) -> isize {
    let res;
    asm!("li    a0, 3
          ecall"
         : "={x10}" (res)
         : "{x11}" (major), "{x12}" (minor), "{x13}" (slice), "{x14}" (len)
         : "memory"
         : "volatile");
    res
}

#[cfg(target_arch = "arm")]
pub unsafe fn memop(major: u32, arg1: usize) -> isize {
    let res;
    asm!("svc 4" : "={r0}"(res)
                 : "{r0}"(major) "{r1}"(arg1)
                 : "memory"
                 : "volatile");
    res
}

#[cfg(target_arch = "riscv32")]
pub unsafe fn memop(major: u32, arg1: usize) -> isize {
    let res;
    asm!("li    a0, 4
          ecall"
         : "={x10}" (res)
         : "{x11}" (major), "{x12}" (arg1)
         : "memory"
         : "volatile");
    res
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use futures::{Future, Stream};

use std::cell::{RefCell};
use std::rc::{Rc, Weak};
use std::sync::Arc;

use stack::Stack;

enum Slot<T> {
    Next(usize),
    Data(T),
}

struct Inner<T, E> {
   // A slab of futures that are being executed. Each slot in this vector is
    // either an active future or a pointer to the next empty slot. This is used
    // to get O(1) deallocation in the slab and O(1) allocation.
    //
    // The `next_future` field is the next slot in the `futures` array that's a
    // `Slot::Next` variant. If it points to the end of the array then the array
    // is full.
    futures: Vec<Slot<Box<Future<Item=T, Error=E>>>>,
    next_future: usize,

    stack: Arc<Stack<usize>>,
    reaper: Box<TaskReaper<T, E>>,

    terminate_with: Option<Result<T, E>>,

    handle_count: usize,
    task: Option<::futures::task::Task>,
}

#[must_use = "a TaskSet does nothing unless polled"]
pub struct TaskSet<T, E> {
    inner: Rc<RefCell<Inner<T, E>>>,
}

impl<T, E> TaskSet<T, E> where T: 'static, E: 'static {
    pub fn new(reaper: Box<TaskReaper<T, E>>)
               -> (TaskSetHandle<T, E>, TaskSet<T, E>)
        where E: 'static, T: 'static, E: ::std::fmt::Debug,
    {
        let inner = Rc::new(RefCell::new(Inner {
            futures: Vec::new(),
            next_future: 0,
            stack: Arc::new(Stack::new()),
            reaper: reaper,
            terminate_with: None,
            handle_count: 1,
            task: None,
        }));

        let weak_inner = Rc::downgrade(&inner);

        let set = TaskSet {
            inner: inner,
        };

        let handle = TaskSetHandle {
            inner: weak_inner,
        };

        (handle, set)
    }
}

pub struct TaskSetHandle<T, E> {
    inner: Weak<RefCell<Inner<T, E>>>,
}

impl<T, E> Clone for TaskSetHandle<T, E> {
    fn clone(&self) -> TaskSetHandle<T, E> {
        match self.inner.upgrade() {
            None => (),
            Some(inner) => {
                inner.borrow_mut().handle_count += 1;
            }
        }
        TaskSetHandle {
            inner: self.inner.clone()
        }
    }
}

impl <T, E> Drop for TaskSetHandle<T, E> {
    fn drop(&mut self) {
        match self.inner.upgrade() {
            None => (),
            Some(inner) => {
                inner.borrow_mut().handle_count -= 1;
            }
        }
    }
}

impl <T, E> TaskSetHandle<T, E> where T: 'static, E: 'static {
    pub fn add<F>(&mut self, promise: F)
        where F: Future<Item=T, Error=E> + 'static
    {
        match self.inner.upgrade() {
            None => (),
            Some(rc_inner) => {
                let ref mut inner = *rc_inner.borrow_mut();
                let future = Box::new(promise);

                let added_idx = inner.next_future;
                if inner.next_future == inner.futures.len() {
                    inner.futures.push(Slot::Data(future));
                    inner.next_future += 1;
                } else {
                    match ::std::mem::replace(&mut inner.futures[inner.next_future],
                                              Slot::Data(future)) {
                        Slot::Next(next) => inner.next_future = next,
                        Slot::Data(_) => unreachable!(),
                    }
                }

                inner.stack.push(added_idx);

                match inner.task.take() {
                    Some(t) => t.unpark(),
                    None => (),
                }
            }
        }
    }

    pub fn terminate(&mut self, result: Result<T, E>) {
        match self.inner.upgrade() {
            None => (),
            Some(rc_inner) => {
                let ref mut inner = *rc_inner.borrow_mut();
                inner.terminate_with = Some(result);

                match inner.task.take() {
                    Some(t) => t.unpark(),
                    None => (),
                }
            }
        }
    }
}

pub trait TaskReaper<T, E> where T: 'static, E: 'static
{
    fn task_succeeded(&mut self, _value: T) {}
    fn task_failed(&mut self, error: E);
}

impl <T, E> Future for TaskSet<T, E> where T: 'static, E: 'static {
    type Item = T;
    type Error = E;

    fn poll(&mut self) -> ::futures::Poll<Self::Item, Self::Error> {
        let ref mut inner = *self.inner.borrow_mut();

        match inner.terminate_with.take() {
            None => (),
            Some(Ok(v)) => return Ok(::futures::Async::Ready(v)),
            Some(Err(e)) => return Err(e),
        }

        for idx in inner.stack.drain() {
            match inner.futures[idx] {
                Slot::Next(_) => unreachable!(),
                Slot::Data(ref mut f) => {
                    let event = ::futures::task::UnparkEvent::new(inner.stack.clone(), idx);
                    match ::futures::task::with_unpark_event(event, || f.poll()) {
                        Ok(::futures::Async::NotReady) => continue,
                        Ok(::futures::Async::Ready(v)) => {
                            inner.reaper.task_succeeded(v);
                        }
                        Err(e) => {
                            inner.reaper.task_failed(e);
                        }
                    }
                }
            }
            inner.futures[idx] = Slot::Next(inner.next_future);
            inner.next_future = idx;
        }

        inner.task = Some(::futures::task::park());
        Ok(::futures::Async::NotReady)
    }
}
<commit_msg>end if no handles and no work<commit_after>// Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use futures::{Future, Stream};

use std::cell::{RefCell};
use std::rc::{Rc, Weak};
use std::sync::Arc;

use stack::Stack;

enum Slot<T> {
    Next(usize),
    Data(T),
}

struct Inner<T, E> {
   // A slab of futures that are being executed. Each slot in this vector is
    // either an active future or a pointer to the next empty slot. This is used
    // to get O(1) deallocation in the slab and O(1) allocation.
    //
    // The `next_future` field is the next slot in the `futures` array that's a
    // `Slot::Next` variant. If it points to the end of the array then the array
    // is full.
    futures: Vec<Slot<Box<Future<Item=T, Error=E>>>>,
    next_future: usize,

    stack: Arc<Stack<usize>>,
    reaper: Box<TaskReaper<T, E>>,

    terminate_with: Option<Result<(), E>>,

    handle_count: usize,
    task: Option<::futures::task::Task>,
}

#[must_use = "a TaskSet does nothing unless polled"]
pub struct TaskSet<T, E> {
    inner: Rc<RefCell<Inner<T, E>>>,
}

impl<T, E> TaskSet<T, E> where T: 'static, E: 'static {
    pub fn new(reaper: Box<TaskReaper<T, E>>)
               -> (TaskSetHandle<T, E>, TaskSet<T, E>)
        where E: 'static, T: 'static, E: ::std::fmt::Debug,
    {
        let inner = Rc::new(RefCell::new(Inner {
            futures: Vec::new(),
            next_future: 0,
            stack: Arc::new(Stack::new()),
            reaper: reaper,
            terminate_with: None,
            handle_count: 1,
            task: None,
        }));

        let weak_inner = Rc::downgrade(&inner);

        let set = TaskSet {
            inner: inner,
        };

        let handle = TaskSetHandle {
            inner: weak_inner,
        };

        (handle, set)
    }
}

pub struct TaskSetHandle<T, E> {
    inner: Weak<RefCell<Inner<T, E>>>,
}

impl<T, E> Clone for TaskSetHandle<T, E> {
    fn clone(&self) -> TaskSetHandle<T, E> {
        match self.inner.upgrade() {
            None => (),
            Some(inner) => {
                inner.borrow_mut().handle_count += 1;
            }
        }
        TaskSetHandle {
            inner: self.inner.clone()
        }
    }
}

impl <T, E> Drop for TaskSetHandle<T, E> {
    fn drop(&mut self) {
        match self.inner.upgrade() {
            None => (),
            Some(inner) => {
                inner.borrow_mut().handle_count -= 1;
            }
        }
    }
}

impl <T, E> TaskSetHandle<T, E> where T: 'static, E: 'static {
    pub fn add<F>(&mut self, promise: F)
        where F: Future<Item=T, Error=E> + 'static
    {
        match self.inner.upgrade() {
            None => (),
            Some(rc_inner) => {
                let ref mut inner = *rc_inner.borrow_mut();
                let future = Box::new(promise);

                let added_idx = inner.next_future;
                if inner.next_future == inner.futures.len() {
                    inner.futures.push(Slot::Data(future));
                    inner.next_future += 1;
                } else {
                    match ::std::mem::replace(&mut inner.futures[inner.next_future],
                                              Slot::Data(future)) {
                        Slot::Next(next) => inner.next_future = next,
                        Slot::Data(_) => unreachable!(),
                    }
                }

                inner.stack.push(added_idx);

                match inner.task.take() {
                    Some(t) => t.unpark(),
                    None => (),
                }
            }
        }
    }

    pub fn terminate(&mut self, result: Result<(), E>) {
        match self.inner.upgrade() {
            None => (),
            Some(rc_inner) => {
                let ref mut inner = *rc_inner.borrow_mut();
                inner.terminate_with = Some(result);

                match inner.task.take() {
                    Some(t) => t.unpark(),
                    None => (),
                }
            }
        }
    }
}

pub trait TaskReaper<T, E> where T: 'static, E: 'static
{
    fn task_succeeded(&mut self, _value: T) {}
    fn task_failed(&mut self, error: E);
}

impl <T, E> Future for TaskSet<T, E> where T: 'static, E: 'static {
    type Item = ();
    type Error = E;

    fn poll(&mut self) -> ::futures::Poll<Self::Item, Self::Error> {
        let ref mut inner = *self.inner.borrow_mut();

        match inner.terminate_with.take() {
            None => (),
            Some(Ok(v)) => return Ok(::futures::Async::Ready(v)),
            Some(Err(e)) => return Err(e),
        }

        for idx in inner.stack.drain() {
            match inner.futures[idx] {
                Slot::Next(_) => unreachable!(),
                Slot::Data(ref mut f) => {
                    let event = ::futures::task::UnparkEvent::new(inner.stack.clone(), idx);
                    match ::futures::task::with_unpark_event(event, || f.poll()) {
                        Ok(::futures::Async::NotReady) => continue,
                        Ok(::futures::Async::Ready(v)) => {
                            inner.reaper.task_succeeded(v);
                        }
                        Err(e) => {
                            inner.reaper.task_failed(e);
                        }
                    }
                }
            }
            inner.futures[idx] = Slot::Next(inner.next_future);
            inner.next_future = idx;
        }

        if inner.futures.len() == 0 && inner.handle_count == 0 {
            Ok(::futures::Async::Ready(()))
        } else {
            inner.task = Some(::futures::task::park());
            Ok(::futures::Async::NotReady)
        }
    }
}
<|endoftext|>


<commit_before>use std::io::Stdin;
use std::io::Stdout;
use std::io::Write;

use super::lexer::Lexer;
use super::token::TokenType;

const PROMPT: &'static str = ">> ";

pub fn start(in_: Stdin, mut out: Stdout) {
    loop {
        print!("{}", PROMPT);
        out.flush().unwrap();

        let mut s = String::new();
        in_.read_line(&mut s).expect("Did not enter a correct string");

        let mut l = Lexer::new(s);
        let mut tok = l.next_token();
        while tok.token_type != TokenType::EOF {
            write!(&mut out, "{:?}\n", tok).unwrap();
            out.flush().unwrap();
            tok = l.next_token();
        }
    }
}
<commit_msg>Printing parsed program in REPL.<commit_after>use std::io::Stdin;
use std::io::Stdout;
use std::io::Write;

use super::lexer::Lexer;
use super::parser::Parser;
use super::ast::Node;

const PROMPT: &'static str = ">> ";

pub fn start(in_: Stdin, mut out: Stdout) {
    loop {
        print!("{}", PROMPT);
        out.flush().unwrap();

        let mut s = String::new();
        in_.read_line(&mut s).expect("Did not enter a correct string");

        let mut l = Lexer::new(s);
        let mut p = Parser::new(&mut l);
        let program = p.parse_program();
        if p.errors().len() != 0 {
            print_parser_errors(&mut out, p.errors());
            continue;
        }

        write!(&mut out, "{}\n", program.string()).expect("Failed to write to stdout");
    }
}

fn print_parser_errors(out: &mut Stdout, errors: &[String]) {
    for err in errors {
        write!(out, "{}\n", err).expect("Failed to write to stdout");
        out.flush().unwrap();
    }
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate sys_info;
extern crate test;

use sys_info::*;
use test::Bencher;

fn main() {

    println!("os: {} {}", os_type().unwrap(), os_release().unwrap());
    println!("cpu: {} cores, {} MHz", cpu_num().unwrap(), cpu_speed().unwrap());
    println!("proc total: {}", proc_total().unwrap());
    let load = loadavg().unwrap();
    println!("load: {} {} {}", load.one, load.five, load.fifteen);
    let mem = mem_info().unwrap();
    println!("mem: total {} KB, free {} KB, avail {} KB, buffers {} KB, cached {} KB",
             mem.total, mem.free, mem.avail, mem.buffers, mem.cached);
    println!("swap: total {} KB, free {} KB", mem.swap_total, mem.swap_free);
    let disk = disk_info().unwrap();
    println!("disk: total {} KB, free {} KB", disk.total, disk.free);
    println!("hostname: {}", hostname().unwrap());

}

#[bench]
fn bench_test(b: &mut Bencher) {
    b.iter(|| {
        let _ = loadavg();
        let _ = mem_info();
        let _ = disk_info();
    });
}

<commit_msg>fix test<commit_after>#![feature(test)]

extern crate "sys-info" as sys_info;
extern crate test;

use sys_info::*;
use test::Bencher;

fn main() {

    println!("os: {} {}", os_type().unwrap(), os_release().unwrap());
    println!("cpu: {} cores, {} MHz", cpu_num().unwrap(), cpu_speed().unwrap());
    println!("proc total: {}", proc_total().unwrap());
    let load = loadavg().unwrap();
    println!("load: {} {} {}", load.one, load.five, load.fifteen);
    let mem = mem_info().unwrap();
    println!("mem: total {} KB, free {} KB, avail {} KB, buffers {} KB, cached {} KB",
             mem.total, mem.free, mem.avail, mem.buffers, mem.cached);
    println!("swap: total {} KB, free {} KB", mem.swap_total, mem.swap_free);
    let disk = disk_info().unwrap();
    println!("disk: total {} KB, free {} KB", disk.total, disk.free);
    println!("hostname: {}", hostname().unwrap());

}

#[bench]
fn bench_test(b: &mut Bencher) {
    b.iter(|| {
        let _ = loadavg();
        let _ = mem_info();
        let _ = disk_info();
    });
}

<|endoftext|>


<commit_before>use clock::Clock;

//
// Clock Creation
//

#[test]
fn test_on_the_hour() {
    assert_eq!(Clock::new(8, 0).to_string(), "08:00");
}

#[test]
fn test_past_the_hour() {
    assert_eq!(Clock::new(11, 9).to_string(), "11:09");
}

#[test]
fn test_midnight_is_zero_hours() {
    assert_eq!(Clock::new(24, 0).to_string(), "00:00");
}

#[test]
fn test_hour_rolls_over() {
    assert_eq!(Clock::new(25, 0).to_string(), "01:00");
}

#[test]
fn test_hour_rolls_over_continuously() {
    assert_eq!(Clock::new(100, 0).to_string(), "04:00");
}

#[test]
fn test_sixty_minutes_is_next_hour() {
    assert_eq!(Clock::new(1, 60).to_string(), "02:00");
}

#[test]
fn test_minutes_roll_over() {
    assert_eq!(Clock::new(0, 160).to_string(), "02:40");
}

#[test]
fn test_minutes_roll_over_continuously() {
    assert_eq!(Clock::new(0, 1723).to_string(), "04:43");
}

#[test]
fn test_hours_and_minutes_roll_over() {
    assert_eq!(Clock::new(25, 160).to_string(), "03:40");
}

#[test]
fn test_hours_and_minutes_roll_over_continuously() {
    assert_eq!(Clock::new(201, 3001).to_string(), "11:01");
}

#[test]
fn test_hours_and_minutes_roll_over_to_exactly_midnight() {
    assert_eq!(Clock::new(72, 8640).to_string(), "00:00");
}

#[test]
fn test_negative_hour() {
    assert_eq!(Clock::new(-1, 15).to_string(), "23:15");
}

#[test]
fn test_negative_hour_roll_over() {
    assert_eq!(Clock::new(-25, 00).to_string(), "23:00");
}

#[test]
fn test_negative_hour_roll_over_continuously() {
    assert_eq!(Clock::new(-91, 00).to_string(), "05:00");
}

#[test]
#[ignore]
fn test_negative_minutes() {
    assert_eq!(Clock::new(1, -40).to_string(), "00:20");
}

#[test]
#[ignore]
fn test_negative_minutes_roll_over() {
    assert_eq!(Clock::new(1, -160).to_string(), "22:20");
}

#[test]
#[ignore]
fn test_negative_minutes_roll_over_continuously() {
    assert_eq!(Clock::new(1, -4820).to_string(), "16:40");
}

#[test]
#[ignore]
fn test_negative_sixty_minutes_is_prev_hour() {
    assert_eq!(Clock::new(2, -60).to_string(), "01:00");
}

#[test]
#[ignore]
fn test_negative_one_twenty_minutes_is_two_prev_hours() {
    assert_eq!(Clock::new(1, -120).to_string(), "23:00");
}

#[test]
#[ignore]
fn test_negative_hour_and_minutes_both_roll_over() {
    assert_eq!(Clock::new(-25, -160).to_string(), "20:20");
}

#[test]
#[ignore]
fn test_negative_hour_and_minutes_both_roll_over_continuously() {
    assert_eq!(Clock::new(-121, -5810).to_string(), "22:10");
}

#[test]
#[ignore]
fn test_zero_hour_and_negative_minutes() {
    assert_eq!(Clock::new(0, -22).to_string(), "23:38");
}

//
// Clock Math
//

#[test]
#[ignore]
fn test_add_minutes() {
    let clock = Clock::new(10, 0).add_minutes(3);
    assert_eq!(clock.to_string(), "10:03");
}

#[test]
#[ignore]
fn test_add_no_minutes() {
    let clock = Clock::new(6, 41).add_minutes(0);
    assert_eq!(clock.to_string(), "06:41");
}

#[test]
#[ignore]
fn test_add_to_next_hour() {
    let clock = Clock::new(0, 45).add_minutes(40);
    assert_eq!(clock.to_string(), "01:25");
}

#[test]
#[ignore]
fn test_add_more_than_one_hour() {
    let clock = Clock::new(10, 0).add_minutes(61);
    assert_eq!(clock.to_string(), "11:01");
}

#[test]
#[ignore]
fn test_add_more_than_two_hours_with_carry() {
    let clock = Clock::new(0, 45).add_minutes(160);
    assert_eq!(clock.to_string(), "03:25");
}

#[test]
#[ignore]
fn test_add_across_midnight() {
    let clock = Clock::new(23, 59).add_minutes(2);
    assert_eq!(clock.to_string(), "00:01");
}

#[test]
#[ignore]
fn test_add_more_than_one_day() {
    let clock = Clock::new(5, 32).add_minutes(1500);
    assert_eq!(clock.to_string(), "06:32");
}

#[test]
#[ignore]
fn test_add_more_than_two_days() {
    let clock = Clock::new(1, 1).add_minutes(3500);
    assert_eq!(clock.to_string(), "11:21");
}

#[test]
#[ignore]
fn test_subtract_minutes() {
    let clock = Clock::new(10, 3).add_minutes(-3);
    assert_eq!(clock.to_string(), "10:00");
}

#[test]
#[ignore]
fn test_subtract_to_previous_hour() {
    let clock = Clock::new(10, 3).add_minutes(-30);
    assert_eq!(clock.to_string(), "09:33");
}

#[test]
#[ignore]
fn test_subtract_more_than_an_hour() {
    let clock = Clock::new(10, 3).add_minutes(-70);
    assert_eq!(clock.to_string(), "08:53");
}

#[test]
#[ignore]
fn test_subtract_across_midnight() {
    let clock = Clock::new(0, 3).add_minutes(-4);
    assert_eq!(clock.to_string(), "23:59");
}

#[test]
#[ignore]
fn test_subtract_more_than_two_hours() {
    let clock = Clock::new(0, 0).add_minutes(-160);
    assert_eq!(clock.to_string(), "21:20");
}

#[test]
#[ignore]
fn test_subtract_more_than_two_hours_with_borrow() {
    let clock = Clock::new(6, 15).add_minutes(-160);
    assert_eq!(clock.to_string(), "03:35");
}

#[test]
#[ignore]
fn test_subtract_more_than_one_day() {
    let clock = Clock::new(5, 32).add_minutes(-1500);
    assert_eq!(clock.to_string(), "04:32");
}

#[test]
#[ignore]
fn test_subtract_more_than_two_days() {
    let clock = Clock::new(2, 20).add_minutes(-3000);
    assert_eq!(clock.to_string(), "00:20");
}

//
// Test Equality
//

#[test]
#[ignore]
fn test_compare_clocks_for_equality() {
    assert_eq!(Clock::new(15, 37), Clock::new(15, 37));
}

#[test]
#[ignore]
fn test_compare_clocks_a_minute_apart() {
    assert_ne!(Clock::new(15, 36), Clock::new(15, 37));
}

#[test]
#[ignore]
fn test_compare_clocks_an_hour_apart() {
    assert_ne!(Clock::new(14, 37), Clock::new(15, 37));
}

#[test]
#[ignore]
fn test_compare_clocks_with_hour_overflow() {
    assert_eq!(Clock::new(10, 37), Clock::new(34, 37));
}

#[test]
#[ignore]
fn test_compare_clocks_with_hour_overflow_by_several_days() {
    assert_eq!(Clock::new(99, 11), Clock::new(3, 11));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hour() {
    assert_eq!(Clock::new(-2, 40), Clock::new(22, 40));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hour_that_wraps() {
    assert_eq!(Clock::new(-31, 3), Clock::new(17, 3));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hour_that_wraps_multiple_times() {
    assert_eq!(Clock::new(-83, 49), Clock::new(13, 49));
}

#[test]
#[ignore]
fn test_compare_clocks_with_minutes_overflow() {
    assert_eq!(Clock::new(0, 1441), Clock::new(0, 1));
}

#[test]
#[ignore]
fn test_compare_clocks_with_minutes_overflow_by_several_days() {
    assert_eq!(Clock::new(2, 4322), Clock::new(2, 2));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_minute() {
    assert_eq!(Clock::new(3, -20), Clock::new(2, 40));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_minute_that_wraps() {
    assert_eq!(Clock::new(5, -1490), Clock::new(4, 10));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_minute_that_wraps_multiple() {
    assert_eq!(Clock::new(6, -4305), Clock::new(6, 15));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hours_and_minutes() {
    assert_eq!(Clock::new(-12, -268), Clock::new(7, 32));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hours_and_minutes_that_wrap() {
    assert_eq!(Clock::new(-54, -11_513), Clock::new(18, 7));
}

#[test]
#[ignore]
fn test_compare_full_clock_and_zeroed_clock() {
    assert_eq!(Clock::new(24, 0), Clock::new(0, 0));
}
<commit_msg>Uncomment passing tests<commit_after>use clock::Clock;

//
// Clock Creation
//

#[test]
fn test_on_the_hour() {
    assert_eq!(Clock::new(8, 0).to_string(), "08:00");
}

#[test]
fn test_past_the_hour() {
    assert_eq!(Clock::new(11, 9).to_string(), "11:09");
}

#[test]
fn test_midnight_is_zero_hours() {
    assert_eq!(Clock::new(24, 0).to_string(), "00:00");
}

#[test]
fn test_hour_rolls_over() {
    assert_eq!(Clock::new(25, 0).to_string(), "01:00");
}

#[test]
fn test_hour_rolls_over_continuously() {
    assert_eq!(Clock::new(100, 0).to_string(), "04:00");
}

#[test]
fn test_sixty_minutes_is_next_hour() {
    assert_eq!(Clock::new(1, 60).to_string(), "02:00");
}

#[test]
fn test_minutes_roll_over() {
    assert_eq!(Clock::new(0, 160).to_string(), "02:40");
}

#[test]
fn test_minutes_roll_over_continuously() {
    assert_eq!(Clock::new(0, 1723).to_string(), "04:43");
}

#[test]
fn test_hours_and_minutes_roll_over() {
    assert_eq!(Clock::new(25, 160).to_string(), "03:40");
}

#[test]
fn test_hours_and_minutes_roll_over_continuously() {
    assert_eq!(Clock::new(201, 3001).to_string(), "11:01");
}

#[test]
fn test_hours_and_minutes_roll_over_to_exactly_midnight() {
    assert_eq!(Clock::new(72, 8640).to_string(), "00:00");
}

#[test]
fn test_negative_hour() {
    assert_eq!(Clock::new(-1, 15).to_string(), "23:15");
}

#[test]
fn test_negative_hour_roll_over() {
    assert_eq!(Clock::new(-25, 00).to_string(), "23:00");
}

#[test]
fn test_negative_hour_roll_over_continuously() {
    assert_eq!(Clock::new(-91, 00).to_string(), "05:00");
}

#[test]
fn test_negative_minutes() {
    assert_eq!(Clock::new(1, -40).to_string(), "00:20");
}

#[test]
fn test_negative_minutes_roll_over() {
    assert_eq!(Clock::new(1, -160).to_string(), "22:20");
}

#[test]
fn test_negative_minutes_roll_over_continuously() {
    assert_eq!(Clock::new(1, -4820).to_string(), "16:40");
}

#[test]
fn test_negative_sixty_minutes_is_prev_hour() {
    assert_eq!(Clock::new(2, -60).to_string(), "01:00");
}

#[test]
fn test_negative_one_twenty_minutes_is_two_prev_hours() {
    assert_eq!(Clock::new(1, -120).to_string(), "23:00");
}

#[test]
fn test_negative_hour_and_minutes_both_roll_over() {
    assert_eq!(Clock::new(-25, -160).to_string(), "20:20");
}

#[test]
fn test_negative_hour_and_minutes_both_roll_over_continuously() {
    assert_eq!(Clock::new(-121, -5810).to_string(), "22:10");
}

#[test]
fn test_zero_hour_and_negative_minutes() {
    assert_eq!(Clock::new(0, -22).to_string(), "23:38");
}

//
// Clock Math
//

#[test]
#[ignore]
fn test_add_minutes() {
    let clock = Clock::new(10, 0).add_minutes(3);
    assert_eq!(clock.to_string(), "10:03");
}

#[test]
#[ignore]
fn test_add_no_minutes() {
    let clock = Clock::new(6, 41).add_minutes(0);
    assert_eq!(clock.to_string(), "06:41");
}

#[test]
#[ignore]
fn test_add_to_next_hour() {
    let clock = Clock::new(0, 45).add_minutes(40);
    assert_eq!(clock.to_string(), "01:25");
}

#[test]
#[ignore]
fn test_add_more_than_one_hour() {
    let clock = Clock::new(10, 0).add_minutes(61);
    assert_eq!(clock.to_string(), "11:01");
}

#[test]
#[ignore]
fn test_add_more_than_two_hours_with_carry() {
    let clock = Clock::new(0, 45).add_minutes(160);
    assert_eq!(clock.to_string(), "03:25");
}

#[test]
#[ignore]
fn test_add_across_midnight() {
    let clock = Clock::new(23, 59).add_minutes(2);
    assert_eq!(clock.to_string(), "00:01");
}

#[test]
#[ignore]
fn test_add_more_than_one_day() {
    let clock = Clock::new(5, 32).add_minutes(1500);
    assert_eq!(clock.to_string(), "06:32");
}

#[test]
#[ignore]
fn test_add_more_than_two_days() {
    let clock = Clock::new(1, 1).add_minutes(3500);
    assert_eq!(clock.to_string(), "11:21");
}

#[test]
#[ignore]
fn test_subtract_minutes() {
    let clock = Clock::new(10, 3).add_minutes(-3);
    assert_eq!(clock.to_string(), "10:00");
}

#[test]
#[ignore]
fn test_subtract_to_previous_hour() {
    let clock = Clock::new(10, 3).add_minutes(-30);
    assert_eq!(clock.to_string(), "09:33");
}

#[test]
#[ignore]
fn test_subtract_more_than_an_hour() {
    let clock = Clock::new(10, 3).add_minutes(-70);
    assert_eq!(clock.to_string(), "08:53");
}

#[test]
#[ignore]
fn test_subtract_across_midnight() {
    let clock = Clock::new(0, 3).add_minutes(-4);
    assert_eq!(clock.to_string(), "23:59");
}

#[test]
#[ignore]
fn test_subtract_more_than_two_hours() {
    let clock = Clock::new(0, 0).add_minutes(-160);
    assert_eq!(clock.to_string(), "21:20");
}

#[test]
#[ignore]
fn test_subtract_more_than_two_hours_with_borrow() {
    let clock = Clock::new(6, 15).add_minutes(-160);
    assert_eq!(clock.to_string(), "03:35");
}

#[test]
#[ignore]
fn test_subtract_more_than_one_day() {
    let clock = Clock::new(5, 32).add_minutes(-1500);
    assert_eq!(clock.to_string(), "04:32");
}

#[test]
#[ignore]
fn test_subtract_more_than_two_days() {
    let clock = Clock::new(2, 20).add_minutes(-3000);
    assert_eq!(clock.to_string(), "00:20");
}

//
// Test Equality
//

#[test]
#[ignore]
fn test_compare_clocks_for_equality() {
    assert_eq!(Clock::new(15, 37), Clock::new(15, 37));
}

#[test]
#[ignore]
fn test_compare_clocks_a_minute_apart() {
    assert_ne!(Clock::new(15, 36), Clock::new(15, 37));
}

#[test]
#[ignore]
fn test_compare_clocks_an_hour_apart() {
    assert_ne!(Clock::new(14, 37), Clock::new(15, 37));
}

#[test]
#[ignore]
fn test_compare_clocks_with_hour_overflow() {
    assert_eq!(Clock::new(10, 37), Clock::new(34, 37));
}

#[test]
#[ignore]
fn test_compare_clocks_with_hour_overflow_by_several_days() {
    assert_eq!(Clock::new(99, 11), Clock::new(3, 11));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hour() {
    assert_eq!(Clock::new(-2, 40), Clock::new(22, 40));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hour_that_wraps() {
    assert_eq!(Clock::new(-31, 3), Clock::new(17, 3));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hour_that_wraps_multiple_times() {
    assert_eq!(Clock::new(-83, 49), Clock::new(13, 49));
}

#[test]
#[ignore]
fn test_compare_clocks_with_minutes_overflow() {
    assert_eq!(Clock::new(0, 1441), Clock::new(0, 1));
}

#[test]
#[ignore]
fn test_compare_clocks_with_minutes_overflow_by_several_days() {
    assert_eq!(Clock::new(2, 4322), Clock::new(2, 2));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_minute() {
    assert_eq!(Clock::new(3, -20), Clock::new(2, 40));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_minute_that_wraps() {
    assert_eq!(Clock::new(5, -1490), Clock::new(4, 10));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_minute_that_wraps_multiple() {
    assert_eq!(Clock::new(6, -4305), Clock::new(6, 15));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hours_and_minutes() {
    assert_eq!(Clock::new(-12, -268), Clock::new(7, 32));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hours_and_minutes_that_wrap() {
    assert_eq!(Clock::new(-54, -11_513), Clock::new(18, 7));
}

#[test]
#[ignore]
fn test_compare_full_clock_and_zeroed_clock() {
    assert_eq!(Clock::new(24, 0), Clock::new(0, 0));
}
<|endoftext|>


<commit_before>#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        assert_eq!(2 + 2, 4);
    }
}
<commit_msg>Make Rust strprintf::fmt work for one argument<commit_after>macro_rules! fmt {
    ( $format:expr ) => {
        $format
    };
}

#[cfg(test)]
mod tests {
    #[test]
    fn returns_first_argument_if_it_is_the_only_one() {
        let input = "Hello, world!";
        assert_eq!(fmt!(input), input);
    }
}
<|endoftext|>


<commit_before>use std::ascii;
use std::ascii::Ascii;
use std::vec::Vec;

/// Member b is a vector of std::ascii::Ascii holding a word to be stemmed.
/// The letters are in b[0], b[1] ... ending at b[z->k]. Member k is readjusted
/// downwards as the stemming progresses. Zero termination is not in fact used
/// in the algorithm.
///
/// Note that only lower case sequences are stemmed. Forcing to lower case
/// should be done before get(...) is called.
///
///
/// Typical usage is:
///
///     let b = "pencils";
///     let res = stem::get(b);
///     assert_eq!(res, Ok("pencil".to_string()));
///
pub struct Stemmer {
    b: Vec<ascii::Ascii>,
    k: uint,
    j: uint,
}

impl Stemmer {
    pub fn new(word: &str) -> Result<Stemmer, &str> {
        if !word.is_ascii() {
            Err("Only support English words with ASCII characters")
        } else {
            let b = unsafe { word.to_ascii_nocheck().to_lowercase() };
            let k = b.len();
            Ok(Stemmer {
                b: b,
                k: k,
                j: 0,
            })
        }
    }

    /// stem.is_consonant(i) is true <=> stem[i] is a consonant
    pub fn is_consonant(&self, i: uint) -> bool {
        match self.b[i].to_char() {
            'a' | 'e' | 'i' | 'o' | 'u' => false,
            'y' => if i == 0 {
                true
            } else {
                !self.is_consonant(i - 1)
            },
            _ => true,
        }
    }

    /// stem.measure() measures the number of consonant sequences in [0, j).
    /// if c is a consonant sequence and v a vowel sequence, and <..> indicates
    /// arbitrary presence,
    ///
    /// ~~~notrust
    ///    <c><v>       gives 0
    ///    <c>vc<v>     gives 1
    ///    <c>vcvc<v>   gives 2
    ///    <c>vcvcvc<v> gives 3
    ///    ....
    /// ~~~
    pub fn measure(&self) -> uint {
        let mut n = 0u;
        let mut i = 0u;
        let j = self.j;
        loop {
            if i >= j { return n }
            if !self.is_consonant(i) { break }
            i += 1;
        }
        i += 1;
        loop {
            loop {
                if i >= j { return n }
                if self.is_consonant(i) { break }
                i += 1;
            }
            i += 1;
            n += 1;
            loop {
                if i >= j { return n }
                if !self.is_consonant(i) { break }
                i += 1;
            }
            i += 1;
        }
    }

    /// stem.has_vowel() is TRUE <=> [0, j-1) contains a vowel
    pub fn has_vowel(&self) -> bool {
        for i in range(0, self.j) {
            if !self.is_consonant(i) {
                return true;
            }
        }
        return false;
    }

    /// stem.double_consonant(i) is TRUE <=> i,(i-1) contain a double consonant.
    pub fn double_consonant(&self, i: uint) -> bool {
        if i < 1 {
            false
        } else if self.b[i] != self.b[i - 1] {
            false
        } else {
            self.is_consonant(i)
        }
    }

    /// cvc(z, i) is TRUE <=> i-2,i-1,i has the form consonant - vowel - consonant
    /// and also if the second c is not w,x or y. this is used when trying to
    /// restore an e at the end of a short word. e.g.
    ///
    /// ~~~notrust
    ///    cav(e), lov(e), hop(e), crim(e), but
    ///    snow, box, tray.
    /// ~~~
    pub fn cvc(&self, i: uint) -> bool {
        if i < 2 || !self.is_consonant(i) || self.is_consonant(i - 1)
            || !self.is_consonant(i - 2) { return false }
        match self.b[i].to_char() {
            'w' | 'x' | 'y' => false,
            _ => true,
        }
    }

    /// stem.ends(s) is true <=> [0, k) ends with the string s.
    pub fn ends(&mut self, s: &str) -> bool {
        let s = s.as_bytes();
        let len = s.len();
        let k = self.k;
        if s[len - 1] != self.b[k-1].to_byte() { return false } /* tiny speed-up */
        if len > k { return false }
        let mut iter = s.iter();
        for ac in self.b.slice(k - len, k).iter() {
            if ac.to_byte() != *iter.next().unwrap() { return false }
        }
        self.j = k - len;
        return true;
    }

    /// stem.setto(s) sets [j,k) to the characters in the string s,
    /// readjusting k.
    fn set_to(&mut self, s: &str) {
        let s = s.as_bytes();
        let length = s.len();
        let j = self.j;
        for i in range(0, length) {
            self.b.as_mut_slice()[j + i] = s[i].to_ascii();
        }
        self.k = j + length;
    }

    /// self.replace(s) is used further down.
    fn r(&mut self, s: &str) {
        if self.measure() > 0 {
            self.set_to(s);
        }
    }

    /// stem.step1ab() gets rid of plurals and -ed or -ing. e.g.
    ///
    /// ~~~~notrust
    ///     caresses  ->  caress
    ///     ponies    ->  poni
    ///     ties      ->  ti
    ///     caress    ->  caress
    ///     cats      ->  cat
    ///
    ///     feed      ->  feed
    ///     agreed    ->  agree
    ///     disabled  ->  disable
    ///
    ///     matting   ->  mat
    ///     mating    ->  mate
    ///     meeting   ->  meet
    ///     milling   ->  mill
    ///     messing   ->  mess
    ///
    ///     meetings  ->  meet
    /// ~~~~
    pub fn step1ab(&mut self) {
        if self.b[self.k - 1].to_char() == 's' {
            if self.ends("sses") {
                self.k -= 2;
            } else if self.ends("ies") {
                self.set_to("i");
            } else if self.b[self.k - 2].to_char() != 's' {
                self.k -= 1;
            }
        }
        if self.ends("eed") {
            if self.measure() > 0 { self.k -= 1 }
        } else if (self.ends("ed") || self.ends("ing")) && self.has_vowel() {
            self.k = self.j;
            if self.ends("at") {
                self.set_to("ate");
            } else if self.ends("bl") {
                self.set_to("ble");
            } else if self.ends("iz") {
                self.set_to("ize");
            } else if self.double_consonant(self.k - 1) {
                self.k -= 1;
                match self.b[self.k - 1].to_char() {
                    'l' | 's' | 'z' => self.k += 1,
                    _ => (),
                }
            } else if self.measure() == 1 && self.cvc(self.k - 1) {
                self.set_to("e");
            }
        }
    }

    /// stem.step1c() turns terminal y to i when there is another vowel in the stem.
    pub fn step1c(&mut self) {
       if self.ends("y") && self.has_vowel() {
           self.b.as_mut_slice()[self.k-1] = 'i'.to_ascii();
        }
    }

    /// stem.step2() maps double suffices to single ones. so -ization ( = -ize
    /// plus -ation) maps to -ize etc. note that the string before the suffix
    /// must give m(z) > 0.
    pub fn step2(&mut self) {
        match self.b[self.k-2].to_char() {
            'a' => {
                if self.ends("ational") { self.r("ate"); return }
                if self.ends("tional") { self.r("tion"); return }
            },
            'c' => {
                if self.ends("enci") { self.r("ence"); return }
                if self.ends("anci") { self.r("ance"); return }
            },
            'e' => if self.ends("izer") { self.r("ize"); return },
            'l' => {
                if self.ends("bli") { self.r("ble"); return } /*-DEPARTURE-*/

             /* To match the published algorithm, replace this line with
                'l' => {
                    if self.ends("abli") { self.r("able"); return } */

                 if self.ends("alli") { self.r("al"); return }
                 if self.ends("entli") { self.r("ent"); return }
                 if self.ends("eli") { self.r("e"); return }
                 if self.ends("ousli") { self.r("ous"); return }
            },
            'o' => {
                if self.ends("ization") { self.r("ize"); return }
                if self.ends("ation") { self.r("ate"); return }
                if self.ends("ator") { self.r("ate"); return }
            },
            's' => {
                if self.ends("alism") { self.r("al"); return }
                if self.ends("iveness") { self.r("ive"); return }
                if self.ends("fulness") { self.r("ful"); return }
                if self.ends("ousness") { self.r("ous"); return }
            },
            't' => {
                if self.ends("aliti") { self.r("al"); return }
                if self.ends("iviti") { self.r("ive"); return }
                if self.ends("biliti") { self.r("ble"); return }
            },
            'g' => if self.ends("logi") { self.r("log"); return }, /*-DEPARTURE-*/
             /* To match the published algorithm, delete this line */
            _ => (),
        }
    }

    /// stem.step3() deals with -ic-, -full, -ness etc. similar strategy to step2.
    pub fn step3(&mut self) {
        match self.b[self.k-1].to_char() {
            'e' => {
                if self.ends("icate") { self.r("ic"); return }
                if self.ends("ative") { self.r(""); return }
                if self.ends("alize") { self.r("al"); return }
            },
            'i' => if self.ends("iciti") { self.r("ic"); return },
            'l' => {
                if self.ends("ical") { self.r("ic"); return }
                if self.ends("ful") { self.r(""); return }
            },
            's' => if self.ends("ness") { self.r(""); return },
            _ => (),
        }
    }

    /// stem.step4() takes off -ant, -ence etc., in context <c>vcvc<v>.
    pub fn step4(&mut self) {
        match self.b[self.k-2].to_char() {
            'a' => {
                if self.ends("al") {}
                else { return }
            }
            'c' => {
                if self.ends("ance") {}
                else if self.ends("ence") {}
                else { return }
            },
            'e' => {
                if self.ends("er") {}
                else { return }
            }
            'i' => {
                if self.ends("ic") {}
                else { return }
            },
            'l' => {
                if self.ends("able") {}
                else if self.ends("ible") {}
                else { return }
            },
            'n' => {
                if self.ends("ant") {}
                else if self.ends("ement") {}
                else if self.ends("ment") {}
                else if self.ends("ent") {}
                else { return }
            },
            'o' => {
                if self.ends("ion")
                    && (self.b[self.j-1].to_char() == 's' || self.b[self.j-1].to_char() == 't') {}
                else if self.ends("ou") {}
                else { return }
                /* takes care of -ous */
            },
            's' => {
                if self.ends("ism") {}
                else { return }
            },
            't' => {
                if self.ends("ate") {}
                else if self.ends("iti") {}
                else { return }
            },
            'u' => {
                if self.ends("ous") {}
                else { return }
            },
            'v' => {
                if self.ends("ive") {}
                else { return }
            },
            'z' => {
                if self.ends("ize") {}
                else { return }
            },
            _ => return,
        }
        if self.measure() > 1 { self.k = self.j }
    }

    /// stem.step5() removes a final -e if self.measure() > 1, and changes -ll
    /// to -l if self.measure() > 1.
    pub fn step5(&mut self) {
       self.j = self.k;
       if self.b[self.k - 1].to_char() == 'e' {
           let a = self.measure();
           if a > 1 || a == 1 && !self.cvc(self.k - 2) { self.k -= 1 }
       }
       if self.b[self.k-1].to_char() == 'l'
           && self.double_consonant(self.k-1) && self.measure() > 1 {
           self.k-=1;
       }
    }

    pub fn get(&self) -> String {
        let borrowed = self.b.slice_to(self.k);
        borrowed.as_str_ascii().into_string()
    }
}

pub fn get(word: &str) -> Result<String, &str> {
    if word.len() > 2 {
        match Stemmer::new(word) {
            Ok(w) => {
                let mut mw = w;
                mw.step1ab();
                mw.step1c();
                mw.step2();
                mw.step3();
                mw.step4();
                mw.step5();
                Ok(mw.get())
            }
            Err(e) => Err(e),
        }
    } else {
        Ok(word.into_string())
    }
}

#[cfg(test)]
mod test {
    use std::io::File;
    use std::io::BufferedReader;
    use std::path;

    use super::get;

    #[test]
    fn lexicon() {
        let input = File::open(&path::Path::new("test-data/voc.txt")).unwrap();
        let result = File::open(&path::Path::new("test-data/output.txt")).unwrap();
        let mut input_reader = BufferedReader::new(input);
        let mut result_reader = BufferedReader::new(result);
        loop {
            match input_reader.read_line() {
                Ok(word) => match get(word.as_slice().trim()) {
                    Ok(stem) => {
                        match result_reader.read_line() {
                            Ok(answer) => if answer.as_slice().trim() != stem.as_slice() {
                                fail!("\n[FAILED] '{:s}' != '{:s}'", stem, answer);
                            } else {
                                print!(".");
                            },
                            Err(_) => break,
                        }
                    },
                    Err(e) => fail!("\n[FAILED] Cannot get stem for '{:s}': {:s}", word, e),
                },
                Err(_) => break,
            }
        }
        println!("");
    }
}
<commit_msg>fail! -> panic!<commit_after>use std::ascii;
use std::ascii::Ascii;
use std::vec::Vec;

/// Member b is a vector of std::ascii::Ascii holding a word to be stemmed.
/// The letters are in b[0], b[1] ... ending at b[z->k]. Member k is readjusted
/// downwards as the stemming progresses. Zero termination is not in fact used
/// in the algorithm.
///
/// Note that only lower case sequences are stemmed. Forcing to lower case
/// should be done before get(...) is called.
///
///
/// Typical usage is:
///
///     let b = "pencils";
///     let res = stem::get(b);
///     assert_eq!(res, Ok("pencil".to_string()));
///
pub struct Stemmer {
    b: Vec<ascii::Ascii>,
    k: uint,
    j: uint,
}

impl Stemmer {
    pub fn new(word: &str) -> Result<Stemmer, &str> {
        if !word.is_ascii() {
            Err("Only support English words with ASCII characters")
        } else {
            let b = unsafe { word.to_ascii_nocheck().to_lowercase() };
            let k = b.len();
            Ok(Stemmer {
                b: b,
                k: k,
                j: 0,
            })
        }
    }

    /// stem.is_consonant(i) is true <=> stem[i] is a consonant
    pub fn is_consonant(&self, i: uint) -> bool {
        match self.b[i].to_char() {
            'a' | 'e' | 'i' | 'o' | 'u' => false,
            'y' => if i == 0 {
                true
            } else {
                !self.is_consonant(i - 1)
            },
            _ => true,
        }
    }

    /// stem.measure() measures the number of consonant sequences in [0, j).
    /// if c is a consonant sequence and v a vowel sequence, and <..> indicates
    /// arbitrary presence,
    ///
    /// ~~~notrust
    ///    <c><v>       gives 0
    ///    <c>vc<v>     gives 1
    ///    <c>vcvc<v>   gives 2
    ///    <c>vcvcvc<v> gives 3
    ///    ....
    /// ~~~
    pub fn measure(&self) -> uint {
        let mut n = 0u;
        let mut i = 0u;
        let j = self.j;
        loop {
            if i >= j { return n }
            if !self.is_consonant(i) { break }
            i += 1;
        }
        i += 1;
        loop {
            loop {
                if i >= j { return n }
                if self.is_consonant(i) { break }
                i += 1;
            }
            i += 1;
            n += 1;
            loop {
                if i >= j { return n }
                if !self.is_consonant(i) { break }
                i += 1;
            }
            i += 1;
        }
    }

    /// stem.has_vowel() is TRUE <=> [0, j-1) contains a vowel
    pub fn has_vowel(&self) -> bool {
        for i in range(0, self.j) {
            if !self.is_consonant(i) {
                return true;
            }
        }
        return false;
    }

    /// stem.double_consonant(i) is TRUE <=> i,(i-1) contain a double consonant.
    pub fn double_consonant(&self, i: uint) -> bool {
        if i < 1 {
            false
        } else if self.b[i] != self.b[i - 1] {
            false
        } else {
            self.is_consonant(i)
        }
    }

    /// cvc(z, i) is TRUE <=> i-2,i-1,i has the form consonant - vowel - consonant
    /// and also if the second c is not w,x or y. this is used when trying to
    /// restore an e at the end of a short word. e.g.
    ///
    /// ~~~notrust
    ///    cav(e), lov(e), hop(e), crim(e), but
    ///    snow, box, tray.
    /// ~~~
    pub fn cvc(&self, i: uint) -> bool {
        if i < 2 || !self.is_consonant(i) || self.is_consonant(i - 1)
            || !self.is_consonant(i - 2) { return false }
        match self.b[i].to_char() {
            'w' | 'x' | 'y' => false,
            _ => true,
        }
    }

    /// stem.ends(s) is true <=> [0, k) ends with the string s.
    pub fn ends(&mut self, s: &str) -> bool {
        let s = s.as_bytes();
        let len = s.len();
        let k = self.k;
        if s[len - 1] != self.b[k-1].to_byte() { return false } /* tiny speed-up */
        if len > k { return false }
        let mut iter = s.iter();
        for ac in self.b.slice(k - len, k).iter() {
            if ac.to_byte() != *iter.next().unwrap() { return false }
        }
        self.j = k - len;
        return true;
    }

    /// stem.setto(s) sets [j,k) to the characters in the string s,
    /// readjusting k.
    fn set_to(&mut self, s: &str) {
        let s = s.as_bytes();
        let length = s.len();
        let j = self.j;
        for i in range(0, length) {
            self.b.as_mut_slice()[j + i] = s[i].to_ascii();
        }
        self.k = j + length;
    }

    /// self.replace(s) is used further down.
    fn r(&mut self, s: &str) {
        if self.measure() > 0 {
            self.set_to(s);
        }
    }

    /// stem.step1ab() gets rid of plurals and -ed or -ing. e.g.
    ///
    /// ~~~~notrust
    ///     caresses  ->  caress
    ///     ponies    ->  poni
    ///     ties      ->  ti
    ///     caress    ->  caress
    ///     cats      ->  cat
    ///
    ///     feed      ->  feed
    ///     agreed    ->  agree
    ///     disabled  ->  disable
    ///
    ///     matting   ->  mat
    ///     mating    ->  mate
    ///     meeting   ->  meet
    ///     milling   ->  mill
    ///     messing   ->  mess
    ///
    ///     meetings  ->  meet
    /// ~~~~
    pub fn step1ab(&mut self) {
        if self.b[self.k - 1].to_char() == 's' {
            if self.ends("sses") {
                self.k -= 2;
            } else if self.ends("ies") {
                self.set_to("i");
            } else if self.b[self.k - 2].to_char() != 's' {
                self.k -= 1;
            }
        }
        if self.ends("eed") {
            if self.measure() > 0 { self.k -= 1 }
        } else if (self.ends("ed") || self.ends("ing")) && self.has_vowel() {
            self.k = self.j;
            if self.ends("at") {
                self.set_to("ate");
            } else if self.ends("bl") {
                self.set_to("ble");
            } else if self.ends("iz") {
                self.set_to("ize");
            } else if self.double_consonant(self.k - 1) {
                self.k -= 1;
                match self.b[self.k - 1].to_char() {
                    'l' | 's' | 'z' => self.k += 1,
                    _ => (),
                }
            } else if self.measure() == 1 && self.cvc(self.k - 1) {
                self.set_to("e");
            }
        }
    }

    /// stem.step1c() turns terminal y to i when there is another vowel in the stem.
    pub fn step1c(&mut self) {
       if self.ends("y") && self.has_vowel() {
           self.b.as_mut_slice()[self.k-1] = 'i'.to_ascii();
        }
    }

    /// stem.step2() maps double suffices to single ones. so -ization ( = -ize
    /// plus -ation) maps to -ize etc. note that the string before the suffix
    /// must give m(z) > 0.
    pub fn step2(&mut self) {
        match self.b[self.k-2].to_char() {
            'a' => {
                if self.ends("ational") { self.r("ate"); return }
                if self.ends("tional") { self.r("tion"); return }
            },
            'c' => {
                if self.ends("enci") { self.r("ence"); return }
                if self.ends("anci") { self.r("ance"); return }
            },
            'e' => if self.ends("izer") { self.r("ize"); return },
            'l' => {
                if self.ends("bli") { self.r("ble"); return } /*-DEPARTURE-*/

             /* To match the published algorithm, replace this line with
                'l' => {
                    if self.ends("abli") { self.r("able"); return } */

                 if self.ends("alli") { self.r("al"); return }
                 if self.ends("entli") { self.r("ent"); return }
                 if self.ends("eli") { self.r("e"); return }
                 if self.ends("ousli") { self.r("ous"); return }
            },
            'o' => {
                if self.ends("ization") { self.r("ize"); return }
                if self.ends("ation") { self.r("ate"); return }
                if self.ends("ator") { self.r("ate"); return }
            },
            's' => {
                if self.ends("alism") { self.r("al"); return }
                if self.ends("iveness") { self.r("ive"); return }
                if self.ends("fulness") { self.r("ful"); return }
                if self.ends("ousness") { self.r("ous"); return }
            },
            't' => {
                if self.ends("aliti") { self.r("al"); return }
                if self.ends("iviti") { self.r("ive"); return }
                if self.ends("biliti") { self.r("ble"); return }
            },
            'g' => if self.ends("logi") { self.r("log"); return }, /*-DEPARTURE-*/
             /* To match the published algorithm, delete this line */
            _ => (),
        }
    }

    /// stem.step3() deals with -ic-, -full, -ness etc. similar strategy to step2.
    pub fn step3(&mut self) {
        match self.b[self.k-1].to_char() {
            'e' => {
                if self.ends("icate") { self.r("ic"); return }
                if self.ends("ative") { self.r(""); return }
                if self.ends("alize") { self.r("al"); return }
            },
            'i' => if self.ends("iciti") { self.r("ic"); return },
            'l' => {
                if self.ends("ical") { self.r("ic"); return }
                if self.ends("ful") { self.r(""); return }
            },
            's' => if self.ends("ness") { self.r(""); return },
            _ => (),
        }
    }

    /// stem.step4() takes off -ant, -ence etc., in context <c>vcvc<v>.
    pub fn step4(&mut self) {
        match self.b[self.k-2].to_char() {
            'a' => {
                if self.ends("al") {}
                else { return }
            }
            'c' => {
                if self.ends("ance") {}
                else if self.ends("ence") {}
                else { return }
            },
            'e' => {
                if self.ends("er") {}
                else { return }
            }
            'i' => {
                if self.ends("ic") {}
                else { return }
            },
            'l' => {
                if self.ends("able") {}
                else if self.ends("ible") {}
                else { return }
            },
            'n' => {
                if self.ends("ant") {}
                else if self.ends("ement") {}
                else if self.ends("ment") {}
                else if self.ends("ent") {}
                else { return }
            },
            'o' => {
                if self.ends("ion")
                    && (self.b[self.j-1].to_char() == 's' || self.b[self.j-1].to_char() == 't') {}
                else if self.ends("ou") {}
                else { return }
                /* takes care of -ous */
            },
            's' => {
                if self.ends("ism") {}
                else { return }
            },
            't' => {
                if self.ends("ate") {}
                else if self.ends("iti") {}
                else { return }
            },
            'u' => {
                if self.ends("ous") {}
                else { return }
            },
            'v' => {
                if self.ends("ive") {}
                else { return }
            },
            'z' => {
                if self.ends("ize") {}
                else { return }
            },
            _ => return,
        }
        if self.measure() > 1 { self.k = self.j }
    }

    /// stem.step5() removes a final -e if self.measure() > 1, and changes -ll
    /// to -l if self.measure() > 1.
    pub fn step5(&mut self) {
       self.j = self.k;
       if self.b[self.k - 1].to_char() == 'e' {
           let a = self.measure();
           if a > 1 || a == 1 && !self.cvc(self.k - 2) { self.k -= 1 }
       }
       if self.b[self.k-1].to_char() == 'l'
           && self.double_consonant(self.k-1) && self.measure() > 1 {
           self.k-=1;
       }
    }

    pub fn get(&self) -> String {
        let borrowed = self.b.slice_to(self.k);
        borrowed.as_str_ascii().into_string()
    }
}

pub fn get(word: &str) -> Result<String, &str> {
    if word.len() > 2 {
        match Stemmer::new(word) {
            Ok(w) => {
                let mut mw = w;
                mw.step1ab();
                mw.step1c();
                mw.step2();
                mw.step3();
                mw.step4();
                mw.step5();
                Ok(mw.get())
            }
            Err(e) => Err(e),
        }
    } else {
        Ok(word.into_string())
    }
}

#[cfg(test)]
mod test {
    use std::io::File;
    use std::io::BufferedReader;
    use std::path;

    use super::get;

    #[test]
    fn lexicon() {
        let input = File::open(&path::Path::new("test-data/voc.txt")).unwrap();
        let result = File::open(&path::Path::new("test-data/output.txt")).unwrap();
        let mut input_reader = BufferedReader::new(input);
        let mut result_reader = BufferedReader::new(result);
        loop {
            match input_reader.read_line() {
                Ok(word) => match get(word.as_slice().trim()) {
                    Ok(stem) => {
                        match result_reader.read_line() {
                            Ok(answer) => if answer.as_slice().trim() != stem.as_slice() {
                                panic!("\n[FAILED] '{:s}' != '{:s}'", stem, answer);
                            } else {
                                print!(".");
                            },
                            Err(_) => break,
                        }
                    },
                    Err(e) => panic!("\n[FAILED] Cannot get stem for '{:s}': {:s}", word, e),
                },
                Err(_) => break,
            }
        }
        println!("");
    }
}
<|endoftext|>