<commit_before>use sodiumoxide::crypto::hash::sha256::Digest;

use super::*;
use crate::crypto::{double_sha256, PublicKey};
use crate::script::Script;

pub const SCRIPT_HASH_BUF_PREFIX: u8 = 0x03;

#[derive(Debug, Clone, PartialEq)]
pub struct ScriptHash(Digest);

impl ScriptHash {
    #[inline]
    pub fn from_slice(slice: &[u8]) -> Option<ScriptHash> {
        let digest = Digest::from_slice(slice)?;
        Some(ScriptHash(digest))
    }
}

impl Wif<ScriptHash, Box<str>> for ScriptHash {
    fn from_wif(s: &str) -> Result<ScriptHash, WifError> {
        if s.len() < 3 || &s[0..3] != PUB_ADDRESS_PREFIX {
            return Err(WifError::new(WifErrorKind::InvalidPrefix));
        }
        let raw = match bs58::decode(&s[3..]).into_vec() {
            Ok(bytes) => bytes,
            Err(_) => {
                return Err(WifError::new(WifErrorKind::InvalidBs58Encoding));
            }
        };
        if raw.len() != 37 {
            return Err(WifError::new(WifErrorKind::InvalidLen));
        } else if raw[0] != SCRIPT_HASH_BUF_PREFIX {
            return Err(WifError::new(WifErrorKind::InvalidPrefix));
        }

        let prefixed_key = &raw[0..raw.len() - 4];
        {
            let checksum_a = &raw[raw.len() - 4..raw.len()];
            let checksum_b = &double_sha256(prefixed_key)[0..4];
            if checksum_a != checksum_b {
                return Err(WifError::new(WifErrorKind::InvalidChecksum));
            }
        }

        let key = &prefixed_key[1..prefixed_key.len()];
        Ok(ScriptHash::from_slice(key).unwrap())
    }

    fn to_wif(&self) -> Box<str> {
        let mut buf: Vec<u8> = Vec::<u8>::with_capacity(37);
        buf.push(SCRIPT_HASH_BUF_PREFIX);
        buf.extend_from_slice(self.0.as_ref());

        let checksum = &double_sha256(&buf)[0..4];
        buf.extend_from_slice(checksum);

        let mut s = bs58::encode(buf).into_string();
        s.insert_str(0, PUB_ADDRESS_PREFIX);
        s.into_boxed_str()
    }
}

impl From<&Script> for ScriptHash {
    fn from(script: &Script) -> ScriptHash {
        let hash = double_sha256(script);
        ScriptHash(hash)
    }
}

impl From<PublicKey> for ScriptHash {
    fn from(key: PublicKey) -> ScriptHash {
        let script: Script = key.into();
        key.into()
    }
}

impl From<&PublicKey> for ScriptHash {
    fn from(key: &PublicKey) -> ScriptHash {
        let script: Script = key.clone().into();
        key.into()
    }
}

impl AsRef<[u8]> for ScriptHash {
    fn as_ref(&self) -> &[u8] {
        self.0.as_ref()
    }
}
<commit_msg>Fix PublicKey -> ScriptHash conversion<commit_after>use sodiumoxide::crypto::hash::sha256::Digest;

use super::*;
use crate::crypto::{double_sha256, PublicKey};
use crate::script::Script;

pub const SCRIPT_HASH_BUF_PREFIX: u8 = 0x03;

#[derive(Debug, Clone, PartialEq)]
pub struct ScriptHash(Digest);

impl ScriptHash {
    #[inline]
    pub fn from_slice(slice: &[u8]) -> Option<ScriptHash> {
        let digest = Digest::from_slice(slice)?;
        Some(ScriptHash(digest))
    }
}

impl Wif<ScriptHash, Box<str>> for ScriptHash {
    fn from_wif(s: &str) -> Result<ScriptHash, WifError> {
        if s.len() < 3 || &s[0..3] != PUB_ADDRESS_PREFIX {
            return Err(WifError::new(WifErrorKind::InvalidPrefix));
        }
        let raw = match bs58::decode(&s[3..]).into_vec() {
            Ok(bytes) => bytes,
            Err(_) => {
                return Err(WifError::new(WifErrorKind::InvalidBs58Encoding));
            }
        };
        if raw.len() != 37 {
            return Err(WifError::new(WifErrorKind::InvalidLen));
        } else if raw[0] != SCRIPT_HASH_BUF_PREFIX {
            return Err(WifError::new(WifErrorKind::InvalidPrefix));
        }

        let prefixed_key = &raw[0..raw.len() - 4];
        {
            let checksum_a = &raw[raw.len() - 4..raw.len()];
            let checksum_b = &double_sha256(prefixed_key)[0..4];
            if checksum_a != checksum_b {
                return Err(WifError::new(WifErrorKind::InvalidChecksum));
            }
        }

        let key = &prefixed_key[1..prefixed_key.len()];
        Ok(ScriptHash::from_slice(key).unwrap())
    }

    fn to_wif(&self) -> Box<str> {
        let mut buf: Vec<u8> = Vec::<u8>::with_capacity(37);
        buf.push(SCRIPT_HASH_BUF_PREFIX);
        buf.extend_from_slice(self.0.as_ref());

        let checksum = &double_sha256(&buf)[0..4];
        buf.extend_from_slice(checksum);

        let mut s = bs58::encode(buf).into_string();
        s.insert_str(0, PUB_ADDRESS_PREFIX);
        s.into_boxed_str()
    }
}

impl From<&Script> for ScriptHash {
    fn from(script: &Script) -> ScriptHash {
        let hash = double_sha256(script);
        ScriptHash(hash)
    }
}

impl From<Script> for ScriptHash {
    fn from(script: Script) -> ScriptHash {
        (&script).into()
    }
}

impl From<PublicKey> for ScriptHash {
    fn from(key: PublicKey) -> ScriptHash {
        let script: Script = key.into();
        script.into()
    }
}

impl From<&PublicKey> for ScriptHash {
    fn from(key: &PublicKey) -> ScriptHash {
        let script: Script = key.clone().into();
        script.into()
    }
}

impl AsRef<[u8]> for ScriptHash {
    fn as_ref(&self) -> &[u8] {
        self.0.as_ref()
    }
}
<|endoftext|>


<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! An "interner" is a data structure that associates values with uint tags and
//! allows bidirectional lookup; i.e. given a value, one can easily find the
//! type, and vice versa.

use ast::Name;

use std::collections::HashMap;
use std::cell::RefCell;
use std::cmp::Equiv;
use std::fmt;
use std::hash::Hash;
use std::mem;
use std::rc::Rc;

pub struct Interner<T> {
    map: RefCell<HashMap<T, Name>>,
    vect: RefCell<Vec<T> >,
}

// when traits can extend traits, we should extend index<Name,T> to get []
impl<T: Eq + Hash + Clone + 'static> Interner<T> {
    pub fn new() -> Interner<T> {
        Interner {
            map: RefCell::new(HashMap::new()),
            vect: RefCell::new(Vec::new()),
        }
    }

    pub fn prefill(init: &[T]) -> Interner<T> {
        let rv = Interner::new();
        for v in init.iter() {
            rv.intern((*v).clone());
        }
        rv
    }

    pub fn intern(&self, val: T) -> Name {
        let mut map = self.map.borrow_mut();
        match (*map).find(&val) {
            Some(&idx) => return idx,
            None => (),
        }

        let mut vect = self.vect.borrow_mut();
        let new_idx = Name((*vect).len() as u32);
        (*map).insert(val.clone(), new_idx);
        (*vect).push(val);
        new_idx
    }

    pub fn gensym(&self, val: T) -> Name {
        let mut vect = self.vect.borrow_mut();
        let new_idx = Name((*vect).len() as u32);
        // leave out of .map to avoid colliding
        (*vect).push(val);
        new_idx
    }

    pub fn get(&self, idx: Name) -> T {
        let vect = self.vect.borrow();
        (*(*vect).get(idx.uint())).clone()
    }

    pub fn len(&self) -> uint {
        let vect = self.vect.borrow();
        (*vect).len()
    }

    pub fn find_equiv<Q:Hash + Equiv<T>>(&self, val: &Q) -> Option<Name> {
        let map = self.map.borrow();
        match (*map).find_equiv(val) {
            Some(v) => Some(*v),
            None => None,
        }
    }

    pub fn clear(&self) {
        *self.map.borrow_mut() = HashMap::new();
        *self.vect.borrow_mut() = Vec::new();
    }
}

#[deriving(Clone, PartialEq, Hash, PartialOrd)]
pub struct RcStr {
    string: Rc<String>,
}

impl Eq for RcStr {}

impl Ord for RcStr {
    fn cmp(&self, other: &RcStr) -> Ordering {
        self.as_slice().cmp(&other.as_slice())
    }
}

impl Str for RcStr {
    #[inline]
    fn as_slice<'a>(&'a self) -> &'a str {
        let s: &'a str = self.string.as_slice();
        s
    }
}

impl fmt::Show for RcStr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use std::fmt::Show;
        self.as_slice().fmt(f)
    }
}

impl RcStr {
    pub fn new(string: &str) -> RcStr {
        RcStr {
            string: Rc::new(string.to_string()),
        }
    }
}

/// A StrInterner differs from Interner<String> in that it accepts
/// &str rather than RcStr, resulting in less allocation.
pub struct StrInterner {
    map: RefCell<HashMap<RcStr, Name>>,
    vect: RefCell<Vec<RcStr> >,
}

/// When traits can extend traits, we should extend index<Name,T> to get []
impl StrInterner {
    pub fn new() -> StrInterner {
        StrInterner {
            map: RefCell::new(HashMap::new()),
            vect: RefCell::new(Vec::new()),
        }
    }

    pub fn prefill(init: &[&str]) -> StrInterner {
        let rv = StrInterner::new();
        for &v in init.iter() { rv.intern(v); }
        rv
    }

    pub fn intern(&self, val: &str) -> Name {
        let mut map = self.map.borrow_mut();
        match map.find_equiv(&val) {
            Some(&idx) => return idx,
            None => (),
        }

        let new_idx = Name(self.len() as u32);
        let val = RcStr::new(val);
        map.insert(val.clone(), new_idx);
        self.vect.borrow_mut().push(val);
        new_idx
    }

    pub fn gensym(&self, val: &str) -> Name {
        let new_idx = Name(self.len() as u32);
        // leave out of .map to avoid colliding
        self.vect.borrow_mut().push(RcStr::new(val));
        new_idx
    }

    // I want these gensyms to share name pointers
    // with existing entries. This would be automatic,
    // except that the existing gensym creates its
    // own managed ptr using to_managed. I think that
    // adding this utility function is the most
    // lightweight way to get what I want, though not
    // necessarily the cleanest.

    /// Create a gensym with the same name as an existing
    /// entry.
    pub fn gensym_copy(&self, idx : Name) -> Name {
        let new_idx = Name(self.len() as u32);
        // leave out of map to avoid colliding
        let mut vect = self.vect.borrow_mut();
        let existing = (*vect.get(idx.uint())).clone();
        vect.push(existing);
        new_idx
    }

    pub fn get(&self, idx: Name) -> RcStr {
        (*self.vect.borrow().get(idx.uint())).clone()
    }

    /// Returns this string with lifetime tied to the interner. Since
    /// strings may never be removed from the interner, this is safe.
    pub fn get_ref<'a>(&'a self, idx: Name) -> &'a str {
        let vect = self.vect.borrow();
        let s: &str = vect.get(idx.uint()).as_slice();
        unsafe {
            mem::transmute(s)
        }
    }

    pub fn len(&self) -> uint {
        self.vect.borrow().len()
    }

    pub fn find_equiv<Q:Hash + Equiv<RcStr>>(&self, val: &Q) -> Option<Name> {
        match (*self.map.borrow()).find_equiv(val) {
            Some(v) => Some(*v),
            None => None,
        }
    }

    pub fn clear(&self) {
        *self.map.borrow_mut() = HashMap::new();
        *self.vect.borrow_mut() = Vec::new();
    }
}

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

    #[test]
    #[should_fail]
    fn i1 () {
        let i : Interner<RcStr> = Interner::new();
        i.get(Name(13));
    }

    #[test]
    fn interner_tests () {
        let i : Interner<RcStr> = Interner::new();
        // first one is zero:
        assert_eq!(i.intern(RcStr::new("dog")), Name(0));
        // re-use gets the same entry:
        assert_eq!(i.intern(RcStr::new("dog")), Name(0));
        // different string gets a different #:
        assert_eq!(i.intern(RcStr::new("cat")), Name(1));
        assert_eq!(i.intern(RcStr::new("cat")), Name(1));
        // dog is still at zero
        assert_eq!(i.intern(RcStr::new("dog")), Name(0));
        // gensym gets 3
        assert_eq!(i.gensym(RcStr::new("zebra") ), Name(2));
        // gensym of same string gets new number :
        assert_eq!(i.gensym (RcStr::new("zebra") ), Name(3));
        // gensym of *existing* string gets new number:
        assert_eq!(i.gensym(RcStr::new("dog")), Name(4));
        assert_eq!(i.get(Name(0)), RcStr::new("dog"));
        assert_eq!(i.get(Name(1)), RcStr::new("cat"));
        assert_eq!(i.get(Name(2)), RcStr::new("zebra"));
        assert_eq!(i.get(Name(3)), RcStr::new("zebra"));
        assert_eq!(i.get(Name(4)), RcStr::new("dog"));
    }

    #[test]
    fn i3 () {
        let i : Interner<RcStr> = Interner::prefill([
            RcStr::new("Alan"),
            RcStr::new("Bob"),
            RcStr::new("Carol")
        ]);
        assert_eq!(i.get(Name(0)), RcStr::new("Alan"));
        assert_eq!(i.get(Name(1)), RcStr::new("Bob"));
        assert_eq!(i.get(Name(2)), RcStr::new("Carol"));
        assert_eq!(i.intern(RcStr::new("Bob")), Name(1));
    }

    #[test]
    fn string_interner_tests() {
        let i : StrInterner = StrInterner::new();
        // first one is zero:
        assert_eq!(i.intern("dog"), Name(0));
        // re-use gets the same entry:
        assert_eq!(i.intern ("dog"), Name(0));
        // different string gets a different #:
        assert_eq!(i.intern("cat"), Name(1));
        assert_eq!(i.intern("cat"), Name(1));
        // dog is still at zero
        assert_eq!(i.intern("dog"), Name(0));
        // gensym gets 3
        assert_eq!(i.gensym("zebra"), Name(2));
        // gensym of same string gets new number :
        assert_eq!(i.gensym("zebra"), Name(3));
        // gensym of *existing* string gets new number:
        assert_eq!(i.gensym("dog"), Name(4));
        // gensym tests again with gensym_copy:
        assert_eq!(i.gensym_copy(Name(2)), Name(5));
        assert_eq!(i.get(Name(5)), RcStr::new("zebra"));
        assert_eq!(i.gensym_copy(Name(2)), Name(6));
        assert_eq!(i.get(Name(6)), RcStr::new("zebra"));
        assert_eq!(i.get(Name(0)), RcStr::new("dog"));
        assert_eq!(i.get(Name(1)), RcStr::new("cat"));
        assert_eq!(i.get(Name(2)), RcStr::new("zebra"));
        assert_eq!(i.get(Name(3)), RcStr::new("zebra"));
        assert_eq!(i.get(Name(4)), RcStr::new("dog"));
    }
}
<commit_msg>Remove unused, unsound method on StrInterner<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! An "interner" is a data structure that associates values with uint tags and
//! allows bidirectional lookup; i.e. given a value, one can easily find the
//! type, and vice versa.

use ast::Name;

use std::collections::HashMap;
use std::cell::RefCell;
use std::cmp::Equiv;
use std::fmt;
use std::hash::Hash;
use std::rc::Rc;

pub struct Interner<T> {
    map: RefCell<HashMap<T, Name>>,
    vect: RefCell<Vec<T> >,
}

// when traits can extend traits, we should extend index<Name,T> to get []
impl<T: Eq + Hash + Clone + 'static> Interner<T> {
    pub fn new() -> Interner<T> {
        Interner {
            map: RefCell::new(HashMap::new()),
            vect: RefCell::new(Vec::new()),
        }
    }

    pub fn prefill(init: &[T]) -> Interner<T> {
        let rv = Interner::new();
        for v in init.iter() {
            rv.intern((*v).clone());
        }
        rv
    }

    pub fn intern(&self, val: T) -> Name {
        let mut map = self.map.borrow_mut();
        match (*map).find(&val) {
            Some(&idx) => return idx,
            None => (),
        }

        let mut vect = self.vect.borrow_mut();
        let new_idx = Name((*vect).len() as u32);
        (*map).insert(val.clone(), new_idx);
        (*vect).push(val);
        new_idx
    }

    pub fn gensym(&self, val: T) -> Name {
        let mut vect = self.vect.borrow_mut();
        let new_idx = Name((*vect).len() as u32);
        // leave out of .map to avoid colliding
        (*vect).push(val);
        new_idx
    }

    pub fn get(&self, idx: Name) -> T {
        let vect = self.vect.borrow();
        (*(*vect).get(idx.uint())).clone()
    }

    pub fn len(&self) -> uint {
        let vect = self.vect.borrow();
        (*vect).len()
    }

    pub fn find_equiv<Q:Hash + Equiv<T>>(&self, val: &Q) -> Option<Name> {
        let map = self.map.borrow();
        match (*map).find_equiv(val) {
            Some(v) => Some(*v),
            None => None,
        }
    }

    pub fn clear(&self) {
        *self.map.borrow_mut() = HashMap::new();
        *self.vect.borrow_mut() = Vec::new();
    }
}

#[deriving(Clone, PartialEq, Hash, PartialOrd)]
pub struct RcStr {
    string: Rc<String>,
}

impl Eq for RcStr {}

impl Ord for RcStr {
    fn cmp(&self, other: &RcStr) -> Ordering {
        self.as_slice().cmp(&other.as_slice())
    }
}

impl Str for RcStr {
    #[inline]
    fn as_slice<'a>(&'a self) -> &'a str {
        let s: &'a str = self.string.as_slice();
        s
    }
}

impl fmt::Show for RcStr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use std::fmt::Show;
        self.as_slice().fmt(f)
    }
}

impl RcStr {
    pub fn new(string: &str) -> RcStr {
        RcStr {
            string: Rc::new(string.to_string()),
        }
    }
}

/// A StrInterner differs from Interner<String> in that it accepts
/// &str rather than RcStr, resulting in less allocation.
pub struct StrInterner {
    map: RefCell<HashMap<RcStr, Name>>,
    vect: RefCell<Vec<RcStr> >,
}

/// When traits can extend traits, we should extend index<Name,T> to get []
impl StrInterner {
    pub fn new() -> StrInterner {
        StrInterner {
            map: RefCell::new(HashMap::new()),
            vect: RefCell::new(Vec::new()),
        }
    }

    pub fn prefill(init: &[&str]) -> StrInterner {
        let rv = StrInterner::new();
        for &v in init.iter() { rv.intern(v); }
        rv
    }

    pub fn intern(&self, val: &str) -> Name {
        let mut map = self.map.borrow_mut();
        match map.find_equiv(&val) {
            Some(&idx) => return idx,
            None => (),
        }

        let new_idx = Name(self.len() as u32);
        let val = RcStr::new(val);
        map.insert(val.clone(), new_idx);
        self.vect.borrow_mut().push(val);
        new_idx
    }

    pub fn gensym(&self, val: &str) -> Name {
        let new_idx = Name(self.len() as u32);
        // leave out of .map to avoid colliding
        self.vect.borrow_mut().push(RcStr::new(val));
        new_idx
    }

    // I want these gensyms to share name pointers
    // with existing entries. This would be automatic,
    // except that the existing gensym creates its
    // own managed ptr using to_managed. I think that
    // adding this utility function is the most
    // lightweight way to get what I want, though not
    // necessarily the cleanest.

    /// Create a gensym with the same name as an existing
    /// entry.
    pub fn gensym_copy(&self, idx : Name) -> Name {
        let new_idx = Name(self.len() as u32);
        // leave out of map to avoid colliding
        let mut vect = self.vect.borrow_mut();
        let existing = (*vect.get(idx.uint())).clone();
        vect.push(existing);
        new_idx
    }

    pub fn get(&self, idx: Name) -> RcStr {
        (*self.vect.borrow().get(idx.uint())).clone()
    }

    pub fn len(&self) -> uint {
        self.vect.borrow().len()
    }

    pub fn find_equiv<Q:Hash + Equiv<RcStr>>(&self, val: &Q) -> Option<Name> {
        match (*self.map.borrow()).find_equiv(val) {
            Some(v) => Some(*v),
            None => None,
        }
    }

    pub fn clear(&self) {
        *self.map.borrow_mut() = HashMap::new();
        *self.vect.borrow_mut() = Vec::new();
    }
}

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

    #[test]
    #[should_fail]
    fn i1 () {
        let i : Interner<RcStr> = Interner::new();
        i.get(Name(13));
    }

    #[test]
    fn interner_tests () {
        let i : Interner<RcStr> = Interner::new();
        // first one is zero:
        assert_eq!(i.intern(RcStr::new("dog")), Name(0));
        // re-use gets the same entry:
        assert_eq!(i.intern(RcStr::new("dog")), Name(0));
        // different string gets a different #:
        assert_eq!(i.intern(RcStr::new("cat")), Name(1));
        assert_eq!(i.intern(RcStr::new("cat")), Name(1));
        // dog is still at zero
        assert_eq!(i.intern(RcStr::new("dog")), Name(0));
        // gensym gets 3
        assert_eq!(i.gensym(RcStr::new("zebra") ), Name(2));
        // gensym of same string gets new number :
        assert_eq!(i.gensym (RcStr::new("zebra") ), Name(3));
        // gensym of *existing* string gets new number:
        assert_eq!(i.gensym(RcStr::new("dog")), Name(4));
        assert_eq!(i.get(Name(0)), RcStr::new("dog"));
        assert_eq!(i.get(Name(1)), RcStr::new("cat"));
        assert_eq!(i.get(Name(2)), RcStr::new("zebra"));
        assert_eq!(i.get(Name(3)), RcStr::new("zebra"));
        assert_eq!(i.get(Name(4)), RcStr::new("dog"));
    }

    #[test]
    fn i3 () {
        let i : Interner<RcStr> = Interner::prefill([
            RcStr::new("Alan"),
            RcStr::new("Bob"),
            RcStr::new("Carol")
        ]);
        assert_eq!(i.get(Name(0)), RcStr::new("Alan"));
        assert_eq!(i.get(Name(1)), RcStr::new("Bob"));
        assert_eq!(i.get(Name(2)), RcStr::new("Carol"));
        assert_eq!(i.intern(RcStr::new("Bob")), Name(1));
    }

    #[test]
    fn string_interner_tests() {
        let i : StrInterner = StrInterner::new();
        // first one is zero:
        assert_eq!(i.intern("dog"), Name(0));
        // re-use gets the same entry:
        assert_eq!(i.intern ("dog"), Name(0));
        // different string gets a different #:
        assert_eq!(i.intern("cat"), Name(1));
        assert_eq!(i.intern("cat"), Name(1));
        // dog is still at zero
        assert_eq!(i.intern("dog"), Name(0));
        // gensym gets 3
        assert_eq!(i.gensym("zebra"), Name(2));
        // gensym of same string gets new number :
        assert_eq!(i.gensym("zebra"), Name(3));
        // gensym of *existing* string gets new number:
        assert_eq!(i.gensym("dog"), Name(4));
        // gensym tests again with gensym_copy:
        assert_eq!(i.gensym_copy(Name(2)), Name(5));
        assert_eq!(i.get(Name(5)), RcStr::new("zebra"));
        assert_eq!(i.gensym_copy(Name(2)), Name(6));
        assert_eq!(i.get(Name(6)), RcStr::new("zebra"));
        assert_eq!(i.get(Name(0)), RcStr::new("dog"));
        assert_eq!(i.get(Name(1)), RcStr::new("cat"));
        assert_eq!(i.get(Name(2)), RcStr::new("zebra"));
        assert_eq!(i.get(Name(3)), RcStr::new("zebra"));
        assert_eq!(i.get(Name(4)), RcStr::new("dog"));
    }
}
<|endoftext|>


<commit_before><commit_msg>reintroduce SegmentLocation so that certain cases which don't need the page buffer part of SegmentHeaderInfo can just clone the location parts.<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2015, Sam Payson
//
// 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 std::io;
use std::mem;

pub enum Primitive {
    UInt8(u8),
    UInt16(u16),
    UInt32(u32),
    UInt64(u64),

    Int8(i8),
    Int16(i16),
    Int32(i32),
    Int64(i64),

    Fixed32(u32),
    Fixed64(u64),

    Float32(f32),
    Float64(f64),

    Bool(bool),

    Bytes(Vec<u8>),
    String(String),

    Enum(i64),
}

pub fn write_uvarint<W>(w: &mut W, mut x: u64) -> io::Result<usize>
    where W: io::Write {

    // A 64-bit varint can be at most 10 bytes long.
    let mut buf = [0u8; 10];
    let mut idx = 0;

    while x > 0x7F {
        buf[idx] = 0x80 | (x & 0x7F) as u8;
        x = x >> 7;
        idx += 1;
    }

    buf[idx] = x as u8;

    try!(w.write_all(&buf[idx..]));

    Ok((idx + 1) as usize)
}

pub fn write_varint<W>(w: &mut W, x: i64) -> io::Result<usize>
    where W: io::Write {

    let ux = (x as u64) << 1;

    write_uvarint(w, if x < 0 { !ux } else { ux })
}

pub fn write_le_u8<W>(w: &mut W, x: u8) -> io::Result<usize>
    where W: io::Write {

    let buf = [x];
    try!(w.write_all(&buf));
    Ok(1)
}

pub fn write_le_u16<W>(w: &mut W, x: u16) -> io::Result<usize>
    where W: io::Write {

    let buf = [
        ((x >> 0) & 0xFF) as u8,
        ((x >> 8) & 0xFF) as u8,
    ];

    try!(w.write_all(&buf));
    Ok(2)
}

pub fn write_le_u32<W>(w: &mut W, x: u32) -> io::Result<usize>
    where W: io::Write {

    let buf = [
        ((x >>  0) & 0xFF) as u8,
        ((x >>  8) & 0xFF) as u8,
        ((x >> 16) & 0xFF) as u8,
        ((x >> 24) & 0xFF) as u8,
    ];

    try!(w.write_all(&buf));
    Ok(4)
}

pub fn write_le_u64<W>(w: &mut W, x: u64) -> io::Result<usize>
    where W: io::Write {

    let buf = [
        ((x >>  0) & 0xFF) as u8,
        ((x >>  8) & 0xFF) as u8,
        ((x >> 16) & 0xFF) as u8,
        ((x >> 24) & 0xFF) as u8,
        ((x >> 32) & 0xFF) as u8,
        ((x >> 40) & 0xFF) as u8,
        ((x >> 48) & 0xFF) as u8,
        ((x >> 56) & 0xFF) as u8,
    ];

    try!(w.write_all(&buf));
    Ok(8)
}

pub fn write_le_i8<W>(w: &mut W, x: i8) -> io::Result<usize>
    where W: io::Write {

    write_le_u8(w, x as u8)
}

pub fn write_le_i16<W>(w: &mut W, x: i16) -> io::Result<usize>
    where W: io::Write {

    write_le_u16(w, x as u16)
}

pub fn write_le_i32<W>(w: &mut W, x: i32) -> io::Result<usize>
    where W: io::Write {

    write_le_u32(w, x as u32)
}

pub fn write_le_i64<W>(w: &mut W, x: i64) -> io::Result<usize>
    where W: io::Write {

    write_le_u64(w, x as u64)
}

pub fn write_le_f32<W>(w: &mut W, x: f32) -> io::Result<usize>
    where W: io::Write {

    write_le_u32(w, unsafe { mem::transmute(x) })
}

pub fn write_le_f64<W>(w: &mut W, x: f64) -> io::Result<usize>
    where W: io::Write {

    write_le_u64(w, unsafe { mem::transmute(x) })
}
<commit_msg>Added functions to compute varint size.<commit_after>// Copyright (c) 2015, Sam Payson
//
// 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 std::io;
use std::mem;

pub enum Primitive {
    UInt8(u8),
    UInt16(u16),
    UInt32(u32),
    UInt64(u64),

    Int8(i8),
    Int16(i16),
    Int32(i32),
    Int64(i64),

    Fixed32(u32),
    Fixed64(u64),

    Float32(f32),
    Float64(f64),

    Bool(bool),

    Bytes(Vec<u8>),
    String(String),

    Enum(i64),
}

pub fn uvarint_size(x: u64) -> usize {
    if x < 0x80 {
        1
    } else if x < 0x80 << 7 {
        2
    } else if x < 0x80 << 14 {
        3
    } else if x < 0x80 << 21 {
        4
    } else if x < 0x80 << 28 {
        5
    } else if x < 0x80 << 35 {
        6
    } else if x < 0x80 << 42 {
        7
    } else if x < 0x80 << 49 {
        8
    } else if x < 0x80 << 56 {
        9
    } else {
        10
    }
}

pub fn varint_size(x: i64) -> usize {
    let ux = (x as u64) << 1;

    uvarint_size(if x < 0 { !ux } else { ux })
}

pub fn write_uvarint<W>(w: &mut W, mut x: u64) -> io::Result<usize>
    where W: io::Write {

    // A 64-bit varint can be at most 10 bytes long.
    let mut buf = [0u8; 10];
    let mut idx = 0;

    while x > 0x7F {
        buf[idx] = 0x80 | (x & 0x7F) as u8;
        x = x >> 7;
        idx += 1;
    }

    buf[idx] = x as u8;

    try!(w.write_all(&buf[idx..]));

    Ok((idx + 1) as usize)
}

pub fn write_varint<W>(w: &mut W, x: i64) -> io::Result<usize>
    where W: io::Write {

    let ux = (x as u64) << 1;

    write_uvarint(w, if x < 0 { !ux } else { ux })
}

pub fn write_le_u8<W>(w: &mut W, x: u8) -> io::Result<usize>
    where W: io::Write {

    let buf = [x];
    try!(w.write_all(&buf));
    Ok(1)
}

pub fn write_le_u16<W>(w: &mut W, x: u16) -> io::Result<usize>
    where W: io::Write {

    let buf = [
        ((x >> 0) & 0xFF) as u8,
        ((x >> 8) & 0xFF) as u8,
    ];

    try!(w.write_all(&buf));
    Ok(2)
}

pub fn write_le_u32<W>(w: &mut W, x: u32) -> io::Result<usize>
    where W: io::Write {

    let buf = [
        ((x >>  0) & 0xFF) as u8,
        ((x >>  8) & 0xFF) as u8,
        ((x >> 16) & 0xFF) as u8,
        ((x >> 24) & 0xFF) as u8,
    ];

    try!(w.write_all(&buf));
    Ok(4)
}

pub fn write_le_u64<W>(w: &mut W, x: u64) -> io::Result<usize>
    where W: io::Write {

    let buf = [
        ((x >>  0) & 0xFF) as u8,
        ((x >>  8) & 0xFF) as u8,
        ((x >> 16) & 0xFF) as u8,
        ((x >> 24) & 0xFF) as u8,
        ((x >> 32) & 0xFF) as u8,
        ((x >> 40) & 0xFF) as u8,
        ((x >> 48) & 0xFF) as u8,
        ((x >> 56) & 0xFF) as u8,
    ];

    try!(w.write_all(&buf));
    Ok(8)
}

pub fn write_le_i8<W>(w: &mut W, x: i8) -> io::Result<usize>
    where W: io::Write {

    write_le_u8(w, x as u8)
}

pub fn write_le_i16<W>(w: &mut W, x: i16) -> io::Result<usize>
    where W: io::Write {

    write_le_u16(w, x as u16)
}

pub fn write_le_i32<W>(w: &mut W, x: i32) -> io::Result<usize>
    where W: io::Write {

    write_le_u32(w, x as u32)
}

pub fn write_le_i64<W>(w: &mut W, x: i64) -> io::Result<usize>
    where W: io::Write {

    write_le_u64(w, x as u64)
}

pub fn write_le_f32<W>(w: &mut W, x: f32) -> io::Result<usize>
    where W: io::Write {

    write_le_u32(w, unsafe { mem::transmute(x) })
}

pub fn write_le_f64<W>(w: &mut W, x: f64) -> io::Result<usize>
    where W: io::Write {

    write_le_u64(w, unsafe { mem::transmute(x) })
}
<|endoftext|>


<commit_before>use std::io::Read;
use std::iter::repeat;

use nom::bytes::complete::tag;
use nom::character::complete::newline;
use nom::combinator::map;
use nom::multi::separated_list1;
use nom::sequence::separated_pair;
use nom::IResult;

use crate::common::ordered;
use crate::common::read_input;
use crate::common::BitSet;

type Coord = (u16, u16);

fn coordinates(input: &[u8]) -> IResult<&[u8], Coord> {
    use nom::character::complete::char;
    use nom::character::complete::u16;

    separated_pair(u16, char(','), u16)(input)
}

fn parse_input(input: &[u8]) -> IResult<&[u8], Vec<(Coord, Coord)>> {
    let read_line = map(
        separated_pair(coordinates, tag(" -> "), coordinates),
        |(begin, end)| ordered(begin, end),
    );

    separated_list1(newline, read_line)(input)
}

fn stripe(
    once: &mut BitSet,
    twice: &mut BitSet,
    width: usize,
    xs: impl Iterator<Item = u16>,
    ys: impl Iterator<Item = u16>,
) {
    for (x, y) in xs.zip(ys) {
        let index = x as usize + y as usize * width;
        if !once.insert(index) {
            twice.insert(index);
        }
    }
}

fn part_common(input: &mut dyn Read, diagonals: bool) -> String {
    let lines = read_input(input, parse_input);

    let width = lines.iter().map(|&((_, x_max), _)| x_max).max().unwrap() as usize + 1;

    let mut once_map = BitSet::new();
    let mut twice_map = BitSet::new();

    for (begin, end) in lines {
        if begin.0 == end.0 {
            let y_range = begin.1..=end.1;
            stripe(
                &mut once_map,
                &mut twice_map,
                width,
                repeat(begin.0),
                y_range,
            );
        } else if begin.1 == end.1 {
            let x_range = begin.0..=end.0;
            stripe(
                &mut once_map,
                &mut twice_map,
                width,
                x_range,
                repeat(begin.1),
            );
        } else if diagonals {
            let x_range = begin.0..=end.0;
            let y_range = (begin.1.min(end.1))..=(begin.1.max(end.1));

            if begin.1 > end.1 {
                // For a downward slope we need to reverse Y
                stripe(&mut once_map, &mut twice_map, width, x_range, y_range.rev());
            } else {
                stripe(&mut once_map, &mut twice_map, width, x_range, y_range);
            }
        }
    }

    twice_map.len().to_string()
}

pub fn part1(input: &mut dyn Read) -> String {
    part_common(input, false)
}

pub fn part2(input: &mut dyn Read) -> String {
    part_common(input, true)
}

#[cfg(test)]
mod tests {
    use crate::test_implementation;

    use super::*;

    const SAMPLE: &[u8] = include_bytes!("samples/05.txt");

    #[test]
    fn sample_part1() {
        test_implementation(part1, SAMPLE, 5)
    }

    #[test]
    fn sample_part2() {
        test_implementation(part2, SAMPLE, 12)
    }
}
<commit_msg>Correct width calculation<commit_after>use std::io::Read;
use std::iter::repeat;

use nom::bytes::complete::tag;
use nom::character::complete::newline;
use nom::combinator::map;
use nom::multi::separated_list1;
use nom::sequence::separated_pair;
use nom::IResult;

use crate::common::ordered;
use crate::common::read_input;
use crate::common::BitSet;

type Coord = (u16, u16);

fn coordinates(input: &[u8]) -> IResult<&[u8], Coord> {
    use nom::character::complete::char;
    use nom::character::complete::u16;

    separated_pair(u16, char(','), u16)(input)
}

fn parse_input(input: &[u8]) -> IResult<&[u8], Vec<(Coord, Coord)>> {
    let read_line = map(
        separated_pair(coordinates, tag(" -> "), coordinates),
        |(begin, end)| ordered(begin, end),
    );

    separated_list1(newline, read_line)(input)
}

fn stripe(
    once: &mut BitSet,
    twice: &mut BitSet,
    width: usize,
    xs: impl Iterator<Item = u16>,
    ys: impl Iterator<Item = u16>,
) {
    for (x, y) in xs.zip(ys) {
        let index = x as usize + y as usize * width;
        if !once.insert(index) {
            twice.insert(index);
        }
    }
}

fn part_common(input: &mut dyn Read, diagonals: bool) -> String {
    let lines = read_input(input, parse_input);

    let width = lines
        .iter()
        .map(|&(_, (x, _))| x as usize + 1)
        .max()
        .unwrap();

    let mut once_map = BitSet::new();
    let mut twice_map = BitSet::new();

    for (begin, end) in lines {
        if begin.0 == end.0 {
            let y_range = begin.1..=end.1;
            stripe(
                &mut once_map,
                &mut twice_map,
                width,
                repeat(begin.0),
                y_range,
            );
        } else if begin.1 == end.1 {
            let x_range = begin.0..=end.0;
            stripe(
                &mut once_map,
                &mut twice_map,
                width,
                x_range,
                repeat(begin.1),
            );
        } else if diagonals {
            let x_range = begin.0..=end.0;
            let y_range = (begin.1.min(end.1))..=(begin.1.max(end.1));

            if begin.1 > end.1 {
                // For a downward slope we need to reverse Y
                stripe(&mut once_map, &mut twice_map, width, x_range, y_range.rev());
            } else {
                stripe(&mut once_map, &mut twice_map, width, x_range, y_range);
            }
        }
    }

    twice_map.len().to_string()
}

pub fn part1(input: &mut dyn Read) -> String {
    part_common(input, false)
}

pub fn part2(input: &mut dyn Read) -> String {
    part_common(input, true)
}

#[cfg(test)]
mod tests {
    use crate::test_implementation;

    use super::*;

    const SAMPLE: &[u8] = include_bytes!("samples/05.txt");

    #[test]
    fn sample_part1() {
        test_implementation(part1, SAMPLE, 5)
    }

    #[test]
    fn sample_part2() {
        test_implementation(part2, SAMPLE, 12)
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
// Andrew Hobden (@hoverbear) <andrew@hoverbear.org>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
// This work was derived from Structopt (https://github.com/TeXitoi/structopt)
// commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the
// MIT/Apache 2.0 license.

mod utils;

use clap::Clap;
use utils::*;

#[test]
fn doc_comments() {
    /// Lorem ipsum
    #[derive(Clap, PartialEq, Debug)]
    struct LoremIpsum {
        /// Fooify a bar
        /// and a baz
        #[clap(short, long)]
        foo: bool,
    }

    let help = get_long_help::<LoremIpsum>();
    assert!(help.contains("Lorem ipsum"));
    assert!(help.contains("Fooify a bar and a baz"));
}

#[test]
fn help_is_better_than_comments() {
    /// Lorem ipsum
    #[derive(Clap, PartialEq, Debug)]
    #[clap(name = "lorem-ipsum", about = "Dolor sit amet")]
    struct LoremIpsum {
        /// Fooify a bar
        #[clap(short, long, help = "DO NOT PASS A BAR UNDER ANY CIRCUMSTANCES")]
        foo: bool,
    }

    let help = get_long_help::<LoremIpsum>();
    assert!(help.contains("Dolor sit amet"));
    assert!(!help.contains("Lorem ipsum"));
    assert!(help.contains("DO NOT PASS A BAR"));
}

#[test]
fn empty_line_in_doc_comment_is_double_linefeed() {
    /// Foo.
    ///
    /// Bar
    #[derive(Clap, PartialEq, Debug)]
    #[clap(name = "lorem-ipsum", no_version)]
    struct LoremIpsum {}

    let help = get_long_help::<LoremIpsum>();
    assert!(help.starts_with("lorem-ipsum \nFoo.\n\nBar\n\nUSAGE:"));
}

#[test]
fn field_long_doc_comment_both_help_long_help() {
    /// Lorem ipsumclap
    #[derive(Clap, PartialEq, Debug)]
    #[clap(name = "lorem-ipsum", about = "Dolor sit amet")]
    struct LoremIpsum {
        /// Dot is removed from multiline comments.
        ///
        /// Long help
        #[clap(long)]
        foo: bool,

        /// Dot is removed from one short comment.
        #[clap(long)]
        bar: bool,
    }

    let short_help = get_help::<LoremIpsum>();
    let long_help = get_long_help::<LoremIpsum>();

    assert!(short_help.contains("Dot is removed from one short comment"));
    assert!(!short_help.contains("Dot is removed from one short comment."));
    assert!(short_help.contains("Dot is removed from multiline comments"));
    assert!(!short_help.contains("Dot is removed from multiline comments."));
    assert!(long_help.contains("Long help"));
    assert!(!short_help.contains("Long help"));
}

#[test]
fn top_long_doc_comment_both_help_long_help() {
    /// Lorem ipsumclap
    #[derive(Clap, Debug)]
    #[clap(name = "lorem-ipsum", about = "Dolor sit amet")]
    struct LoremIpsum {
        #[clap(subcommand)]
        foo: SubCommand,
    }

    #[derive(Clap, Debug)]
    pub enum SubCommand {
        /// DO NOT PASS A BAR UNDER ANY CIRCUMSTANCES
        ///
        /// Or something else
        Foo {
            #[clap(help = "foo")]
            bars: Vec<String>,
        },
    }

    let short_help = get_help::<LoremIpsum>();
    let long_help = get_subcommand_long_help::<LoremIpsum>("foo");

    assert!(!short_help.contains("Or something else"));
    assert!(long_help.contains("DO NOT PASS A BAR UNDER ANY CIRCUMSTANCES"));
    assert!(long_help.contains("Or something else"));
}

#[test]
fn verbatim_doc_comment() {
    /// DANCE!
    ///
    ///                    ()
    ///                    |
    ///               (   ()   )
    ///     ) ________    //  )
    ///  ()  |\       \  //
    /// ( \\__ \ ______\//
    ///    \__) |       |
    ///      |  |       |
    ///       \ |       |
    ///        \|_______|
    ///        //    \\
    ///       ((     ||
    ///        \\    ||
    ///      ( ()    ||
    ///       (      () ) )
    #[derive(Clap, Debug)]
    #[clap(verbatim_doc_comment)]
    struct SeeFigure1 {
        #[clap(long)]
        foo: bool,
    }

    let help = get_long_help::<SeeFigure1>();
    let sample = r#"
                   ()
                   |
              (   ()   )
    ) ________    //  )
 ()  |\       \  //
( \\__ \ ______\//
   \__) |       |
     |  |       |
      \ |       |
       \|_______|
       //    \\
      ((     ||
       \\    ||
     ( ()    ||
      (      () ) )"#;

    assert!(help.contains(sample))
}

#[test]
fn verbatim_doc_comment_field() {
    #[derive(StructOpt, Debug)]
    struct App {
        /// This help ends in a period.
        #[structopt(long, verbatim_doc_comment)]
        foo: bool,
        /// This help does not end in a period.
        #[structopt(long)]
        bar: bool,
    }

    let help = get_long_help::<App>();
    let sample = r#"
        --bar
            This help does not end in a period

        --foo
            This help ends in a period."#;

    assert!(help.contains(sample))
}
<commit_msg>Fix tests<commit_after>// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
// Andrew Hobden (@hoverbear) <andrew@hoverbear.org>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
// This work was derived from Structopt (https://github.com/TeXitoi/structopt)
// commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the
// MIT/Apache 2.0 license.

mod utils;

use clap::Clap;
use utils::*;

#[test]
fn doc_comments() {
    /// Lorem ipsum
    #[derive(Clap, PartialEq, Debug)]
    struct LoremIpsum {
        /// Fooify a bar
        /// and a baz
        #[clap(short, long)]
        foo: bool,
    }

    let help = get_long_help::<LoremIpsum>();
    assert!(help.contains("Lorem ipsum"));
    assert!(help.contains("Fooify a bar and a baz"));
}

#[test]
fn help_is_better_than_comments() {
    /// Lorem ipsum
    #[derive(Clap, PartialEq, Debug)]
    #[clap(name = "lorem-ipsum", about = "Dolor sit amet")]
    struct LoremIpsum {
        /// Fooify a bar
        #[clap(short, long, help = "DO NOT PASS A BAR UNDER ANY CIRCUMSTANCES")]
        foo: bool,
    }

    let help = get_long_help::<LoremIpsum>();
    assert!(help.contains("Dolor sit amet"));
    assert!(!help.contains("Lorem ipsum"));
    assert!(help.contains("DO NOT PASS A BAR"));
}

#[test]
fn empty_line_in_doc_comment_is_double_linefeed() {
    /// Foo.
    ///
    /// Bar
    #[derive(Clap, PartialEq, Debug)]
    #[clap(name = "lorem-ipsum", no_version)]
    struct LoremIpsum {}

    let help = get_long_help::<LoremIpsum>();
    assert!(help.starts_with("lorem-ipsum \nFoo.\n\nBar\n\nUSAGE:"));
}

#[test]
fn field_long_doc_comment_both_help_long_help() {
    /// Lorem ipsumclap
    #[derive(Clap, PartialEq, Debug)]
    #[clap(name = "lorem-ipsum", about = "Dolor sit amet")]
    struct LoremIpsum {
        /// Dot is removed from multiline comments.
        ///
        /// Long help
        #[clap(long)]
        foo: bool,

        /// Dot is removed from one short comment.
        #[clap(long)]
        bar: bool,
    }

    let short_help = get_help::<LoremIpsum>();
    let long_help = get_long_help::<LoremIpsum>();

    assert!(short_help.contains("Dot is removed from one short comment"));
    assert!(!short_help.contains("Dot is removed from one short comment."));
    assert!(short_help.contains("Dot is removed from multiline comments"));
    assert!(!short_help.contains("Dot is removed from multiline comments."));
    assert!(long_help.contains("Long help"));
    assert!(!short_help.contains("Long help"));
}

#[test]
fn top_long_doc_comment_both_help_long_help() {
    /// Lorem ipsumclap
    #[derive(Clap, Debug)]
    #[clap(name = "lorem-ipsum", about = "Dolor sit amet")]
    struct LoremIpsum {
        #[clap(subcommand)]
        foo: SubCommand,
    }

    #[derive(Clap, Debug)]
    pub enum SubCommand {
        /// DO NOT PASS A BAR UNDER ANY CIRCUMSTANCES
        ///
        /// Or something else
        Foo {
            #[clap(help = "foo")]
            bars: Vec<String>,
        },
    }

    let short_help = get_help::<LoremIpsum>();
    let long_help = get_subcommand_long_help::<LoremIpsum>("foo");

    assert!(!short_help.contains("Or something else"));
    assert!(long_help.contains("DO NOT PASS A BAR UNDER ANY CIRCUMSTANCES"));
    assert!(long_help.contains("Or something else"));
}

#[test]
fn verbatim_doc_comment() {
    /// DANCE!
    ///
    ///                    ()
    ///                    |
    ///               (   ()   )
    ///     ) ________    //  )
    ///  ()  |\       \  //
    /// ( \\__ \ ______\//
    ///    \__) |       |
    ///      |  |       |
    ///       \ |       |
    ///        \|_______|
    ///        //    \\
    ///       ((     ||
    ///        \\    ||
    ///      ( ()    ||
    ///       (      () ) )
    #[derive(Clap, Debug)]
    #[clap(verbatim_doc_comment)]
    struct SeeFigure1 {
        #[clap(long)]
        foo: bool,
    }

    let help = get_long_help::<SeeFigure1>();
    let sample = r#"
                   ()
                   |
              (   ()   )
    ) ________    //  )
 ()  |\       \  //
( \\__ \ ______\//
   \__) |       |
     |  |       |
      \ |       |
       \|_______|
       //    \\
      ((     ||
       \\    ||
     ( ()    ||
      (      () ) )"#;

    assert!(help.contains(sample))
}

#[test]
fn verbatim_doc_comment_field() {
    #[derive(Clap, Debug)]
    struct App {
        /// This help ends in a period.
        #[clap(long, verbatim_doc_comment)]
        foo: bool,
        /// This help does not end in a period.
        #[clap(long)]
        bar: bool,
    }

    let help = get_long_help::<App>();

    assert!(help.contains("This help ends in a period."));
    assert!(help.contains("This help does not end in a period"));
}
<|endoftext|>


<commit_before>//! Draw rectangle
//!
//! This module contains the definintion of a rectangle with possibly rounded
//! corners. It contains the code to draw the rectangle and defines properties
//! like color and shape. The rectangle dimensions and location are specified by
//! `types::Rectangle`.
//!
//! To draw a square with side 10 and top left corner in (0, 0), do the
//! following:
//! ```
//! let rectangle = Rectangle::new(color::BLACK);
//! let dims = square(0.0, 0.0, 10.0);
//! rectangle.draw(dims, &draw_state::Default::default(), transform, g);
//! ```

use types::{Color, Radius, Resolution};
use {types, triangulation, Graphics, DrawState};
use math::{Matrix2d, Scalar};

pub use math::margin_rectangle as margin;

/// Create `types::Rectangle` by the two opposit corners.
///
/// The corners are in (x0, y0) and (x1, y1).
pub fn rectangle_by_corners(x0: Scalar, y0: Scalar, x1: Scalar, y1: Scalar) -> types::Rectangle {
    let (xmin, w) = if x0 <= x1 {
        (x0, x1 - x0)
    } else {
        (x1, x0 - x1)
    };

    let (ymin, h) = if y0 <= y1 {
        (y0, y1 - y0)
    } else {
        (y1, y0 - y1)
    };

    [xmin, ymin, w, h]
}

/// Use x, y, half-width, half-height
pub fn centered(rect: types::Rectangle) -> types::Rectangle {
    [rect[0] - rect[2], rect[1] - rect[3], 2.0 * rect[2], 2.0 * rect[3]]
}

/// Create `types::Rectangle` for a square with a center in (`x`, `y`) and side
/// `2 * radius`.
pub fn centered_square(x: Scalar, y: Scalar, radius: Scalar) -> types::Rectangle {
    [x - radius, y - radius, 2.0 * radius, 2.0 * radius]
}

/// Create `types::Rectangle` for a square with a top-left corner in (`x`, `y`)
/// and side `size`.
pub fn square(x: Scalar, y: Scalar, size: Scalar) -> types::Rectangle {
    [x, y, size, size]
}

/// The shape of the rectangle corners
#[derive(Copy, Clone)]
pub enum Shape {
    /// Square corners
    Square,
    /// Round corners, with resolution per corner.
    Round(Radius, Resolution),
    /// Bevel corners
    Bevel(Radius),
}

/// The border of the rectangle
#[derive(Copy, Clone)]
pub struct Border {
    /// The color of the border
    pub color: Color,
    /// The radius of the border. The half-width of the line by which border is
    /// drawn.
    pub radius: Radius,
}

/// A filled rectangle
#[derive(Copy, Clone)]
pub struct Rectangle {
    /// The rectangle color
    pub color: Color,
    /// The roundness of the rectangle
    pub shape: Shape,
    /// The border
    pub border: Option<Border>,
}

impl Rectangle {
    /// Creates a new rectangle.
    pub fn new(color: Color) -> Rectangle {
        Rectangle {
            color: color,
            shape: Shape::Square,
            border: None,
        }
    }

    /// Creates a new rectangle with rounded corners.
    pub fn new_round(color: Color, round_radius: Radius) -> Rectangle {
        Rectangle {
            color: color,
            shape: Shape::Round(round_radius, 32),
            border: None,
        }
    }

    /// Creates a new rectangle border.
    pub fn new_border(color: Color, radius: Radius) -> Rectangle {
        Rectangle {
            color: [0.0; 4],
            shape: Shape::Square,
            border: Some(Border {
                color: color,
                radius: radius,
            }),
        }
    }

    /// Creates a new rectangle border with rounded corners.
    pub fn new_round_border(color: Color,
                            round_radius: Radius,
                            border_radius: Radius)
                            -> Rectangle {
        Rectangle {
            color: [0.0; 4],
            shape: Shape::Round(round_radius, 32),
            border: Some(Border {
                color: color,
                radius: border_radius,
            }),
        }
    }

    /// Sets color.
    pub fn color(mut self, value: Color) -> Self {
        self.color = value;
        self
    }

    /// Sets shape of the corners.
    pub fn shape(mut self, value: Shape) -> Self {
        self.shape = value;
        self
    }

    /// Sets border properties.
    pub fn border(mut self, value: Border) -> Self {
        self.border = Some(value);
        self
    }

    /// Sets optional border.
    pub fn maybe_border(mut self, value: Option<Border>) -> Self {
        self.border = value;
        self
    }

    /// Draws the rectangle using the default method.
    ///
    /// `rectangle` defines the rectangle's location and dimensions,
    /// `draw_state` draw state, `draw_state::Default::default()` can be used
    /// as a default, `transform` is the transformation matrix, `g` is the
    /// `Graphics` implementation, that is used to actually draw the rectangle.s
    #[inline(always)]
    pub fn draw<R: Into<types::Rectangle>, G>(&self,
                                              rectangle: R,
                                              draw_state: &DrawState,
                                              transform: Matrix2d,
                                              g: &mut G)
        where G: Graphics
    {
        g.rectangle(self, rectangle, draw_state, transform);
    }

    /// Draws the rectangle using triangulation.
    ///
    /// This is the default implementation of draw() that will be used if `G`
    /// does not redefine `Graphics::rectangle()`.
    pub fn draw_tri<R: Into<types::Rectangle>, G>(&self,
                                                  rectangle: R,
                                                  draw_state: &DrawState,
                                                  transform: Matrix2d,
                                                  g: &mut G)
        where G: Graphics
    {
        let rectangle = rectangle.into();
        if self.color[3] != 0.0 {
            match self.shape {
                Shape::Square => {
                    g.tri_list(draw_state,
                               &self.color,
                               |f| f(&triangulation::rect_tri_list_xy(transform, rectangle)));
                }
                Shape::Round(round_radius, resolution) => {
                    g.tri_list(draw_state, &self.color, |f| {
                        triangulation::with_round_rectangle_tri_list(resolution,
                                                                     transform,
                                                                     rectangle,
                                                                     round_radius,
                                                                     |vertices| f(vertices))
                    });
                }
                Shape::Bevel(bevel_radius) => {
                    g.tri_list(draw_state, &self.color, |f| {
                        triangulation::with_round_rectangle_tri_list(2,
                                                                     transform,
                                                                     rectangle,
                                                                     bevel_radius,
                                                                     |vertices| f(vertices))
                    });
                }
            }
        }

        if let Some(Border { color, radius: border_radius }) = self.border {
            if color[3] == 0.0 {
                return;
            }
            match self.shape {
                Shape::Square => {
                    g.tri_list(draw_state, &color, |f| {
                        f(&triangulation::rect_border_tri_list_xy(transform,
                                                                  rectangle,
                                                                  border_radius))
                    });
                }
                Shape::Round(round_radius, resolution) => {
                    g.tri_list(draw_state, &color, |f| {
                        triangulation::with_round_rectangle_border_tri_list(resolution,
                                                                            transform,
                                                                            rectangle,
                                                                            round_radius,
                                                                            border_radius,
                                                                            |vertices| f(vertices))
                    });
                }
                Shape::Bevel(bevel_radius) => {
                    g.tri_list(draw_state, &color, |f| {
                        triangulation::with_round_rectangle_border_tri_list(2,
                                                                            transform,
                                                                            rectangle,
                                                                            bevel_radius,
                                                                            border_radius,
                                                                            |vertices| f(vertices))
                    });
                }
            }
        }
    }
}

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

    #[test]
    fn test_rectangle() {
        let _rectangle = Rectangle::new([1.0; 4])
            .color([0.0; 4])
            .shape(Shape::Round(10.0, 32))
            .border(Border {
                color: [0.0; 4],
                radius: 4.0,
            });
    }

    #[test]
    fn test_rectangle_by_corners() {
        assert_eq!(rectangle_by_corners(1.0, -1.0, 2.0, 3.0),
                   [1.0, -1.0, 1.0, 4.0]);
        assert_eq!(rectangle_by_corners(2.0, 3.0, 1.0, -1.0),
                   [1.0, -1.0, 1.0, 4.0]);
    }
}
<commit_msg>Fixed spelling error<commit_after>//! Draw rectangle
//!
//! This module contains the definintion of a rectangle with possibly rounded
//! corners. It contains the code to draw the rectangle and defines properties
//! like color and shape. The rectangle dimensions and location are specified by
//! `types::Rectangle`.
//!
//! To draw a square with side 10 and top left corner in (0, 0), do the
//! following:
//! ```
//! let rectangle = Rectangle::new(color::BLACK);
//! let dims = square(0.0, 0.0, 10.0);
//! rectangle.draw(dims, &draw_state::Default::default(), transform, g);
//! ```

use types::{Color, Radius, Resolution};
use {types, triangulation, Graphics, DrawState};
use math::{Matrix2d, Scalar};

pub use math::margin_rectangle as margin;

/// Create `types::Rectangle` by the two opposite corners.
///
/// The corners are in (x0, y0) and (x1, y1).
pub fn rectangle_by_corners(x0: Scalar, y0: Scalar, x1: Scalar, y1: Scalar) -> types::Rectangle {
    let (xmin, w) = if x0 <= x1 {
        (x0, x1 - x0)
    } else {
        (x1, x0 - x1)
    };

    let (ymin, h) = if y0 <= y1 {
        (y0, y1 - y0)
    } else {
        (y1, y0 - y1)
    };

    [xmin, ymin, w, h]
}

/// Use x, y, half-width, half-height
pub fn centered(rect: types::Rectangle) -> types::Rectangle {
    [rect[0] - rect[2], rect[1] - rect[3], 2.0 * rect[2], 2.0 * rect[3]]
}

/// Create `types::Rectangle` for a square with a center in (`x`, `y`) and side
/// `2 * radius`.
pub fn centered_square(x: Scalar, y: Scalar, radius: Scalar) -> types::Rectangle {
    [x - radius, y - radius, 2.0 * radius, 2.0 * radius]
}

/// Create `types::Rectangle` for a square with a top-left corner in (`x`, `y`)
/// and side `size`.
pub fn square(x: Scalar, y: Scalar, size: Scalar) -> types::Rectangle {
    [x, y, size, size]
}

/// The shape of the rectangle corners
#[derive(Copy, Clone)]
pub enum Shape {
    /// Square corners
    Square,
    /// Round corners, with resolution per corner.
    Round(Radius, Resolution),
    /// Bevel corners
    Bevel(Radius),
}

/// The border of the rectangle
#[derive(Copy, Clone)]
pub struct Border {
    /// The color of the border
    pub color: Color,
    /// The radius of the border. The half-width of the line by which border is
    /// drawn.
    pub radius: Radius,
}

/// A filled rectangle
#[derive(Copy, Clone)]
pub struct Rectangle {
    /// The rectangle color
    pub color: Color,
    /// The roundness of the rectangle
    pub shape: Shape,
    /// The border
    pub border: Option<Border>,
}

impl Rectangle {
    /// Creates a new rectangle.
    pub fn new(color: Color) -> Rectangle {
        Rectangle {
            color: color,
            shape: Shape::Square,
            border: None,
        }
    }

    /// Creates a new rectangle with rounded corners.
    pub fn new_round(color: Color, round_radius: Radius) -> Rectangle {
        Rectangle {
            color: color,
            shape: Shape::Round(round_radius, 32),
            border: None,
        }
    }

    /// Creates a new rectangle border.
    pub fn new_border(color: Color, radius: Radius) -> Rectangle {
        Rectangle {
            color: [0.0; 4],
            shape: Shape::Square,
            border: Some(Border {
                color: color,
                radius: radius,
            }),
        }
    }

    /// Creates a new rectangle border with rounded corners.
    pub fn new_round_border(color: Color,
                            round_radius: Radius,
                            border_radius: Radius)
                            -> Rectangle {
        Rectangle {
            color: [0.0; 4],
            shape: Shape::Round(round_radius, 32),
            border: Some(Border {
                color: color,
                radius: border_radius,
            }),
        }
    }

    /// Sets color.
    pub fn color(mut self, value: Color) -> Self {
        self.color = value;
        self
    }

    /// Sets shape of the corners.
    pub fn shape(mut self, value: Shape) -> Self {
        self.shape = value;
        self
    }

    /// Sets border properties.
    pub fn border(mut self, value: Border) -> Self {
        self.border = Some(value);
        self
    }

    /// Sets optional border.
    pub fn maybe_border(mut self, value: Option<Border>) -> Self {
        self.border = value;
        self
    }

    /// Draws the rectangle using the default method.
    ///
    /// `rectangle` defines the rectangle's location and dimensions,
    /// `draw_state` draw state, `draw_state::Default::default()` can be used
    /// as a default, `transform` is the transformation matrix, `g` is the
    /// `Graphics` implementation, that is used to actually draw the rectangle.s
    #[inline(always)]
    pub fn draw<R: Into<types::Rectangle>, G>(&self,
                                              rectangle: R,
                                              draw_state: &DrawState,
                                              transform: Matrix2d,
                                              g: &mut G)
        where G: Graphics
    {
        g.rectangle(self, rectangle, draw_state, transform);
    }

    /// Draws the rectangle using triangulation.
    ///
    /// This is the default implementation of draw() that will be used if `G`
    /// does not redefine `Graphics::rectangle()`.
    pub fn draw_tri<R: Into<types::Rectangle>, G>(&self,
                                                  rectangle: R,
                                                  draw_state: &DrawState,
                                                  transform: Matrix2d,
                                                  g: &mut G)
        where G: Graphics
    {
        let rectangle = rectangle.into();
        if self.color[3] != 0.0 {
            match self.shape {
                Shape::Square => {
                    g.tri_list(draw_state,
                               &self.color,
                               |f| f(&triangulation::rect_tri_list_xy(transform, rectangle)));
                }
                Shape::Round(round_radius, resolution) => {
                    g.tri_list(draw_state, &self.color, |f| {
                        triangulation::with_round_rectangle_tri_list(resolution,
                                                                     transform,
                                                                     rectangle,
                                                                     round_radius,
                                                                     |vertices| f(vertices))
                    });
                }
                Shape::Bevel(bevel_radius) => {
                    g.tri_list(draw_state, &self.color, |f| {
                        triangulation::with_round_rectangle_tri_list(2,
                                                                     transform,
                                                                     rectangle,
                                                                     bevel_radius,
                                                                     |vertices| f(vertices))
                    });
                }
            }
        }

        if let Some(Border { color, radius: border_radius }) = self.border {
            if color[3] == 0.0 {
                return;
            }
            match self.shape {
                Shape::Square => {
                    g.tri_list(draw_state, &color, |f| {
                        f(&triangulation::rect_border_tri_list_xy(transform,
                                                                  rectangle,
                                                                  border_radius))
                    });
                }
                Shape::Round(round_radius, resolution) => {
                    g.tri_list(draw_state, &color, |f| {
                        triangulation::with_round_rectangle_border_tri_list(resolution,
                                                                            transform,
                                                                            rectangle,
                                                                            round_radius,
                                                                            border_radius,
                                                                            |vertices| f(vertices))
                    });
                }
                Shape::Bevel(bevel_radius) => {
                    g.tri_list(draw_state, &color, |f| {
                        triangulation::with_round_rectangle_border_tri_list(2,
                                                                            transform,
                                                                            rectangle,
                                                                            bevel_radius,
                                                                            border_radius,
                                                                            |vertices| f(vertices))
                    });
                }
            }
        }
    }
}

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

    #[test]
    fn test_rectangle() {
        let _rectangle = Rectangle::new([1.0; 4])
            .color([0.0; 4])
            .shape(Shape::Round(10.0, 32))
            .border(Border {
                color: [0.0; 4],
                radius: 4.0,
            });
    }

    #[test]
    fn test_rectangle_by_corners() {
        assert_eq!(rectangle_by_corners(1.0, -1.0, 2.0, 3.0),
                   [1.0, -1.0, 1.0, 4.0]);
        assert_eq!(rectangle_by_corners(2.0, 3.0, 1.0, -1.0),
                   [1.0, -1.0, 1.0, 4.0]);
    }
}
<|endoftext|>


<commit_before>//! [β-reduction](https://en.wikipedia.org/wiki/Beta_normal_form) for lambda `Term`s

use term::*;
use term::Term::*;
use self::Closure::*;
use self::Expression::*;
use std::collections::VecDeque;

#[derive(Debug, PartialEq, Clone)]
enum Closure {
    Depth(usize),
    TermInEnv(Term, Environment)
}

#[derive(Debug, PartialEq)]
enum Expression {
    Evaluation(Closure),
    Application(Box<Expression>, Term, Environment)
}

type Environment = VecDeque<Closure>;

fn whnf(term: Term, mut env: Environment) -> Expression {
    match term {
        Var(i) => match env.remove(i - 1) {
            Some(Depth(i)) => Evaluation(Depth(i)),
            Some(TermInEnv(t, e)) => whnf(t, e),
            None => unreachable!()
        },
        Abs(t) => Evaluation(TermInEnv(Abs(t), env)),
        App(lhs, rhs) => match whnf(*lhs, env.clone()) { // TODO: try to remove this clone()
            Evaluation(TermInEnv(Abs(lhs2), mut env2)) => {
                env2.push_front(TermInEnv(*rhs, env));
                whnf(*lhs2, env2)
            },
            expr => Application(Box::new(expr), *rhs, env)
        }
    }
}

fn reduce(depth: usize, exp: Expression) -> Term {
    match exp {
        Application(lhs, rhs, env) => app(reduce(depth, *lhs), nf(depth, rhs, env)),
        Evaluation(TermInEnv(Abs(term), mut env)) => {
            env.push_front(Depth(depth));
            abs(nf(depth + 1, *term, env))
        },
        Evaluation(TermInEnv(term, _)) => term,
        Evaluation(Depth(i)) => Var(depth - i)
    }
}

fn nf(depth: usize, term: Term, env: Environment) -> Term {
    reduce(depth, whnf(term, env))
}

/// Returns a term reduced to its normal form. Consumes its argument.
///
/// # Example
///
/// ```
/// use lambda_calculus::booleans::{if_else, tru};
/// use lambda_calculus::arithmetic::{zero, one, succ};
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(succ().app(zero())), one());
/// assert_eq!(normalize(if_else().app(tru()).app(one()).app(zero())), one());
/// ```
pub fn normalize(term: Term) -> Term {
    nf(0, term, VecDeque::new())
}

// TODO: untested; check if works, add tests
pub fn beta_reduce_once(term: &mut Term) {
    let mut done = false;

    _beta_reduce_once(term, &mut done)
}

fn _beta_reduce_once(term: &mut Term, done: &mut bool) {
    if *done == true { return }

    match *term {
        Var(_) => (),
        Abs(_) => {
            beta_reduce(term.unabs_ref_mut().unwrap()) // safe
        },
        App(_, _) => {
            beta_reduce(term.lhs_ref_mut().unwrap()); // safe
            beta_reduce(term.rhs_ref_mut().unwrap()); // safe

            let copy = term.clone();
            if let Ok(result) = copy.eval() {
                *term = result;
                *done = true
            }
        }
    }
}

// TODO: sometimes needs to be applied a few times; test more
pub fn beta_reduce(term: &mut Term) {
    match *term {
        Var(_) => (),
        Abs(_) => {
            beta_reduce(term.unabs_ref_mut().unwrap()) // safe
        },
        App(_, _) => {
            beta_reduce(term.lhs_ref_mut().unwrap()); // safe
            beta_reduce(term.rhs_ref_mut().unwrap()); // safe

            let copy = term.clone();
            if let Ok(result) = copy.eval() {
                *term = result;
            }
        }
    }
}

#[cfg(test)]
mod test {
    use arithmetic::{succ, pred};
    use super::beta_reduce;

    #[test]
    fn weak_head_normal_form() {
        // TODO
    }

    #[test]
    fn beta_reduction() {
        let mut succ = succ().apply(0.into()).unwrap();
        let mut pred = pred().apply(1.into()).unwrap();
        beta_reduce(&mut succ);

        println!("{}", pred);
        beta_reduce(&mut pred);
        println!("{}", pred);
        beta_reduce(&mut pred);
        println!("{}", pred);
        beta_reduce(&mut pred);
        println!("{}", pred);

        assert_eq!(succ, 1.into());
        assert_eq!(pred, 0.into());
    }
}
<commit_msg>Further WIP on beta reduction<commit_after>//! [β-reduction](https://en.wikipedia.org/wiki/Beta_normal_form) for lambda `Term`s

use term::*;
use term::Term::*;
use self::Closure::*;
use self::Expression::*;
use std::collections::VecDeque;

#[derive(Debug, PartialEq, Clone)]
enum Closure {
    Depth(usize),
    TermInEnv(Term, Environment)
}

#[derive(Debug, PartialEq)]
enum Expression {
    Evaluation(Closure),
    Application(Box<Expression>, Term, Environment)
}

type Environment = VecDeque<Closure>;

fn whnf(term: Term, mut env: Environment) -> Expression {
    match term {
        Var(i) => match env.remove(i - 1) {
            Some(Depth(i)) => Evaluation(Depth(i)),
            Some(TermInEnv(t, e)) => whnf(t, e),
            None => unreachable!()
        },
        Abs(t) => Evaluation(TermInEnv(Abs(t), env)),
        App(lhs, rhs) => match whnf(*lhs, env.clone()) { // TODO: try to remove this clone()
            Evaluation(TermInEnv(Abs(lhs2), mut env2)) => {
                env2.push_front(TermInEnv(*rhs, env));
                whnf(*lhs2, env2)
            },
            expr => Application(Box::new(expr), *rhs, env)
        }
    }
}

fn reduce(depth: usize, exp: Expression) -> Term {
    match exp {
        Application(lhs, rhs, env) => app(reduce(depth, *lhs), nf(depth, rhs, env)),
        Evaluation(TermInEnv(Abs(term), mut env)) => {
            env.push_front(Depth(depth));
            abs(nf(depth + 1, *term, env))
        },
        Evaluation(TermInEnv(term, _)) => term,
        Evaluation(Depth(i)) => Var(depth - i)
    }
}

fn nf(depth: usize, term: Term, env: Environment) -> Term {
    reduce(depth, whnf(term, env))
}

/// Returns a term reduced to its normal form. Consumes its argument.
///
/// # Example
///
/// ```
/// use lambda_calculus::booleans::{if_else, tru};
/// use lambda_calculus::arithmetic::{zero, one, succ};
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(succ().app(zero())), one());
/// assert_eq!(normalize(if_else().app(tru()).app(one()).app(zero())), one());
/// ```
pub fn normalize(term: Term) -> Term {
    nf(0, term, VecDeque::new())
}

// WIP; doesn't fully reduce after multiple applications
/// Performs a single β-reduction on `self`
///
/// # Example
///
/// ```
/// use lambda_calculus::reduction::beta_reduce_once;
/// use lambda_calculus::arithmetic::pred;
///
/// // PRED := λλλ3(λλ1(24))(λ2)(λ1)
/// let mut pred_one = pred().apply(1.into()).unwrap();
/// beta_reduce_once(&mut pred_one);
///
/// assert_eq!(&*format!("{}", pred_one), "λλ(λ(λλ1(35))1)(λ2)(λ1)");
/// ```
pub fn beta_reduce_once(term: &mut Term) {
    _beta_reduce_once(term, false)

}

fn _beta_reduce_once(term: &mut Term, in_abs: bool) {
    println!("beta reducing {}", term);

    match *term {
        Var(_) => (),
        Abs(_) => {
            _beta_reduce_once(term.unabs_ref_mut().unwrap(), true) // safe
        },
        App(_, _) => {
            let copy = term.clone();
            if let Ok(result) = copy.eval() {
                println!("successfully reduced {} to {}", term, result);
                *term = result;
                return
            }
            if term.lhs_ref().unwrap().unvar_ref().is_err() {
                _beta_reduce_once(term.lhs_ref_mut().unwrap(), false) // safe
            } else if term.rhs_ref().unwrap().unvar_ref().is_err() {
                _beta_reduce_once(term.rhs_ref_mut().unwrap(), false) // safe
            }
        }
    }
}

// TODO: needs to be applied a few times; test more; check eval order
pub fn beta_reduce(term: &mut Term) {
    match *term {
        Var(_) => (),
        Abs(_) => {
            beta_reduce(term.unabs_ref_mut().unwrap()) // safe
        },
        App(_, _) => {
            beta_reduce(term.lhs_ref_mut().unwrap()); // safe
            beta_reduce(term.rhs_ref_mut().unwrap()); // safe

            let copy = term.clone();
            if let Ok(result) = copy.eval() {
                *term = result;
            }
        }
    }
}

#[cfg(test)]
mod test {
    use arithmetic::{succ, pred};
    use super::{beta_reduce_once};
    use term::Term;

    #[test]
    fn weak_head_normal_form() {
        // TODO
    }

    #[test]
    fn single_beta_reduction() {
        println!("({})({})", succ(), Term::from(1));
        let mut succ_one = succ().apply(1.into()).unwrap();
        println!("{}", succ_one);
        beta_reduce_once(&mut succ_one);
        println!("{}", succ_one);
        beta_reduce_once(&mut succ_one);
        println!("{}", succ_one);
        beta_reduce_once(&mut succ_one);
        println!("{}", succ_one);
        beta_reduce_once(&mut succ_one);
        println!("{}", succ_one);
    }
/*
    #[test]
    fn beta_reduction() {
        let mut succ = succ().apply(0.into()).unwrap();
        let mut pred = pred().apply(1.into()).unwrap();
        beta_reduce(&mut succ);

        println!("{}", pred);
        beta_reduce(&mut pred);
        println!("{}", pred);
        beta_reduce(&mut pred);
        println!("{}", pred);
        beta_reduce(&mut pred);
        println!("{}", pred);

        assert_eq!(succ, 1.into());
        assert_eq!(pred, 0.into());
    }
*/
}
<|endoftext|>


<commit_before>//! REPL (Read–eval–print loop) executable module provides interactive
//! execution of Tokamak language.

extern crate env_logger;
extern crate libc;
extern crate llvm;
extern crate llvm_sys;
#[macro_use]
extern crate log;
extern crate parser;
extern crate rl_sys; // libreadline

extern crate common;
extern crate exec;
extern crate plan;

mod value_print;

use std::collections::HashMap;
use std::io;
use llvm::{Builder, Function, JitCompiler, ValueRef, Verifier};
use rl_sys::readline;

use common::plugin::{FuncRegistry, PluginManager};
use common::types::{HasType, Ty};
use common::session::Session;
use exec::processor::{ExprCompiler, to_llvm_ty};
use plan::expr::Expr;
use parser::lexer;
use parser::parser as p;
use value_print::ValuePrint;

// Logical Components
// Repl - Main compoenent for REPL
// SymbolTable - HashMap, keeping functions and variables in top-level module
// IncCompiler - Imitate incremental execution with some tricky way
// ValuePrinter - Print the value contents.

pub struct Repl<'a> {
  // for system
  jit: &'a JitCompiler,
  sess: &'a Session,
  plugin_mgr: &'a PluginManager<'a>,

  // in/out descriptors
  out: &'a mut io::Write, // can be stdout or anything else,

  // for compile internal
  compiler: IncCompiler<'a>,
}

#[derive(Eq, Hash, PartialEq)]
pub enum SymbolKind {
  // Function
  Func,
  // Immutable value
  ImmVal,
  // Mutable value
  MutVal,
}

pub struct Symbol;

impl<'a> Repl<'a> {
  pub fn new(sess: &'a Session,
             plugin_mgr: &'a PluginManager<'a>,
             jit: &'a JitCompiler,
             out: &'a mut io::Write)
             -> Repl<'a> {
    Repl {
      jit: jit,
      sess: sess,
      plugin_mgr: plugin_mgr,

      out: out,

      compiler: IncCompiler {
        jit: jit,
        fn_reg: plugin_mgr.fn_registry(),
        sess: sess,
        sym_tb: HashMap::new(),
      },
    }
  }

  /// Execute a statement or expression (public for testing)
  pub fn execute(stmts: &str) -> Result<(), String> {
    Ok(())
  }

  /// Execute a meta command (public for testing)
  pub fn run_metacmd(cmd: &str) -> Result<(), String> {
    Ok(())
  }

  /// Loop for read and eval
  pub fn eval_loop(&mut self) {

    let value_print = ValuePrint::new(self.jit);
    let mut tokens = Vec::new();
    let mut ast = Vec::new();

    loop {
      match readline::readline("\x1b[33mtkm> \x1b[0m") {
        Ok(Some(line)) => {
          tokens.extend(lexer::tokenize(&line));
          let parsed = p::parse(&tokens[..], &ast[..]);

          match parsed {
            Ok(r) => {
              match r.1.len() {
                0 => {
                  match self.compiler.compile(&r.0[0]) {
                    Ok(ref f) => {

                      debug!("{:?}", r.0[0]);
                      if log_enabled!(::log::LogLevel::Debug) {
                        f.dump();
                      }
                      Verifier::verify_func(f).unwrap_or_else(|err_msg| {
                        if !log_enabled!(::log::LogLevel::Debug) {
                          f.dump();
                        }
                        panic!("{}", err_msg);
                      });

                      let mut buf = String::new();
                      value_print.print(f, r.0[0].ty(), &mut buf);

                      self.out.write(buf.as_bytes()).ok().unwrap();
                      self.out.write("\n".as_bytes()).ok().unwrap();
                      self.out.flush().ok().unwrap();

                      ast.clear();
                      tokens.clear();
                      llvm::delete_func(&f);
                    }
                    Err(msg) => {
                      println!("{}", msg);
                      ast.clear();
                      tokens.clear();
                    }
                  }
                }
                _ => {}
              }
            }
            Err(msg) => println!("{}", msg),
          }
        }
        Ok(None) => break,
        Err(e) => println!("{}", e),
      };
      // add_history(line);
    }
  }
}

pub struct IncCompiler<'a> {
  pub jit: &'a JitCompiler,
  pub sess: &'a Session,
  pub fn_reg: &'a FuncRegistry,
  pub sym_tb: HashMap<(SymbolKind, String), Symbol>,
}

impl<'a> IncCompiler<'a> {
  fn create_fn_proto(&self, bld: &Builder, ret_ty: &Ty) -> Function {
    let jit = self.jit;
    jit.create_func_prototype("processor",
                              to_llvm_ty(jit, ret_ty),
                              &[],
                              Some(bld))
  }

  fn compile(&self, expr: &Expr) -> Result<Function, String> {
    let bld = self.jit.new_builder();
    let func = self.create_fn_proto(&bld, expr.ty());
    let mut exprc = ExprCompiler::new(self.jit, self.fn_reg, self.sess, &bld);

    match exprc.compile2(&bld, expr) {
      Ok(value) => {
        bld.create_ret(&value);
        Ok(func)
      }
      Err(_) => Err("".to_string()),
    }
  }
}

// Execute the completed AST, then
// * return a value if expression
// * return an empty value if statement
// * return error if any error is included

// TODO - Error should include span and error message.

pub fn main() {
  env_logger::init().unwrap();

  // Output stream for repl
  let mut stdout = &mut io::stdout();

  // Initialize system context
  let plugin_mgr = &PluginManager::new();
  let jit = &JitCompiler::from_bc("../common/target/ir/common.bc").ok().unwrap();
  assert!(jit.get_ty("struct.Chunk").is_some());
  assert!(jit.get_ty("struct.Page").is_some());
  let sess = &Session;

  let mut repl = Repl::new(sess, plugin_mgr, jit, stdout);
  repl.eval_loop();
}
<commit_msg>Rename IncCompiler to IncrementalCompiler.<commit_after>//! REPL (Read–eval–print loop) executable module provides interactive
//! execution of Tokamak language.

extern crate env_logger;
extern crate libc;
extern crate llvm;
extern crate llvm_sys;
#[macro_use]
extern crate log;
extern crate parser;
extern crate rl_sys; // libreadline

extern crate common;
extern crate exec;
extern crate plan;

mod value_print;

use std::collections::HashMap;
use std::io;
use llvm::{Builder, Function, JitCompiler, ValueRef, Verifier};
use rl_sys::readline;

use common::plugin::{FuncRegistry, PluginManager};
use common::types::{HasType, Ty};
use common::session::Session;
use exec::processor::{ExprCompiler, to_llvm_ty};
use plan::expr::Expr;
use parser::lexer;
use parser::parser as p;
use value_print::ValuePrint;

// Logical Components
// Repl - Main compoenent for REPL
// SymbolTable - HashMap, keeping functions and variables in top-level module
// IncrementalCompiler - Imitate incremental execution with some tricky way
// ValuePrinter - Print the value contents.

pub struct Repl<'a> {
  // for system
  jit: &'a JitCompiler,
  sess: &'a Session,
  plugin_mgr: &'a PluginManager<'a>,

  // in/out descriptors
  out: &'a mut io::Write, // can be stdout or anything else,

  // for compile internal
  compiler: IncrementalCompiler<'a>,
}

#[derive(Eq, Hash, PartialEq)]
pub enum SymbolKind {
  // Function
  Func,
  // Immutable value
  ImmVal,
  // Mutable value
  MutVal,
}

pub struct Symbol;

impl<'a> Repl<'a> {
  pub fn new(sess: &'a Session,
             plugin_mgr: &'a PluginManager<'a>,
             jit: &'a JitCompiler,
             out: &'a mut io::Write)
             -> Repl<'a> {
    Repl {
      jit: jit,
      sess: sess,
      plugin_mgr: plugin_mgr,

      out: out,

      compiler: IncrementalCompiler {
        jit: jit,
        fn_reg: plugin_mgr.fn_registry(),
        sess: sess,
        sym_tb: HashMap::new(),
      },
    }
  }

  /// Execute a statement or expression (public for testing)
  pub fn execute(stmts: &str) -> Result<(), String> {
    Ok(())
  }

  /// Execute a meta command (public for testing)
  pub fn run_metacmd(cmd: &str) -> Result<(), String> {
    Ok(())
  }

  /// Loop for read and eval
  pub fn eval_loop(&mut self) {

    let value_print = ValuePrint::new(self.jit);
    let mut tokens = Vec::new();
    let mut ast = Vec::new();

    loop {
      match readline::readline("\x1b[33mtkm> \x1b[0m") {
        Ok(Some(line)) => {
          tokens.extend(lexer::tokenize(&line));
          let parsed = p::parse(&tokens[..], &ast[..]);

          match parsed {
            Ok(r) => {
              match r.1.len() {
                0 => {
                  match self.compiler.compile(&r.0[0]) {
                    Ok(ref f) => {

                      debug!("{:?}", r.0[0]);
                      if log_enabled!(::log::LogLevel::Debug) {
                        f.dump();
                      }
                      Verifier::verify_func(f).unwrap_or_else(|err_msg| {
                        if !log_enabled!(::log::LogLevel::Debug) {
                          f.dump();
                        }
                        panic!("{}", err_msg);
                      });

                      let mut buf = String::new();
                      value_print.print(f, r.0[0].ty(), &mut buf);

                      self.out.write(buf.as_bytes()).ok().unwrap();
                      self.out.write("\n".as_bytes()).ok().unwrap();
                      self.out.flush().ok().unwrap();

                      ast.clear();
                      tokens.clear();
                      llvm::delete_func(&f);
                    }
                    Err(msg) => {
                      println!("{}", msg);
                      ast.clear();
                      tokens.clear();
                    }
                  }
                }
                _ => {}
              }
            }
            Err(msg) => println!("{}", msg),
          }
        }
        Ok(None) => break,
        Err(e) => println!("{}", e),
      };
      // add_history(line);
    }
  }
}

/// Evaluator: Expr -> String

/// ValuePrint: Value -> String

/// IncCompiler: Expr -> Value
pub struct IncrementalCompiler<'a> {
  pub jit: &'a JitCompiler,
  pub sess: &'a Session,
  pub fn_reg: &'a FuncRegistry,
  pub sym_tb: HashMap<(SymbolKind, String), Symbol>,
}

impl<'a> IncrementalCompiler<'a> {
  fn create_fn_proto(&self, bld: &Builder, ret_ty: &Ty) -> Function {
    let jit = self.jit;
    jit.create_func_prototype("processor",
                              to_llvm_ty(jit, ret_ty),
                              &[],
                              Some(bld))
  }

  fn compile(&self, expr: &Expr) -> Result<Function, String> {
    let bld = self.jit.new_builder();
    let func = self.create_fn_proto(&bld, expr.ty());
    let mut exprc = ExprCompiler::new(self.jit, self.fn_reg, self.sess, &bld);

    match exprc.compile2(&bld, expr) {
      Ok(value) => {
        bld.create_ret(&value);
        Ok(func)
      }
      Err(_) => Err("".to_string()),
    }
  }
}

// Execute the completed AST, then
// * return a value if expression
// * return an empty value if statement
// * return error if any error is included

// TODO - Error should include span and error message.

pub fn main() {
  env_logger::init().unwrap();

  // Output stream for repl
  let mut stdout = &mut io::stdout();

  // Initialize system context
  let plugin_mgr = &PluginManager::new();
  let jit = &JitCompiler::from_bc("../common/target/ir/common.bc").ok().unwrap();
  assert!(jit.get_ty("struct.Chunk").is_some());
  assert!(jit.get_ty("struct.Page").is_some());
  let sess = &Session;

  let mut repl = Repl::new(sess, plugin_mgr, jit, stdout);
  repl.eval_loop();
}
<|endoftext|>