<commit_before>//! Helper methods and structures for working with cubes.
//!
//! ```ignore
//!         3  ---------  2
//!           /       / |
//!          /  up   /  |
//!      6  -------- 7  | 1
//!        |        |  /
//! west   |  south | /  east
//!        |        |/
//!      5  -------- 4
//! ```
//!
//!
//! ```ignore
//!         7  ---------  6
//!           /       / |
//!          /  up   /  |
//!      2  -------- 3  | 5
//!        |        |  /
//! east   |  north | /  west
//!        |        |/
//!      1  -------- 0
//! ```

use std::num::FromPrimitive;
use std::str::FromStr;

use vecmath::Vector3;

pub use self::Face::{
    Down,
    Up,
    North,
    South,
    West,
    East,
};

// Cube faces (clockwise).
pub const QUADS: &'static [[usize; 4]; 6] = &[
    [1, 0, 5, 4], // down
    [7, 6, 3, 2], // up
    [0, 1, 2, 3], // north
    [4, 5, 6, 7], // south
    [5, 0, 3, 6], // west
    [1, 4, 7, 2]  // east
];

// Cube vertices.
pub const VERTICES: &'static [Vector3<f32>; 8] = &[
    // This is the north surface
    [0.0, 0.0, 0.0], // 0
    [1.0, 0.0, 0.0], // 1
    [1.0, 1.0, 0.0], // 2
    [0.0, 1.0, 0.0], // 3

    // This is the south surface
    [1.0, 0.0, 1.0], // 4
    [0.0, 0.0, 1.0], // 5
    [0.0, 1.0, 1.0], // 6
    [1.0, 1.0, 1.0]  // 7
];

/// A value representing face direction.
#[repr(usize)]
#[derive(Copy, PartialEq, Eq, FromPrimitive, Show)]
pub enum Face {
    /// Facing down.
    Down = 0,
    /// Facing up.
    Up = 1,
    /// Facing north.
    North = 2,
    /// Facing south.
    South = 3,
    /// Facing west.
    West = 4,
    /// Facing east.
    East = 5
}

impl Face {
    /// Computes vertices of the face.
    pub fn vertices(self, base: Vector3<f32>, scale: Vector3<f32>) -> [Vector3<f32>; 4] {
        use array::*;

        let [x, y, z] = base;
        let [sx, sy, sz] = scale;

        QUADS[self as usize].map(|i| VERTICES[i]).map(|[vx, vy, vz]| {
            [x + sx * vx, y + sy * vy, z + sz * vz]
        })
    }

    /// Gets the direction of face.
    pub fn direction(self) -> [i32; 3] {
        match self {
            Down => [0, -1, 0],
            Up => [0, 1, 0],
            North => [0, 0, -1],
            South => [0, 0, 1],
            West => [-1, 0, 0],
            East => [1, 0, 0]
        }
    }

    /// Gets the face in a specific direction.
    pub fn from_direction(d: [i32; 3]) -> Option<Face> {
        Some(match d {
            [0, -1, 0] => Down,
            [0, 1, 0] => Up,
            [0, 0, -1] => North,
            [0, 0, 1] => South,
            [-1, 0, 0] => West,
            [1, 0, 0] => East,
            _ => return None
        })
    }
}

impl FromStr for Face {
    fn from_str(s: &str) -> Option<Face> {
        Some(match s {
            "down" => Down,
            "up" => Up,
            "north" => North,
            "south" => South,
            "west" => West,
            "east" => East,
            _ => return None
        })
    }
}

/// Iterates through each face on a cube.
#[derive(Copy)]
pub struct FaceIterator {
    face: usize,
}

impl FaceIterator {
    /// Creates a new face iterator.
    pub fn new() -> FaceIterator {
        FaceIterator {
            face: 0
        }
    }
}

impl Iterator for FaceIterator {
    type Item = Face;

    fn next(&mut self) -> Option<Face> {
        match self.face {
            x if x < 6 => {
                self.face += 1;
                FromPrimitive::from_uint(x)
            },
            _ => None
        }
    }
}
<commit_msg>Change visibility of Face::from_str (wasn't public).<commit_after>//! Helper methods and structures for working with cubes.
//!
//! ```ignore
//!         3  ---------  2
//!           /       / |
//!          /  up   /  |
//!      6  -------- 7  | 1
//!        |        |  /
//! west   |  south | /  east
//!        |        |/
//!      5  -------- 4
//! ```
//!
//!
//! ```ignore
//!         7  ---------  6
//!           /       / |
//!          /  up   /  |
//!      2  -------- 3  | 5
//!        |        |  /
//! east   |  north | /  west
//!        |        |/
//!      1  -------- 0
//! ```

use std::num::FromPrimitive;
use std::str::FromStr;

use vecmath::Vector3;

pub use self::Face::{
    Down,
    Up,
    North,
    South,
    West,
    East,
};

// Cube faces (clockwise).
pub const QUADS: &'static [[usize; 4]; 6] = &[
    [1, 0, 5, 4], // down
    [7, 6, 3, 2], // up
    [0, 1, 2, 3], // north
    [4, 5, 6, 7], // south
    [5, 0, 3, 6], // west
    [1, 4, 7, 2]  // east
];

// Cube vertices.
pub const VERTICES: &'static [Vector3<f32>; 8] = &[
    // This is the north surface
    [0.0, 0.0, 0.0], // 0
    [1.0, 0.0, 0.0], // 1
    [1.0, 1.0, 0.0], // 2
    [0.0, 1.0, 0.0], // 3

    // This is the south surface
    [1.0, 0.0, 1.0], // 4
    [0.0, 0.0, 1.0], // 5
    [0.0, 1.0, 1.0], // 6
    [1.0, 1.0, 1.0]  // 7
];

/// A value representing face direction.
#[repr(usize)]
#[derive(Copy, PartialEq, Eq, FromPrimitive, Show)]
pub enum Face {
    /// Facing down.
    Down = 0,
    /// Facing up.
    Up = 1,
    /// Facing north.
    North = 2,
    /// Facing south.
    South = 3,
    /// Facing west.
    West = 4,
    /// Facing east.
    East = 5
}

impl Face {
    /// Computes vertices of the face.
    pub fn vertices(self, base: Vector3<f32>, scale: Vector3<f32>) -> [Vector3<f32>; 4] {
        use array::*;

        let [x, y, z] = base;
        let [sx, sy, sz] = scale;

        QUADS[self as usize].map(|i| VERTICES[i]).map(|[vx, vy, vz]| {
            [x + sx * vx, y + sy * vy, z + sz * vz]
        })
    }

    /// Gets the direction of face.
    pub fn direction(self) -> [i32; 3] {
        match self {
            Down => [0, -1, 0],
            Up => [0, 1, 0],
            North => [0, 0, -1],
            South => [0, 0, 1],
            West => [-1, 0, 0],
            East => [1, 0, 0]
        }
    }

    /// Gets the face in a specific direction.
    pub fn from_direction(d: [i32; 3]) -> Option<Face> {
        Some(match d {
            [0, -1, 0] => Down,
            [0, 1, 0] => Up,
            [0, 0, -1] => North,
            [0, 0, 1] => South,
            [-1, 0, 0] => West,
            [1, 0, 0] => East,
            _ => return None
        })
    }
}

impl FromStr for Face {
    pub fn from_str(s: &str) -> Option<Face> {
        Some(match s {
            "down" => Down,
            "up" => Up,
            "north" => North,
            "south" => South,
            "west" => West,
            "east" => East,
            _ => return None
        })
    }
}

/// Iterates through each face on a cube.
#[derive(Copy)]
pub struct FaceIterator {
    face: usize,
}

impl FaceIterator {
    /// Creates a new face iterator.
    pub fn new() -> FaceIterator {
        FaceIterator {
            face: 0
        }
    }
}

impl Iterator for FaceIterator {
    type Item = Face;

    fn next(&mut self) -> Option<Face> {
        match self.face {
            x if x < 6 => {
                self.face += 1;
                FromPrimitive::from_uint(x)
            },
            _ => None
        }
    }
}
<|endoftext|>


<commit_before>use hyper::server::Request;
use std::sync::Mutex;
extern crate redis;
extern crate byteorder;

use common::*;
use self::byteorder::{BigEndian, WriteBytesExt};
use std::net::IpAddr;
use std::net::Ipv4Addr;
extern crate time;
use std::error::Error;

pub fn announce(req: &Request, redis_connection: &Mutex<redis::Connection>) -> Result<Vec<u8>, String>
{
    let query_hashmap = query_hashmap(&req.uri);

    // Check we have everything we need
    let info_hash = try!(query_hashmap.get("info_hash")
        .ok_or_else(|| "No info_hash specified".to_owned())
        .and_then(|i| parse_info_hash(i)));
    let peer_id = try!(query_hashmap.get("peer_id")
        .ok_or_else(|| "No peer_id specified".to_owned())
        .and_then(|i| parse_peer_id(i)));
    let port = try!(query_hashmap.get("port")
        .ok_or_else(|| "No port specified".to_owned())
        .and_then(|i| i.parse::<u16>().map_err(|_| "Invalid port specified".to_owned())));
    let left = try!(query_hashmap.get("left")
        .ok_or_else(|| "No left specified".to_owned())
        .and_then(|i| i.parse::<u64>().map_err(|_| "Invalid left specified".to_owned())));
    let compact = try!(query_hashmap.get("compact")
        .ok_or_else(|| "No compact specified".to_owned())
        .and_then(|i| i.parse::<u64>().map_err(|_| "Invalid left specified".to_owned())));
    let ip = req.remote_addr.ip();

    // Generate compact peer entry
    let ip_v4 = match ip {
        IpAddr::V4(i) => i,
        _ => return Err("Ipv6 not implemented yet".to_owned()),
    };
    let peer_v4 = generate_peer_ipv4(ip_v4, port);

    // Get ready for redis queries
    let key_base = format!("torrent:{}", info_hash);
    let key_seeds = format!("{}:seeds", key_base);
    let key_peers = format!("{}:peers", key_base);
    let time_now = time::get_time().sec;
    let time_drop = time_now - 60;
    let mut pipe = redis::pipe();

    // Prune out old entries
    pipe.cmd("ZREMRANGEBYSCORE").arg(&*key_seeds).arg(0).arg(time_drop).ignore();
    pipe.cmd("ZREMRANGEBYSCORE").arg(&*key_peers).arg(0).arg(time_drop).ignore();

    // Get total count of peers/seeds
    pipe.cmd("ZCARD").arg(&*key_seeds);
    pipe.cmd("ZCARD").arg(&*key_peers);

    // Get peers and seeds
    let numwant = 50;
    pipe.cmd("ZRANGE").arg(&*key_seeds).arg(0).arg(numwant);
    pipe.cmd("ZRANGE").arg(&*key_peers).arg(0).arg(numwant);

    // Add
    if left == 0 {
        pipe.cmd("ZADD").arg(&*key_seeds).arg(time_now).arg(peer_v4).ignore();
    }
    else {
        pipe.cmd("ZADD").arg(&*key_peers).arg(time_now).arg(peer_v4).ignore();
    }

    // Unlock mutex and go!
    let results: (u32, u32, Vec<Vec<u8>>, Vec<Vec<u8>>);
    {
        let r = redis_connection.lock().unwrap();
        results = try!(pipe.query(&(*r))
            .map_err(|e| format!("Redis error: {}", e.description())));
    }

    let (total_seeds, total_peers, seeds, peers) = results;

    // Begin building output
    let mut response: Vec<u8> = Vec::new();
    response.extend(format!("d8:completei{}e10:incompletei{}e8:intervali{}e5:peers",
        total_seeds, total_peers, 60).bytes());

    // dont give seeds to seeds
    if left == 0 {
        response.extend(format!("{}:", 6*peers.len()).bytes());
        for i in peers {
            response.extend(i);
        }
    }
    else {
        response.extend(format!("{}:", 6*seeds.len() + 6*peers.len()).bytes());
        for i in seeds {
            response.extend(i);
        }
        for i in peers {
            response.extend(i);
        }
    }
    response.extend(b"e");

    return Ok(response);
}

fn generate_peer_ipv4(ip: Ipv4Addr, port: u16) -> Vec<u8> {
    let mut retval = Vec::with_capacity(6);
    retval.extend(ip.octets().iter());
    retval.write_u16::<BigEndian>(port).unwrap();
    return retval;
}

#[test]
fn generate_peer_ipv4_test() {
    assert_eq!(generate_peer_ipv4(Ipv4Addr::new(127, 0, 0, 1), 0x3039), &[127, 0, 0, 1, 0x30, 0x39]);
}
<commit_msg>Say we only support compact<commit_after>use hyper::server::Request;
use std::sync::Mutex;
extern crate redis;
extern crate byteorder;

use common::*;
use self::byteorder::{BigEndian, WriteBytesExt};
use std::net::IpAddr;
use std::net::Ipv4Addr;
extern crate time;
use std::error::Error;

pub fn announce(req: &Request, redis_connection: &Mutex<redis::Connection>) -> Result<Vec<u8>, String>
{
    let query_hashmap = query_hashmap(&req.uri);

    // Check we have everything we need
    let info_hash = try!(query_hashmap.get("info_hash")
        .ok_or_else(|| "No info_hash specified".to_owned())
        .and_then(|i| parse_info_hash(i)));
    let peer_id = try!(query_hashmap.get("peer_id")
        .ok_or_else(|| "No peer_id specified".to_owned())
        .and_then(|i| parse_peer_id(i)));
    let port = try!(query_hashmap.get("port")
        .ok_or_else(|| "No port specified".to_owned())
        .and_then(|i| i.parse::<u16>().map_err(|_| "Invalid port specified".to_owned())));
    let left = try!(query_hashmap.get("left")
        .ok_or_else(|| "No left specified".to_owned())
        .and_then(|i| i.parse::<u64>().map_err(|_| "Invalid left specified".to_owned())));
    let compact = try!(query_hashmap.get("compact")
        .ok_or_else(|| "No compact specified".to_owned())
        .and_then(|i| i.parse::<u64>().map_err(|_| "Invalid compact specified".to_owned())));
    if compact != 1 {
        return Err("This tracker only supports compact responses".to_owned());
    }
    let ip = req.remote_addr.ip();

    // Generate compact peer entry
    let ip_v4 = match ip {
        IpAddr::V4(i) => i,
        _ => return Err("Ipv6 not implemented yet".to_owned()),
    };
    let peer_v4 = generate_peer_ipv4(ip_v4, port);

    // Get ready for redis queries
    let key_base = format!("torrent:{}", info_hash);
    let key_seeds = format!("{}:seeds", key_base);
    let key_peers = format!("{}:peers", key_base);
    let time_now = time::get_time().sec;
    let time_drop = time_now - 60;
    let mut pipe = redis::pipe();

    // Prune out old entries
    pipe.cmd("ZREMRANGEBYSCORE").arg(&*key_seeds).arg(0).arg(time_drop).ignore();
    pipe.cmd("ZREMRANGEBYSCORE").arg(&*key_peers).arg(0).arg(time_drop).ignore();

    // Get total count of peers/seeds
    pipe.cmd("ZCARD").arg(&*key_seeds);
    pipe.cmd("ZCARD").arg(&*key_peers);

    // Get peers and seeds
    let numwant = 50;
    pipe.cmd("ZRANGE").arg(&*key_seeds).arg(0).arg(numwant);
    pipe.cmd("ZRANGE").arg(&*key_peers).arg(0).arg(numwant);

    // Add
    if left == 0 {
        pipe.cmd("ZADD").arg(&*key_seeds).arg(time_now).arg(peer_v4).ignore();
    }
    else {
        pipe.cmd("ZADD").arg(&*key_peers).arg(time_now).arg(peer_v4).ignore();
    }

    // Unlock mutex and go!
    let results: (u32, u32, Vec<Vec<u8>>, Vec<Vec<u8>>);
    {
        let r = redis_connection.lock().unwrap();
        results = try!(pipe.query(&(*r))
            .map_err(|e| format!("Redis error: {}", e.description())));
    }

    let (total_seeds, total_peers, seeds, peers) = results;

    // Begin building output
    let mut response: Vec<u8> = Vec::new();
    response.extend(format!("d8:completei{}e10:incompletei{}e8:intervali{}e5:peers",
        total_seeds, total_peers, 60).bytes());

    // dont give seeds to seeds
    if left == 0 {
        response.extend(format!("{}:", 6*peers.len()).bytes());
        for i in peers {
            response.extend(i);
        }
    }
    else {
        response.extend(format!("{}:", 6*seeds.len() + 6*peers.len()).bytes());
        for i in seeds {
            response.extend(i);
        }
        for i in peers {
            response.extend(i);
        }
    }
    response.extend(b"e");

    return Ok(response);
}

fn generate_peer_ipv4(ip: Ipv4Addr, port: u16) -> Vec<u8> {
    let mut retval = Vec::with_capacity(6);
    retval.extend(ip.octets().iter());
    retval.write_u16::<BigEndian>(port).unwrap();
    return retval;
}

#[test]
fn generate_peer_ipv4_test() {
    assert_eq!(generate_peer_ipv4(Ipv4Addr::new(127, 0, 0, 1), 0x3039), &[127, 0, 0, 1, 0x30, 0x39]);
}
<|endoftext|>


<commit_before>fn main() {
    let x = "fn main() {\n    let x = ";
    let y = "print!(\"{}{:?};\n    let y = {:?};\n    {}\", x, x, y, y)\n}\n";
    print!(
        "{}{:?};
    let y = {:?};
    {}",
        x, x, y, y
    )
}
<commit_msg>fix quine formatting<commit_after>fn main() {
    let x = "fn main() {\n    let x = ";
    let y = "print!(\"{}{:?};\n    let y = {:?};\n    {}\", x, x, y, y)\n}\n";
    print!("{}{:?};
    let y = {:?};
    {}", x, x, y, y)
}
<|endoftext|>


<commit_before>use chrono::{DateTime, Duration, TimeZone, Utc};
use std::time::SystemTime;

use {Error, Result};

/// A UTC timestamp. Used for serialization to and from the plist date type.
#[derive(Clone, Debug, PartialEq)]
pub struct Date {
    inner: DateTime<Utc>,
}

impl Date {
    pub(crate) fn from_rfc3339(date: &str) -> Result<Self> {
        let date = DateTime::parse_from_rfc3339(date).map_err(|_| Error::InvalidData)?;
        Ok(Date {
            inner: date.with_timezone(&Utc),
        })
    }

    pub(crate) fn to_rfc3339(&self) -> String {
        format!("{:?}", self.inner)
    }

    pub(crate) fn from_seconds_since_plist_epoch(timestamp: f64) -> Result<Date> {
        // Seconds since 1/1/2001 00:00:00.

        if timestamp.is_nan() {
            return Err(Error::InvalidData);
        }

        let millis = timestamp * 1_000.0;
        // Chrono's Duration can only millisecond values between ::std::i64::MIN and
        // ::std::i64::MAX.
        if millis > ::std::i64::MAX as f64 || millis < ::std::i64::MIN as f64 {
            return Err(Error::InvalidData);
        }

        let whole_millis = millis.floor();
        let submilli_nanos = ((millis - whole_millis) * 1_000_000.0).floor();

        let dur = Duration::milliseconds(whole_millis as i64);
        let dur = dur + Duration::nanoseconds(submilli_nanos as i64);

        let plist_epoch = Utc.ymd(2001, 1, 1).and_hms(0, 0, 0);
        let date = plist_epoch
            .checked_add_signed(dur)
            .ok_or(Error::InvalidData)?;

        Ok(Date { inner: date })
    }

    #[cfg(test)]
    pub(crate) fn from_chrono(date: DateTime<Utc>) -> Date {
        Date { inner: date }
    }
}

impl From<SystemTime> for Date {
    fn from(date: SystemTime) -> Self {
        Date { inner: date.into() }
    }
}

impl Into<SystemTime> for Date {
    fn into(self) -> SystemTime {
        self.inner.into()
    }
}

#[cfg(feature = "serde")]
pub mod serde_impls {
    use serde_base::de::{Deserialize, Deserializer, Error, Unexpected, Visitor};
    use serde_base::ser::{Serialize, Serializer};
    use std::fmt;

    use Date;

    pub const DATE_NEWTYPE_STRUCT_NAME: &'static str = "PLIST-DATE";

    impl Serialize for Date {
        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where
            S: Serializer,
        {
            let date_str = self.to_rfc3339();
            serializer.serialize_newtype_struct(DATE_NEWTYPE_STRUCT_NAME, &date_str)
        }
    }

    struct DateNewtypeVisitor;

    impl<'de> Visitor<'de> for DateNewtypeVisitor {
        type Value = Date;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a plist date newtype")
        }

        fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
        where
            D: Deserializer<'de>,
        {
            deserializer.deserialize_str(DateStrVisitor)
        }
    }

    struct DateStrVisitor;

    impl<'de> Visitor<'de> for DateStrVisitor {
        type Value = Date;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a plist date string")
        }

        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
        where
            E: Error,
        {
            Date::from_rfc3339(v).map_err(|_| E::invalid_value(Unexpected::Str(v), &self))
        }
    }

    impl<'de> Deserialize<'de> for Date {
        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where
            D: Deserializer<'de>,
        {
            deserializer.deserialize_newtype_struct(DATE_NEWTYPE_STRUCT_NAME, DateNewtypeVisitor)
        }
    }
}
<commit_msg>Provide an improved debug implementation for Date.<commit_after>use chrono::{DateTime, Duration, TimeZone, Utc};
use std::fmt;
use std::result::Result as StdResult;
use std::time::SystemTime;

use {Error, Result};

/// A UTC timestamp. Used for serialization to and from the plist date type.
#[derive(Clone, PartialEq)]
pub struct Date {
    inner: DateTime<Utc>,
}

impl Date {
    pub(crate) fn from_rfc3339(date: &str) -> Result<Self> {
        let date = DateTime::parse_from_rfc3339(date).map_err(|_| Error::InvalidData)?;
        Ok(Date {
            inner: date.with_timezone(&Utc),
        })
    }

    pub(crate) fn to_rfc3339(&self) -> String {
        format!("{:?}", self.inner)
    }

    pub(crate) fn from_seconds_since_plist_epoch(timestamp: f64) -> Result<Date> {
        // Seconds since 1/1/2001 00:00:00.

        if timestamp.is_nan() {
            return Err(Error::InvalidData);
        }

        let millis = timestamp * 1_000.0;
        // Chrono's Duration can only millisecond values between ::std::i64::MIN and
        // ::std::i64::MAX.
        if millis > ::std::i64::MAX as f64 || millis < ::std::i64::MIN as f64 {
            return Err(Error::InvalidData);
        }

        let whole_millis = millis.floor();
        let submilli_nanos = ((millis - whole_millis) * 1_000_000.0).floor();

        let dur = Duration::milliseconds(whole_millis as i64);
        let dur = dur + Duration::nanoseconds(submilli_nanos as i64);

        let plist_epoch = Utc.ymd(2001, 1, 1).and_hms(0, 0, 0);
        let date = plist_epoch
            .checked_add_signed(dur)
            .ok_or(Error::InvalidData)?;

        Ok(Date { inner: date })
    }

    #[cfg(test)]
    pub(crate) fn from_chrono(date: DateTime<Utc>) -> Date {
        Date { inner: date }
    }
}

impl fmt::Debug for Date {
    fn fmt(&self, f: &mut fmt::Formatter) -> StdResult<(), fmt::Error> {
        self.inner.fmt(f)
    }
}

impl From<SystemTime> for Date {
    fn from(date: SystemTime) -> Self {
        Date { inner: date.into() }
    }
}

impl Into<SystemTime> for Date {
    fn into(self) -> SystemTime {
        self.inner.into()
    }
}

#[cfg(feature = "serde")]
pub mod serde_impls {
    use serde_base::de::{Deserialize, Deserializer, Error, Unexpected, Visitor};
    use serde_base::ser::{Serialize, Serializer};
    use std::fmt;

    use Date;

    pub const DATE_NEWTYPE_STRUCT_NAME: &'static str = "PLIST-DATE";

    impl Serialize for Date {
        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where
            S: Serializer,
        {
            let date_str = self.to_rfc3339();
            serializer.serialize_newtype_struct(DATE_NEWTYPE_STRUCT_NAME, &date_str)
        }
    }

    struct DateNewtypeVisitor;

    impl<'de> Visitor<'de> for DateNewtypeVisitor {
        type Value = Date;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a plist date newtype")
        }

        fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
        where
            D: Deserializer<'de>,
        {
            deserializer.deserialize_str(DateStrVisitor)
        }
    }

    struct DateStrVisitor;

    impl<'de> Visitor<'de> for DateStrVisitor {
        type Value = Date;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a plist date string")
        }

        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
        where
            E: Error,
        {
            Date::from_rfc3339(v).map_err(|_| E::invalid_value(Unexpected::Str(v), &self))
        }
    }

    impl<'de> Deserialize<'de> for Date {
        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where
            D: Deserializer<'de>,
        {
            deserializer.deserialize_newtype_struct(DATE_NEWTYPE_STRUCT_NAME, DateNewtypeVisitor)
        }
    }
}
<|endoftext|>


<commit_before>use std::iter;

extern crate itertools;
use self::itertools::Itertools;

pub fn main(input: &str) -> Vec<String> {
    let s1 = house_count(&input);
    let s2 = robo_santa(&input);
    vec![s1.to_string(), s2.to_string()]
}

fn directions(c: char) -> (i32, i32) {
    match c {
        '>' => (1, 0),
        '<' => (-1, 0),
        '^' => (0, 1),
        'v' => (0, -1),
        _ => panic!("invalid input"),
    }
}

fn house_count(input: &str) -> usize {
    input.chars()
         .map(directions)
         .scan((0, 0), |&mut (ref mut x, ref mut y), (dx, dy)| {
             *x += dx;
             *y += dy;
             Some((*x, *y))
         })
         .chain(iter::once((0, 0)))
         .unique()
         .count()
}

#[test]
fn test_house_count() {
    assert_eq!(house_count(">"), 2);
    assert_eq!(house_count("^>v<"), 4);
    assert_eq!(house_count("^v^v^v^v^v"), 2);
}

fn robo_santa(input: &str) -> usize {
    let odd = input.chars().step(2);
    let even = input.chars().skip(1).step(2);

    odd.map(directions)
       .scan((0, 0), |&mut (ref mut x, ref mut y), (dx, dy)| {
           *x += dx;
           *y += dy;
           Some((*x, *y))
       })
       .chain(even.map(directions)
                  .scan((0, 0), |&mut (ref mut x, ref mut y), (dx, dy)| {
                      *x += dx;
                      *y += dy;
                      Some((*x, *y))
                  }))
       .chain(iter::once((0, 0)))
       .unique()
       .count()
}

#[test]
fn test_robo_santa() {
    assert_eq!(robo_santa("^v"), 3);
    assert_eq!(robo_santa("^>v<"), 3);
    assert_eq!(robo_santa("^v^v^v^v^v"), 11);
}
<commit_msg>better code sharing<commit_after>use std::iter;

extern crate itertools;
use self::itertools::Itertools;

pub fn main(input: &str) -> Vec<String> {
    let s1 = house_count(&input);
    let s2 = robo_santa(&input);
    vec![s1.to_string(), s2.to_string()]
}

fn directions(c: char) -> (i32, i32) {
    match c {
        '>' => (1, 0),
        '<' => (-1, 0),
        '^' => (0, 1),
        'v' => (0, -1),
        _ => panic!("invalid input"),
    }
}

fn visit_houses<'a>(input: &'a str) -> Box<Iterator<Item = (i32, i32)> + 'a> {
    Box::new(input.chars()
                  .map(directions)
                  .scan((0, 0), |&mut (ref mut x, ref mut y), (dx, dy)| {
                      *x += dx;
                      *y += dy;
                      Some((*x, *y))
                  })
                  .chain(iter::once((0, 0))))
}

fn house_count(input: &str) -> usize {
    visit_houses(input)
        .unique()
        .count()
}

#[test]
fn test_house_count() {
    assert_eq!(house_count(">"), 2);
    assert_eq!(house_count("^>v<"), 4);
    assert_eq!(house_count("^v^v^v^v^v"), 2);
}

fn robo_santa(input: &str) -> usize {
    let odd: String = input.chars().step(2).collect();
    let even: String = input.chars().skip(1).step(2).collect();

    return visit_houses(&odd)
               .chain(visit_houses(&even))
               .unique()
               .count();
}

#[test]
fn test_robo_santa() {
    assert_eq!(robo_santa("^v"), 3);
    assert_eq!(robo_santa("^>v<"), 3);
    assert_eq!(robo_santa("^v^v^v^v^v"), 11);
}
<|endoftext|>


<commit_before>//
// MSX CAS Packager
// Copyright (c) 2015 Alvaro Polo
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::io::Read;
use std::io::Error as IoError;
use std::str::from_utf8;

/// A block of data contained in a tape.
///
/// A tape file is comprised by a sequence of blocks. Each block starts with the prefix bytes
/// `1fa6debacc137d74` followed by the block data. The `Block` type stores the block data
/// without the prefix bytes.
///
#[derive(Debug)]
pub struct Block {
    data: Vec<u8>,
}

impl Block {

    /// Generates a new block from the data bytes (without the prefix bytes).
    pub fn from_data(bytes: &[u8]) -> Block {
        Block { data: Vec::from(bytes) }
    }

    /// Returns the block data (without the prefix bytes).
    pub fn data(&self) -> &[u8] { &self.data[..] }

    /// Returns `true` if the block is detected as a binary header.
    ///
    /// A bin header is comprised by `0xd0d0d0d0d0d0d0d0d0d0` followed by six bytes for
    /// the name of the binary file. This function returns `true` if the block data match
    /// this pattern, `false` otherwise.
    pub fn is_bin_header(&self) -> bool {
        self.data.len() == 16 &&
            self.data[..10] == [0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0]
    }

    /// Returns `true` if the block is detected as a Basic header.
    ///
    /// A Basic header is comprised by `0xd3d3d3d3d3d3d3d3d3d3` followed by six bytes for
    /// the name of the Basic file. This function returns `true` if the block data match
    /// this pattern, `false` otherwise.
    pub fn is_basic_header(&self) -> bool {
        self.data.len() == 16 &&
            self.data[..10] == [0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3]
    }

    /// Returns `true` if the block is detected as an ASCII header.
    ///
    /// An ASCII header is comprised by `0xeaeaeaeaeaeaeaeaeaea` followed by six bytes for
    /// the name of the ASCII file. This function returns `true` if the block data match
    /// this pattern, `false` otherwise.
    pub fn is_ascii_header(&self) -> bool {
        self.data.len() == 16 &&
            self.data[..10] == [0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea]
    }

    /// Returns the file name in case of a binary, ascii or basic header, `None` otherwise.
    pub fn file_name(&self) -> Option<&str> {
        if self.is_bin_header() || self.is_basic_header() || self.is_ascii_header() {
            let name = &self.data[10..16];
            let mut last = 6;
            for i in (0..6).rev() {
                if name[i] == 0 { last = i }
            }
            from_utf8(&name[..last]).ok()
        }
        else { None }
    }
}

/// A file contained in a tape
///
/// Files stored in a tape can be one of:
/// * Binary files. They contain binary code and/or data. They are loaded using `BLOAD`
///   instruction from Basic.
/// * ASCII files. They contain text, typically corresponding to Basic source code. They are
///   loaded using `LOAD` instruction from Basic.
/// * Basic files. They contain tokenized Basic, a compact form of Basic source code. They are
///   loaded using `CLOAD` instruction from Basic.
/// * Custom files. They contain arbitrary data generated by a program using direct calls to
///   casette IO addresses. Its contents cannot be processed from Basic but loaded from the
///   program that generates them in a custom way.
///
/// `File` instances are generated in iteration from `files()` function of `Tape` type.
///
#[derive(Debug, PartialEq)]
pub enum File<'a> {
	Bin(String, usize, usize, usize, &'a[u8]),
    Custom(&'a[u8])
}

/// An iterator over the files of a `Tape`
pub struct Files<'a> {
    tape: &'a Tape,
    i: usize,
}

impl<'a> Iterator for Files<'a> {

    type Item = File<'a>;

    fn next(&mut self) -> Option<File<'a>> {
        while self.i < self.tape.blocks.len() {
            let block = &self.tape.blocks[self.i];
            if block.is_bin_header() {
                let name = block.file_name().unwrap().to_string();
                let content = &self.tape.blocks[self.i+1].data;
                let begin = (content[0] as usize) | (content[1] as usize) << 8;
                let end = (content[2] as usize) | (content[3] as usize) << 8;
                let start = (content[4] as usize) | (content[5] as usize) << 8;
                let data = &content[6..];
                self.i = self.i + 2;
                return Some(File::Bin(name, begin, end, start, data));
            } else {
                self.i = self.i + 1;
                return Some(File::Custom(&block.data[..]));
            }
        }
        None
    }
}

/// An MSX tape.
///
/// A tape is a sequence of byte blocks (see `Blocks` for more details). The blocks may be
/// grouped such as the tape is seen as a sequence of files through `files()` method.
///
#[derive(Debug)]
pub struct Tape {
    blocks: Vec<Block>,
}

impl Tape {

    /// Read a `Tape` instance from the given `Read` object.
    ///
    /// This function returns a new `Tape` instance as result of processing the
    /// contents of the `Read` passed as argument (e.g., a file), or an `std::io::Error`
    /// if there is an error while reading.
    ///
	#[allow(dead_code)]
	pub fn read(input: &mut Read) -> Result<Tape, IoError> {
		let mut bytes: Vec<u8> = vec![];
		try!(input.read_to_end(&mut bytes));
		Ok(Tape::from_bytes(&bytes[..]))
	}

    /// Read a `Tape` instance from the given bytes.
    ///
    /// This function returns a new `Tape` instance as result of processing the bytes passed
    /// as argument.
	pub fn from_bytes(bytes: &[u8]) -> Tape {
		Tape { blocks: Tape::parse_blocks(bytes) }
	}

    /// Return the files contained in the tape.
    ///
    /// This function returns an `Iterator` over the files found in the tape blocks.
    ///
    pub fn files(&self) -> Files { Files { tape: self, i: 0 } }

    fn parse_blocks(bytes: &[u8]) -> Vec<Block> {
        let mut blocks: Vec<Block> = vec![];
        let mut hindex: Vec<usize> = vec![];
        let mut i = 0;

        // First of all, we compute the indices of all block headers.
        for win in bytes.windows(8) {
            if win == [0x1f, 0xa6, 0xde, 0xba, 0xcc, 0x13, 0x7d, 0x74] {
                hindex.push(i);
            }
            i = i + 1;
        }

        // Now we use the block header indices to generate the blocks
        for i in 0..hindex.len() {
            let from = hindex[i] + 8;
            let to = if i == hindex.len() - 1 { bytes.len() } else { hindex[i+1] };
            let block = Block::from_data(&bytes[from..to]);
            blocks.push(block);
        }
        blocks
    }
}

#[cfg(test)]
mod test {

    use super::*;

    macro_rules! assert_bin {
        ($f:expr, $n:expr, $b:expr, $e:expr, $s:expr, $d:expr) => {
            match $f {
            &File::Bin(ref name, begin, end, start, data) => {
                assert_eq!($n, name);
                assert_eq!($b, begin);
                assert_eq!($e, end);
                assert_eq!($s, start);
                assert_eq!($d, &data[..]);
            },
            _ => panic!("unexpected file"),
        }
        }
    }

    #[test]
    fn should_detect_bin_header_block() {
        let bytes: Vec<u8> = vec![
            0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0,
            0x46, 0x4f, 0x4f, 0x42, 0x41, 0x52,
        ];
        let block = Block::from_data(&bytes);
        assert!(block.is_bin_header());
        assert_eq!("FOOBAR", block.file_name().unwrap());
    }

    #[test]
    fn should_detect_basic_header_block() {
        let bytes: Vec<u8> = vec![
            0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3,
            0x46, 0x4f, 0x4f, 0x42, 0x41, 0x52,
        ];
        let block = Block::from_data(&bytes);
        assert!(block.is_basic_header());
        assert_eq!("FOOBAR", block.file_name().unwrap());
    }

    #[test]
    fn should_detect_ascii_header_block() {
        let bytes: Vec<u8> = vec![
            0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea,
            0x46, 0x4f, 0x4f, 0x42, 0x41, 0x52,
        ];
        let block = Block::from_data(&bytes);
        assert!(block.is_ascii_header());
        assert_eq!("FOOBAR", block.file_name().unwrap());
    }

    #[test]
    fn should_return_no_name_on_non_header_block() {
        let bytes: Vec<u8> = vec![
            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
            0x46, 0x4f, 0x4f, 0x00, 0x00, 0x00,
        ];
        let block = Block::from_data(&bytes);
        assert_eq!(None, block.file_name());
    }

    #[test]
    fn should_detect_block_with_short_name() {
        let bytes: Vec<u8> = vec![
            0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0,
            0x46, 0x4f, 0x4f, 0x00, 0x00, 0x00,
        ];
        let block = Block::from_data(&bytes);
        assert_eq!("FOO", block.file_name().unwrap());
    }

    #[test]
    fn should_load_empty_tape() {
    	let bytes: Vec<u8> = vec![];
    	let tape = Tape::from_bytes(&bytes);
        assert_eq!(None, tape.files().next());
    }

    #[test]
    fn should_load_bin_file() {
        let bytes: Vec<u8> = vec![
            0x1f, 0xa6, 0xde, 0xba, 0xcc, 0x13, 0x7d, 0x74,
            0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0,
            0x46, 0x4f, 0x4f, 0x42, 0x41, 0x52,
            0x1f, 0xa6, 0xde, 0xba, 0xcc, 0x13, 0x7d, 0x74,
            0x00, 0x80, 0x08, 0x80, 0x00, 0x00,
            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
        ];
        let tape = Tape::from_bytes(&bytes);
        for f in tape.files() {
            assert_bin!(&f,
                "FOOBAR", 0x8000, 0x8008, 0x0000, &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]);
        }
    }
}
<commit_msg>Use 8-byte alignment for input data of `tape` unit tests<commit_after>//
// MSX CAS Packager
// Copyright (c) 2015 Alvaro Polo
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::io::Read;
use std::io::Error as IoError;
use std::str::from_utf8;

/// A block of data contained in a tape.
///
/// A tape file is comprised by a sequence of blocks. Each block starts with the prefix bytes
/// `1fa6debacc137d74` followed by the block data. The `Block` type stores the block data
/// without the prefix bytes.
///
#[derive(Debug)]
pub struct Block {
    data: Vec<u8>,
}

impl Block {

    /// Generates a new block from the data bytes (without the prefix bytes).
    pub fn from_data(bytes: &[u8]) -> Block {
        Block { data: Vec::from(bytes) }
    }

    /// Returns the block data (without the prefix bytes).
    pub fn data(&self) -> &[u8] { &self.data[..] }

    /// Returns `true` if the block is detected as a binary header.
    ///
    /// A bin header is comprised by `0xd0d0d0d0d0d0d0d0d0d0` followed by six bytes for
    /// the name of the binary file. This function returns `true` if the block data match
    /// this pattern, `false` otherwise.
    pub fn is_bin_header(&self) -> bool {
        self.data.len() == 16 &&
            self.data[..10] == [0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0]
    }

    /// Returns `true` if the block is detected as a Basic header.
    ///
    /// A Basic header is comprised by `0xd3d3d3d3d3d3d3d3d3d3` followed by six bytes for
    /// the name of the Basic file. This function returns `true` if the block data match
    /// this pattern, `false` otherwise.
    pub fn is_basic_header(&self) -> bool {
        self.data.len() == 16 &&
            self.data[..10] == [0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3]
    }

    /// Returns `true` if the block is detected as an ASCII header.
    ///
    /// An ASCII header is comprised by `0xeaeaeaeaeaeaeaeaeaea` followed by six bytes for
    /// the name of the ASCII file. This function returns `true` if the block data match
    /// this pattern, `false` otherwise.
    pub fn is_ascii_header(&self) -> bool {
        self.data.len() == 16 &&
            self.data[..10] == [0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea]
    }

    /// Returns the file name in case of a binary, ascii or basic header, `None` otherwise.
    pub fn file_name(&self) -> Option<&str> {
        if self.is_bin_header() || self.is_basic_header() || self.is_ascii_header() {
            let name = &self.data[10..16];
            let mut last = 6;
            for i in (0..6).rev() {
                if name[i] == 0 { last = i }
            }
            from_utf8(&name[..last]).ok()
        }
        else { None }
    }
}

/// A file contained in a tape
///
/// Files stored in a tape can be one of:
/// * Binary files. They contain binary code and/or data. They are loaded using `BLOAD`
///   instruction from Basic.
/// * ASCII files. They contain text, typically corresponding to Basic source code. They are
///   loaded using `LOAD` instruction from Basic.
/// * Basic files. They contain tokenized Basic, a compact form of Basic source code. They are
///   loaded using `CLOAD` instruction from Basic.
/// * Custom files. They contain arbitrary data generated by a program using direct calls to
///   casette IO addresses. Its contents cannot be processed from Basic but loaded from the
///   program that generates them in a custom way.
///
/// `File` instances are generated in iteration from `files()` function of `Tape` type.
///
#[derive(Debug, PartialEq)]
pub enum File<'a> {
	Bin(String, usize, usize, usize, &'a[u8]),
    Custom(&'a[u8])
}

/// An iterator over the files of a `Tape`
pub struct Files<'a> {
    tape: &'a Tape,
    i: usize,
}

impl<'a> Iterator for Files<'a> {

    type Item = File<'a>;

    fn next(&mut self) -> Option<File<'a>> {
        while self.i < self.tape.blocks.len() {
            let block = &self.tape.blocks[self.i];
            if block.is_bin_header() {
                let name = block.file_name().unwrap().to_string();
                let content = &self.tape.blocks[self.i+1].data;
                let begin = (content[0] as usize) | (content[1] as usize) << 8;
                let end = (content[2] as usize) | (content[3] as usize) << 8;
                let start = (content[4] as usize) | (content[5] as usize) << 8;
                let data = &content[6..];
                self.i = self.i + 2;
                return Some(File::Bin(name, begin, end, start, data));
            } else {
                self.i = self.i + 1;
                return Some(File::Custom(&block.data[..]));
            }
        }
        None
    }
}

/// An MSX tape.
///
/// A tape is a sequence of byte blocks (see `Blocks` for more details). The blocks may be
/// grouped such as the tape is seen as a sequence of files through `files()` method.
///
#[derive(Debug)]
pub struct Tape {
    blocks: Vec<Block>,
}

impl Tape {

    /// Read a `Tape` instance from the given `Read` object.
    ///
    /// This function returns a new `Tape` instance as result of processing the
    /// contents of the `Read` passed as argument (e.g., a file), or an `std::io::Error`
    /// if there is an error while reading.
    ///
	#[allow(dead_code)]
	pub fn read(input: &mut Read) -> Result<Tape, IoError> {
		let mut bytes: Vec<u8> = vec![];
		try!(input.read_to_end(&mut bytes));
		Ok(Tape::from_bytes(&bytes[..]))
	}

    /// Read a `Tape` instance from the given bytes.
    ///
    /// This function returns a new `Tape` instance as result of processing the bytes passed
    /// as argument.
	pub fn from_bytes(bytes: &[u8]) -> Tape {
		Tape { blocks: Tape::parse_blocks(bytes) }
	}

    /// Return the files contained in the tape.
    ///
    /// This function returns an `Iterator` over the files found in the tape blocks.
    ///
    pub fn files(&self) -> Files { Files { tape: self, i: 0 } }

    fn parse_blocks(bytes: &[u8]) -> Vec<Block> {
        let mut blocks: Vec<Block> = vec![];
        let mut hindex: Vec<usize> = vec![];
        let mut i = 0;

        // First of all, we compute the indices of all block headers.
        for win in bytes.windows(8) {
            if win == [0x1f, 0xa6, 0xde, 0xba, 0xcc, 0x13, 0x7d, 0x74] {
                hindex.push(i);
            }
            i = i + 1;
        }

        // Now we use the block header indices to generate the blocks
        for i in 0..hindex.len() {
            let from = hindex[i] + 8;
            let to = if i == hindex.len() - 1 { bytes.len() } else { hindex[i+1] };
            let block = Block::from_data(&bytes[from..to]);
            blocks.push(block);
        }
        blocks
    }
}

#[cfg(test)]
mod test {

    use super::*;

    macro_rules! assert_bin {
        ($f:expr, $n:expr, $b:expr, $e:expr, $s:expr, $d:expr) => {
            match $f {
            &File::Bin(ref name, begin, end, start, data) => {
                assert_eq!($n, name);
                assert_eq!($b, begin);
                assert_eq!($e, end);
                assert_eq!($s, start);
                assert_eq!($d, &data[..]);
            },
            _ => panic!("unexpected file"),
        }
        }
    }

    #[test]
    fn should_detect_bin_header_block() {
        let bytes: Vec<u8> = vec![
            0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0,
            0xd0, 0xd0, 0x46, 0x4f, 0x4f, 0x42, 0x41, 0x52,
        ];
        let block = Block::from_data(&bytes);
        assert!(block.is_bin_header());
        assert_eq!("FOOBAR", block.file_name().unwrap());
    }

    #[test]
    fn should_detect_basic_header_block() {
        let bytes: Vec<u8> = vec![
            0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3,
            0xd3, 0xd3, 0x46, 0x4f, 0x4f, 0x42, 0x41, 0x52,
        ];
        let block = Block::from_data(&bytes);
        assert!(block.is_basic_header());
        assert_eq!("FOOBAR", block.file_name().unwrap());
    }

    #[test]
    fn should_detect_ascii_header_block() {
        let bytes: Vec<u8> = vec![
            0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea,
            0xea, 0xea, 0x46, 0x4f, 0x4f, 0x42, 0x41, 0x52,
        ];
        let block = Block::from_data(&bytes);
        assert!(block.is_ascii_header());
        assert_eq!("FOOBAR", block.file_name().unwrap());
    }

    #[test]
    fn should_return_no_name_on_non_header_block() {
        let bytes: Vec<u8> = vec![
            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
            0x09, 0x0a, 0x46, 0x4f, 0x4f, 0x00, 0x00, 0x00,
        ];
        let block = Block::from_data(&bytes);
        assert_eq!(None, block.file_name());
    }

    #[test]
    fn should_detect_block_with_short_name() {
        let bytes: Vec<u8> = vec![
            0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0,
            0xd0, 0xd0, 0x46, 0x4f, 0x4f, 0x00, 0x00, 0x00,
        ];
        let block = Block::from_data(&bytes);
        assert_eq!("FOO", block.file_name().unwrap());
    }

    #[test]
    fn should_load_empty_tape() {
    	let bytes: Vec<u8> = vec![];
    	let tape = Tape::from_bytes(&bytes);
        assert_eq!(None, tape.files().next());
    }

    #[test]
    fn should_load_bin_file() {
        let bytes: Vec<u8> = vec![
            0x1f, 0xa6, 0xde, 0xba, 0xcc, 0x13, 0x7d, 0x74,
            0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0,
            0xd0, 0xd0, 0x46, 0x4f, 0x4f, 0x42, 0x41, 0x52,
            0x1f, 0xa6, 0xde, 0xba, 0xcc, 0x13, 0x7d, 0x74,
            0x00, 0x80, 0x08, 0x80, 0x00, 0x00, 0x01, 0x02,
            0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a
        ];
        let tape = Tape::from_bytes(&bytes);
        for f in tape.files() {
            assert_bin!(&f,
                "FOOBAR",
                0x8000,
                0x8008,
                0x0000,
                &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a]);
        }
    }
}
<|endoftext|>


<commit_before>use std::rc::Rc;
use std::ops::Deref;

use expr::{Expr, Type, Prim, Proc};
use error::Error as E;
use env::{Env, Result};
use util::*;
use stdlib::*;
use skk;
#[cfg(test)]
use read::read;

fn bind_names(mut env: &mut Env, params: &Expr, args: &Expr) -> Result<()>{
    let mut phead = params;
    let mut ahead = args;
    let nil = &Expr::Nil;
    while phead != nil && ahead != nil {
        match (phead, ahead) {
            (&Expr::Cons(ref pcar, ref pcdr), &Expr::Cons(ref acar, ref acdr)) => {
                match pcar.deref() {
                    &Expr::Sym(ref name) => env.register(name.clone(), acar.deref().clone()),
                    pcar => return Err(E::Form(pcar.clone()))
                };
                phead = pcdr.deref();
                ahead = acdr.deref();
            },
            _ => return Err(E::Form(args.clone()))
        }
    };
    Ok(())
}

pub fn funcall(mut env: &mut Env, f: &Proc, args: &Expr) -> Result<Expr> {
    match f {
        &Proc::Prim(prim) => {
            match prim {
                Prim::Add => k_add(env, args),
                Prim::Sub => k_sub(env, args),
                Prim::Div => k_div(env, args),
                Prim::Mul => k_mul(env, args),
                Prim::Concat => k_concat(env, args),
                Prim::Funcall => k_funcall(env, args),
                Prim::Car => k_car(env, args),
                Prim::Cdr => k_cdr(env, args),
                Prim::CurrentTimeString => skk::k_current_time_string(env, args),
                Prim::SkkCalc => skk::k_skk_calc(env, args),
                Prim::SkkGadgetUnitsConversion  =>  skk::k_skk_gadget_units_conversion(env, args)
            }
        },
        &Proc::Lambda(ref params, ref body) => {
            env.new_local();
            try!(bind_names(env, params.deref(), args));
            let ret = eval(env, body.deref());
            env.end_local();
            ret
        }
    }
}

fn k_quote(_: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args, (sexp, Any));
    Ok(sexp.clone())
}

fn f_lambda(_: &mut Env, args: &Expr) -> Result<Proc> {
    match args {
        &Expr::Cons(ref params, ref body) => Ok(Proc::Lambda(params.clone(), Rc::new(Expr::Cons(Rc::new(Expr::Sym("progn".to_string())), body.clone())))),
        _ => unreachable!()
    }
}

fn k_lambda(mut env: &mut Env, args: &Expr) -> Result<Expr> {
    Ok(Expr::Proc(try!(f_lambda(env, args))))
}

fn k_feval(mut env: &mut Env, args: &Expr) -> Result<Expr> {
    match args {
        &Expr::Cons(ref car, _) => Ok(Expr::Proc(try!(feval(env, car.deref())))),
        _ => unreachable!()
    }
}

fn k_progn(mut env: &mut Env, args: &Expr) -> Result<Expr> {
    let mut head = args;
    let nil = &Expr::Nil;
    let mut res = Expr::Nil;
    while head != nil {
        match head {
            &Expr::Cons(ref car, ref cdr) => {
                res = try!(eval(env, car.deref()));
                head = cdr.deref();
            },
            _ => return Err(E::Form(args.clone()))
        }
    };
    Ok(res)
}

fn k_fset(mut env: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args, (s, Any) (f, Any));
    let s = try!(eval(env, s));
    let f = try!(feval(env, f));
    let tmp = cons(s, Expr::Nil);
    get_args!(&tmp, (s, Sym));
    env.fregister(s.clone(), f.clone());
    return Ok(Expr::Nil);
}

fn k_if(mut env: &mut Env, args: &Expr) -> Result<Expr> {
    // TODO: optional else clasue. Need optional argments.
    get_args!(args, (cnd, Any) (thn, Any) (els, Any));
    let res = try!(eval(env, cnd));
    if res != Expr::Nil {
        eval(env, thn)
    } else {
        eval(env, els)
    }
}

fn feval(mut env: &mut Env, expr: &Expr) -> Result<Proc> {
    match expr {
        &Expr::Sym(ref sym) => {
            match env.ffind(sym) {
                Ok(f) => Ok(f.clone()),
                Err(e) => Err(e)
            }
        },
        &Expr::Cons(ref op, ref rest) => {
            let op = op.deref();
            match op {
                &Expr::Sym(ref sym) => match &sym[..] {
                    "lambda" => f_lambda(env, rest.deref()),
                    _ => Err(E::NotFunction(expr.clone()))
                },
                _ => Err(E::NotFunction(expr.clone()))
            }
        }
        &Expr::Proc(ref f) => Ok(f.clone()),
        _ => Err(E::NotFunction(expr.clone()))
    }
}

pub fn eval(mut env: &mut Env, expr: &Expr) -> Result<Expr> {
    match expr {
        &Expr::Nil |
        &Expr::EOF |
        &Expr::Str(_) |
        &Expr::Int(_) |
        &Expr::Proc(_) => Ok(expr.clone()),
        &Expr::Sym(ref name) => match env.find(&name.to_string()) {
            Ok(v) =>Ok(v.clone()),
            Err(m) => Err(m)
        },
        &Expr::Cons(ref car, ref cdr) => {
            let car = car.deref();
            let cdr = cdr.deref();
            match car {
                &Expr::Sym(ref sym) => match &sym[..] {
                    "quote" => k_quote(env, cdr),
                    "function" => k_feval(env, cdr),
                    "lambda" => k_lambda(env, cdr),
                    "progn" => k_progn(env, cdr),
                    "fset" => k_fset(env, cdr),
                    "if" => k_if(env, cdr),
                    _ => {
                        let f = try!(feval(env, car));
                        let arg = try!(f_map(env, &|env, x| eval(env, x), cdr));
                        funcall(env, &f, &arg)
                    }
                },
                car => {
                    let f = try!(feval(env, car));
                    let arg = try!(f_map(env, &|env, x| eval(env, x), cdr));
                    funcall(env, &f, &arg)
                }
            }
        }
    }
}

#[test]
fn test_atom(){
    assert_eq!(eval(&mut Env::new(), &read("1")), Ok(Expr::Int(1)));
    assert_eq!(eval(&mut Env::new(), &read("()")), Ok(Expr::Nil));
    assert_eq!(eval(&mut Env::new(), &read("")), Ok(Expr::EOF));
    assert_eq!(eval(&mut Env::new(), &read("\"string\"")), Ok(Expr::Str("string".to_string())));
}

#[test]
fn test_progn(){
    assert_eq!(eval(&mut Env::new(), &read("(progn 1 2)")), Ok(Expr::Int(2)));
    assert_eq!(eval(&mut Env::new(), &read("(progn (+ 1 2) (+ 2 3))")), Ok(Expr::Int(5)));
}

#[test]
fn test_lambda(){
    assert_eq!(eval(&mut Env::new(), &read("(lambda (x) x)")), Ok(Expr::Proc(Proc::Lambda(Rc::new(list1(Expr::Sym("x".to_string()))),
                                                                           Rc::new(list2(Expr::Sym("progn".to_string()), Expr::Sym("x".to_string())))))));
    assert_eq!(eval(&mut Env::new(), &read("((lambda (x) (+ x x)) 1)")), Ok(Expr::Int(2)))
}

#[test]
fn test_fset(){
    let mut env = Env::new();
    assert_eq!(eval(&mut env, &read("(fset 'add2 (lambda (x) (+ x 2)))")), Ok(Expr::Nil));
    assert_eq!(eval(&mut env, &read("(add2 2)")), Ok(Expr::Int(4)));
}
<commit_msg>write test against if<commit_after>use std::rc::Rc;
use std::ops::Deref;

use expr::{Expr, Type, Prim, Proc};
use error::Error as E;
use env::{Env, Result};
use util::*;
use stdlib::*;
use skk;
#[cfg(test)]
use read::read;

fn bind_names(mut env: &mut Env, params: &Expr, args: &Expr) -> Result<()>{
    let mut phead = params;
    let mut ahead = args;
    let nil = &Expr::Nil;
    while phead != nil && ahead != nil {
        match (phead, ahead) {
            (&Expr::Cons(ref pcar, ref pcdr), &Expr::Cons(ref acar, ref acdr)) => {
                match pcar.deref() {
                    &Expr::Sym(ref name) => env.register(name.clone(), acar.deref().clone()),
                    pcar => return Err(E::Form(pcar.clone()))
                };
                phead = pcdr.deref();
                ahead = acdr.deref();
            },
            _ => return Err(E::Form(args.clone()))
        }
    };
    Ok(())
}

pub fn funcall(mut env: &mut Env, f: &Proc, args: &Expr) -> Result<Expr> {
    match f {
        &Proc::Prim(prim) => {
            match prim {
                Prim::Add => k_add(env, args),
                Prim::Sub => k_sub(env, args),
                Prim::Div => k_div(env, args),
                Prim::Mul => k_mul(env, args),
                Prim::Concat => k_concat(env, args),
                Prim::Funcall => k_funcall(env, args),
                Prim::Car => k_car(env, args),
                Prim::Cdr => k_cdr(env, args),
                Prim::CurrentTimeString => skk::k_current_time_string(env, args),
                Prim::SkkCalc => skk::k_skk_calc(env, args),
                Prim::SkkGadgetUnitsConversion  =>  skk::k_skk_gadget_units_conversion(env, args)
            }
        },
        &Proc::Lambda(ref params, ref body) => {
            env.new_local();
            try!(bind_names(env, params.deref(), args));
            let ret = eval(env, body.deref());
            env.end_local();
            ret
        }
    }
}

fn k_quote(_: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args, (sexp, Any));
    Ok(sexp.clone())
}

fn f_lambda(_: &mut Env, args: &Expr) -> Result<Proc> {
    match args {
        &Expr::Cons(ref params, ref body) => Ok(Proc::Lambda(params.clone(), Rc::new(Expr::Cons(Rc::new(Expr::Sym("progn".to_string())), body.clone())))),
        _ => unreachable!()
    }
}

fn k_lambda(mut env: &mut Env, args: &Expr) -> Result<Expr> {
    Ok(Expr::Proc(try!(f_lambda(env, args))))
}

fn k_feval(mut env: &mut Env, args: &Expr) -> Result<Expr> {
    match args {
        &Expr::Cons(ref car, _) => Ok(Expr::Proc(try!(feval(env, car.deref())))),
        _ => unreachable!()
    }
}

fn k_progn(mut env: &mut Env, args: &Expr) -> Result<Expr> {
    let mut head = args;
    let nil = &Expr::Nil;
    let mut res = Expr::Nil;
    while head != nil {
        match head {
            &Expr::Cons(ref car, ref cdr) => {
                res = try!(eval(env, car.deref()));
                head = cdr.deref();
            },
            _ => return Err(E::Form(args.clone()))
        }
    };
    Ok(res)
}

fn k_fset(mut env: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args, (s, Any) (f, Any));
    let s = try!(eval(env, s));
    let f = try!(feval(env, f));
    let tmp = list1(s);
    get_args!(&tmp, (s, Sym));
    env.fregister(s.clone(), f.clone());
    return Ok(Expr::Nil);
}

fn k_set(mut env: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args, (s, Any) (f, Any));
    let s = try!(eval(env, s));
    let e = try!(eval(env, f));
    let tmp = list1(s);
    get_args!(&tmp, (s, Sym));
    env.register(s.clone(), e.clone());
    return Ok(Expr::Nil);
}

fn k_if(mut env: &mut Env, args: &Expr) -> Result<Expr> {
    // TODO: optional else clasue. Need optional argments.
    get_args!(args, (cnd, Any) (thn, Any) (els, Any));
    let res = try!(eval(env, cnd));
    if res != Expr::Nil {
        eval(env, thn)
    } else {
        eval(env, els)
    }
}

fn feval(mut env: &mut Env, expr: &Expr) -> Result<Proc> {
    match expr {
        &Expr::Sym(ref sym) => {
            match env.ffind(sym) {
                Ok(f) => Ok(f.clone()),
                Err(e) => Err(e)
            }
        },
        &Expr::Cons(ref op, ref rest) => {
            let op = op.deref();
            match op {
                &Expr::Sym(ref sym) => match &sym[..] {
                    "lambda" => f_lambda(env, rest.deref()),
                    _ => Err(E::NotFunction(expr.clone()))
                },
                _ => Err(E::NotFunction(expr.clone()))
            }
        }
        &Expr::Proc(ref f) => Ok(f.clone()),
        _ => Err(E::NotFunction(expr.clone()))
    }
}

pub fn eval(mut env: &mut Env, expr: &Expr) -> Result<Expr> {
    match expr {
        &Expr::Nil |
        &Expr::EOF |
        &Expr::Str(_) |
        &Expr::Int(_) |
        &Expr::Proc(_) => Ok(expr.clone()),
        &Expr::Sym(ref name) => match env.find(&name.to_string()) {
            Ok(v) =>Ok(v.clone()),
            Err(m) => Err(m)
        },
        &Expr::Cons(ref car, ref cdr) => {
            let car = car.deref();
            let cdr = cdr.deref();
            match car {
                &Expr::Sym(ref sym) => match &sym[..] {
                    "quote" => k_quote(env, cdr),
                    "function" => k_feval(env, cdr),
                    "lambda" => k_lambda(env, cdr),
                    "progn" => k_progn(env, cdr),
                    "fset" => k_fset(env, cdr),
                    "set"  => k_set(env, cdr),
                    "if" => k_if(env, cdr),
                    _ => {
                        let f = try!(feval(env, car));
                        let arg = try!(f_map(env, &|env, x| eval(env, x), cdr));
                        funcall(env, &f, &arg)
                    }
                },
                car => {
                    let f = try!(feval(env, car));
                    let arg = try!(f_map(env, &|env, x| eval(env, x), cdr));
                    funcall(env, &f, &arg)
                }
            }
        }
    }
}

#[test]
fn test_atom(){
    assert_eq!(eval(&mut Env::new(), &read("1")), Ok(Expr::Int(1)));
    assert_eq!(eval(&mut Env::new(), &read("()")), Ok(Expr::Nil));
    assert_eq!(eval(&mut Env::new(), &read("")), Ok(Expr::EOF));
    assert_eq!(eval(&mut Env::new(), &read("\"string\"")), Ok(Expr::Str("string".to_string())));
}
// TODO: test `function`

#[test]
fn test_progn(){
    assert_eq!(eval(&mut Env::new(), &read("(progn 1 2)")), Ok(Expr::Int(2)));
    assert_eq!(eval(&mut Env::new(), &read("(progn (+ 1 2) (+ 2 3))")), Ok(Expr::Int(5)));
}

#[test]
fn test_lambda(){
    assert_eq!(eval(&mut Env::new(), &read("(lambda (x) x)")), Ok(Expr::Proc(Proc::Lambda(Rc::new(list1(Expr::Sym("x".to_string()))),
                                                                           Rc::new(list2(Expr::Sym("progn".to_string()), Expr::Sym("x".to_string())))))));
    assert_eq!(eval(&mut Env::new(), &read("((lambda (x) (+ x x)) 1)")), Ok(Expr::Int(2)))
}

#[test]
fn test_fset(){
    let mut env = Env::new();
    assert_eq!(eval(&mut env, &read("(fset 'add2 (lambda (x) (+ x 2)))")), Ok(Expr::Nil));
    assert_eq!(eval(&mut env, &read("(add2 2)")), Ok(Expr::Int(4)));
}

#[test]
fn test_set() {
    let mut env = Env::new();
    assert_eq!(eval(&mut env, &read("(set 'foo (+ 1 2 3))")), Ok(Expr::Nil));
    assert_eq!(eval(&mut env, &read("foo")), Ok(Expr::Int(6)));

}

#[test]
fn test_if() {
    assert_eq!(eval(&mut Env::new(), &read("(if () 1 2)")), Ok(Expr::Int(2)));
    assert_eq!(eval(&mut Env::new(), &read("(if 1 1 2)")), Ok(Expr::Int(1)));
}
<|endoftext|>


<commit_before>//! Backend for Rust

use backend::PackageProcessor;
use core::errors::*;
use core::{self, ForEachLoc, Handle, RelativePath, RelativePathBuf};
use flavored::{RpEnumBody, RpField, RpInterfaceBody, RpName, RpPackage, RpServiceBody,
               RpTupleBody, RpTypeBody, RustFlavor};
use genco::{Cons, IntoTokens, Quoted, Rust, Tokens};
use rust_file_spec::RustFileSpec;
use std::collections::{BTreeMap, BTreeSet};
use std::rc::Rc;
use trans::{self, Translated};
use utils::Comments;
use {Options, Root, Service, EXT, LIB, MOD, TYPE_SEP};

/// #[allow(non_camel_case_types)] attribute.
pub struct AllowNonCamelCaseTypes;

impl<'a> IntoTokens<'a, Rust<'a>> for AllowNonCamelCaseTypes {
    fn into_tokens(self) -> Tokens<'a, Rust<'a>> {
        "#[allow(non_camel_case_types)]".into()
    }
}

/// Serializer derives.
pub struct Derives;

impl<'a> IntoTokens<'a, Rust<'a>> for Derives {
    fn into_tokens(self) -> Tokens<'a, Rust<'a>> {
        "#[derive(Serialize, Deserialize, Debug)]".into()
    }
}

/// A serde rename annotation.
pub struct Rename<'a>(&'a str);

impl<'a> IntoTokens<'a, Rust<'a>> for Rename<'a> {
    fn into_tokens(self) -> Tokens<'a, Rust<'a>> {
        toks!["#[serde(rename = ", self.0.quoted(), ")]"]
    }
}

/// Tag attribute.
pub struct Tag<'a>(&'a str);

impl<'a> IntoTokens<'a, Rust<'a>> for Tag<'a> {
    fn into_tokens(self) -> Tokens<'a, Rust<'a>> {
        toks!["#[serde(tag = ", self.0.quoted(), ")]"]
    }
}

pub struct Compiler<'el> {
    pub env: &'el Translated<RustFlavor>,
    options: Options,
    handle: &'el Handle,
}

impl<'el> Compiler<'el> {
    pub fn new(
        env: &'el Translated<RustFlavor>,
        options: Options,
        handle: &'el Handle,
    ) -> Compiler<'el> {
        Compiler {
            env,
            options,
            handle,
        }
    }

    /// Build an implementation of the given name and body.
    fn build_impl(&self, name: Rc<String>, body: Tokens<'el, Rust<'el>>) -> Tokens<'el, Rust<'el>> {
        let mut out_impl = Tokens::new();

        out_impl.push(toks!["impl ", name.clone(), " {"]);
        out_impl.nested(body);
        out_impl.push("}");

        out_impl
    }

    /// Convert the type name
    ///
    /// Optionally also emit the necessary attributes to suppress warnings for bad naming
    /// conventions.
    fn convert_type_name(&self, name: &RpName) -> (Rc<String>, Tokens<'static, Rust<'static>>) {
        let attributes = if name.parts.len() > 1 {
            AllowNonCamelCaseTypes.into_tokens()
        } else {
            Tokens::new()
        };

        (Rc::new(name.join(TYPE_SEP)), attributes)
    }

    fn into_type<'a>(&self, field: &'a RpField) -> Result<Tokens<'a, Rust<'a>>> {
        let stmt = toks![field.ty.clone()];

        if field.is_optional() {
            return Ok(toks!["Option<", stmt, ">"]);
        }

        Ok(stmt)
    }

    fn enum_value_fn<'a>(
        &self,
        name: Rc<String>,
        match_body: Tokens<'a, Rust<'a>>,
    ) -> Tokens<'a, Rust<'a>> {
        let mut value_fn = Tokens::new();
        let mut match_decl = Tokens::new();

        match_decl.push("match *self {");
        match_decl.nested(match_body);
        match_decl.push("}");

        value_fn.push("pub fn value(&self) -> &'static str {");
        value_fn.nested(toks!["use self::", name, "::*;"]);
        value_fn.nested(match_decl);
        value_fn.push("}");

        value_fn
    }

    // Build the corresponding element out of a field declaration.
    fn field_element<'a>(&self, field: &'a RpField, is_pub: bool) -> Result<Tokens<'a, Rust<'a>>> {
        let mut t = Tokens::new();

        let ident = field.safe_ident();
        let type_spec = self.into_type(field)?;

        if field.is_optional() {
            t.push(toks!["#[serde(skip_serializing_if=\"Option::is_none\")]"]);
        }

        if field.name() != ident {
            t.push(Rename(field.name()));
        }

        t.push_into(|t| {
            if is_pub {
                t.append("pub ");
            }

            t.append(toks![ident, ": ", type_spec, ","]);
        });

        Ok(t.into())
    }

    pub fn compile(&self) -> Result<()> {
        let mut files = self.populate_files()?;

        for g in &self.options.root {
            g.generate(Root { files: &mut files })?;
        }

        self.write_mod_files(&files)?;
        self.write_files(files)
    }

    fn write_mod_files(&self, files: &BTreeMap<RpPackage, RustFileSpec>) -> Result<()> {
        let mut packages: BTreeMap<RelativePathBuf, BTreeSet<String>> = BTreeMap::new();
        let mut root_names = BTreeSet::new();

        for (package, _) in files {
            let mut current = RelativePathBuf::new();

            let mut it = package.parts().peekable();

            if let Some(root) = it.peek() {
                root_names.insert(root.to_string());
            }

            while let Some(part) = it.next() {
                current = current.join(part);

                if let Some(next) = it.peek() {
                    let mut full_path = current.join(MOD);
                    full_path.set_extension(self.ext());

                    packages
                        .entry(full_path)
                        .or_insert_with(BTreeSet::new)
                        .insert(next.to_string());
                }
            }
        }

        let mut root_mod = RelativePathBuf::new().join(MOD);
        root_mod.set_extension(self.ext());
        packages.insert(root_mod, root_names);

        let handle = self.handle();

        for (full_path, children) in packages {
            // skip writing mod if lib file exists.
            let lib_path = full_path.with_file_name(LIB).with_extension(self.ext());
            let parent = full_path.parent().unwrap_or(RelativePath::new("."));

            if !self.handle.is_dir(&parent) {
                debug!("+dir: {}", parent.display());
                handle.create_dir_all(&parent)?;
            }

            // do not create mod file if there is a lib.rs in the root.
            if lib_path.parent().is_none() && handle.is_file(&lib_path) {
                debug!(
                    "+mod: {} (skip due to: {})",
                    full_path.display(),
                    lib_path.display()
                );
                continue;
            }

            if !handle.is_file(&full_path) {
                debug!("+mod: {}", full_path.display());
                let mut f = handle.create(&full_path)?;

                for child in children {
                    writeln!(f, "pub mod {};", child)?;
                }
            }
        }

        Ok(())
    }
}

impl<'el> PackageProcessor<'el, RustFlavor, RpName> for Compiler<'el> {
    type Out = RustFileSpec<'el>;
    type DeclIter = trans::translated::DeclIter<'el, RustFlavor>;

    fn ext(&self) -> &str {
        EXT
    }

    fn decl_iter(&self) -> Self::DeclIter {
        self.env.decl_iter()
    }

    fn handle(&self) -> &'el Handle {
        self.handle
    }

    fn default_process(&self, _out: &mut Self::Out, _: &RpName) -> Result<()> {
        Ok(())
    }

    fn process_tuple(&self, out: &mut Self::Out, body: &'el RpTupleBody) -> Result<()> {
        let mut fields = Tokens::new();

        for field in &body.fields {
            fields.append(toks!["pub ", self.into_type(field)?]);
        }

        let (name, attributes) = self.convert_type_name(&body.name);

        let mut t = Tokens::new();

        t.push_unless_empty(Comments(&body.comment));
        t.push_unless_empty(attributes);
        t.push(Derives);
        t.push(toks!["pub struct ", name, "(", fields.join(", "), ");",]);

        out.0.push(t);
        Ok(())
    }

    fn process_enum(&self, out: &mut Self::Out, body: &'el RpEnumBody) -> Result<()> {
        let (name, attributes) = self.convert_type_name(&body.name);

        // variant declarations
        let mut variants = Tokens::new();
        // body of value function
        let mut match_body = Tokens::new();

        body.variants.iter().for_each_loc(|variant| {
            let value = if let core::RpEnumOrdinal::String(ref s) = variant.ordinal {
                if s != variant.ident() {
                    variants.push(Rename(s.as_str()));
                }

                s
            } else {
                variant.ident()
            };

            match_body.push(toks![variant.ident(), " => ", value.quoted(), ",",]);

            variants.push_unless_empty(Comments(&variant.comment));
            variants.push(toks![variant.ident(), ","]);
            Ok(()) as Result<()>
        })?;

        out.0.push({
            let mut t = Tokens::new();

            t.push_unless_empty(Comments(&body.comment));
            t.push_unless_empty(attributes);
            t.push(Derives);
            t.push(toks!["pub enum ", name.clone(), " {"]);
            t.nested(variants);
            t.push("}");

            t
        });

        out.0.push({
            let mut t = Tokens::new();

            t.push(toks!["impl ", name.clone(), " {"]);

            t.nested({
                let mut t = Tokens::new();
                t.push(self.enum_value_fn(name.clone(), match_body));
                t.push_unless_empty(code!(&body.codes, core::RpContext::Rust));
                t
            });

            t.push("}");

            t
        });

        Ok(())
    }

    fn process_type(&self, out: &mut Self::Out, body: &'el RpTypeBody) -> Result<()> {
        let (name, attributes) = self.convert_type_name(&body.name);
        let mut t = Tokens::new();

        t.push_unless_empty(Comments(&body.comment));
        t.push_unless_empty(attributes);
        t.push(Derives);
        t.push(toks!["pub struct ", name.clone(), " {"]);

        // fields
        t.nested({
            let mut t = Tokens::new();

            for field in &body.fields {
                t.push({
                    let mut t = Tokens::new();
                    t.push_unless_empty(Comments(&field.comment));
                    t.push(self.field_element(field, true)?);
                    t
                });
            }

            t.join_line_spacing()
        });

        t.push("}");

        out.0.push(t);

        // if custom code is present, punt it into an impl.
        let impl_body = code!(&body.codes, core::RpContext::Rust).into_tokens();

        if !impl_body.is_empty() {
            out.0.push(self.build_impl(name.clone(), impl_body));
        }

        Ok(())
    }

    fn process_interface(&self, out: &mut Self::Out, body: &'el RpInterfaceBody) -> Result<()> {
        let (name, attributes) = self.convert_type_name(&body.name);

        let mut t = Tokens::new();

        t.push_unless_empty(Comments(&body.comment));
        t.push_unless_empty(attributes);
        t.push(Derives);

        match body.sub_type_strategy {
            core::RpSubTypeStrategy::Tagged { ref tag, .. } => {
                t.push(Tag(tag.as_str()));
            }
        }

        t.push(toks!["pub enum ", name.clone(), " {"]);

        body.sub_types.iter().for_each_loc(|s| {
            t.nested({
                let mut t = Tokens::new();

                t.push_unless_empty(Comments(&s.comment));

                // TODO: clone should not be needed
                if let Some(ref name) = s.sub_type_name {
                    if name.as_str() != s.ident.as_str() {
                        t.push(Rename(name));
                    }
                }

                t.push(toks![s.ident.as_str(), " {"]);

                t.push({
                    let mut t = Tokens::new();

                    for field in body.fields.iter().chain(s.fields.iter()) {
                        t.nested({
                            let mut t = Tokens::new();
                            t.push_unless_empty(Comments(&field.comment));
                            t.push(self.field_element(field, false)?);
                            t
                        });
                    }

                    t.join_line_spacing()
                });

                t.push("},");

                t
            });

            Ok(()) as Result<()>
        })?;

        t.push("}");

        out.0.push(t);

        let impl_body = code!(&body.codes, core::RpContext::Rust).into_tokens();

        if !impl_body.is_empty() {
            out.0.push(self.build_impl(name.clone(), impl_body));
        }

        Ok(())
    }

    fn process_service(&self, out: &mut Self::Out, body: &'el RpServiceBody) -> Result<()> {
        let (name, attributes) = self.convert_type_name(&body.name);

        for s in &self.options.service {
            s.generate(Service {
                body: body,
                container: &mut out.0,
                name: Cons::from(name.clone()),
                attributes: &attributes,
            })?;
        }

        Ok(())
    }
}
<commit_msg>rust: support required_fields<commit_after>//! Backend for Rust

use backend::PackageProcessor;
use core::errors::*;
use core::{self, ForEachLoc, Handle, RelativePath, RelativePathBuf};
use flavored::{RpEnumBody, RpField, RpInterfaceBody, RpName, RpPackage, RpServiceBody,
               RpTupleBody, RpTypeBody, RustFlavor};
use genco::{Cons, IntoTokens, Quoted, Rust, Tokens};
use rust_file_spec::RustFileSpec;
use std::collections::{BTreeMap, BTreeSet};
use std::rc::Rc;
use trans::{self, Translated};
use utils::Comments;
use {Options, Root, Service, EXT, LIB, MOD, TYPE_SEP};

/// #[allow(non_camel_case_types)] attribute.
pub struct AllowNonCamelCaseTypes;

impl<'a> IntoTokens<'a, Rust<'a>> for AllowNonCamelCaseTypes {
    fn into_tokens(self) -> Tokens<'a, Rust<'a>> {
        "#[allow(non_camel_case_types)]".into()
    }
}

/// Serializer derives.
pub struct Derives;

impl<'a> IntoTokens<'a, Rust<'a>> for Derives {
    fn into_tokens(self) -> Tokens<'a, Rust<'a>> {
        "#[derive(Serialize, Deserialize, Debug)]".into()
    }
}

/// A serde rename annotation.
pub struct Rename<'a>(&'a str);

impl<'a> IntoTokens<'a, Rust<'a>> for Rename<'a> {
    fn into_tokens(self) -> Tokens<'a, Rust<'a>> {
        toks!["#[serde(rename = ", self.0.quoted(), ")]"]
    }
}

/// Tag attribute.
pub struct Tag<'a>(&'a str);

impl<'a> IntoTokens<'a, Rust<'a>> for Tag<'a> {
    fn into_tokens(self) -> Tokens<'a, Rust<'a>> {
        toks!["#[serde(tag = ", self.0.quoted(), ")]"]
    }
}

/// Untagged attribute.
pub struct Untagged;

impl<'el> IntoTokens<'el, Rust<'el>> for Untagged {
    fn into_tokens(self) -> Tokens<'el, Rust<'el>> {
        toks!["#[serde(untagged)]"]
    }
}

pub struct Compiler<'el> {
    pub env: &'el Translated<RustFlavor>,
    options: Options,
    handle: &'el Handle,
}

impl<'el> Compiler<'el> {
    pub fn new(
        env: &'el Translated<RustFlavor>,
        options: Options,
        handle: &'el Handle,
    ) -> Compiler<'el> {
        Compiler {
            env,
            options,
            handle,
        }
    }

    /// Build an implementation of the given name and body.
    fn build_impl(&self, name: Rc<String>, body: Tokens<'el, Rust<'el>>) -> Tokens<'el, Rust<'el>> {
        let mut out_impl = Tokens::new();

        out_impl.push(toks!["impl ", name.clone(), " {"]);
        out_impl.nested(body);
        out_impl.push("}");

        out_impl
    }

    /// Convert the type name
    ///
    /// Optionally also emit the necessary attributes to suppress warnings for bad naming
    /// conventions.
    fn convert_type_name(&self, name: &RpName) -> (Rc<String>, Tokens<'static, Rust<'static>>) {
        let attributes = if name.parts.len() > 1 {
            AllowNonCamelCaseTypes.into_tokens()
        } else {
            Tokens::new()
        };

        (Rc::new(name.join(TYPE_SEP)), attributes)
    }

    fn into_type<'a>(&self, field: &'a RpField) -> Result<Tokens<'a, Rust<'a>>> {
        let stmt = toks![field.ty.clone()];

        if field.is_optional() {
            return Ok(toks!["Option<", stmt, ">"]);
        }

        Ok(stmt)
    }

    fn enum_value_fn<'a>(
        &self,
        name: Rc<String>,
        match_body: Tokens<'a, Rust<'a>>,
    ) -> Tokens<'a, Rust<'a>> {
        let mut value_fn = Tokens::new();
        let mut match_decl = Tokens::new();

        match_decl.push("match *self {");
        match_decl.nested(match_body);
        match_decl.push("}");

        value_fn.push("pub fn value(&self) -> &'static str {");
        value_fn.nested(toks!["use self::", name, "::*;"]);
        value_fn.nested(match_decl);
        value_fn.push("}");

        value_fn
    }

    // Build the corresponding element out of a field declaration.
    fn field_element<'a>(&self, field: &'a RpField, is_pub: bool) -> Result<Tokens<'a, Rust<'a>>> {
        let mut t = Tokens::new();

        let ident = field.safe_ident();
        let type_spec = self.into_type(field)?;

        if field.is_optional() {
            t.push(toks!["#[serde(skip_serializing_if=\"Option::is_none\")]"]);
        }

        if field.name() != ident {
            t.push(Rename(field.name()));
        }

        t.push_into(|t| {
            if is_pub {
                t.append("pub ");
            }

            t.append(toks![ident, ": ", type_spec, ","]);
        });

        Ok(t.into())
    }

    pub fn compile(&self) -> Result<()> {
        let mut files = self.populate_files()?;

        for g in &self.options.root {
            g.generate(Root { files: &mut files })?;
        }

        self.write_mod_files(&files)?;
        self.write_files(files)
    }

    fn write_mod_files(&self, files: &BTreeMap<RpPackage, RustFileSpec>) -> Result<()> {
        let mut packages: BTreeMap<RelativePathBuf, BTreeSet<String>> = BTreeMap::new();
        let mut root_names = BTreeSet::new();

        for (package, _) in files {
            let mut current = RelativePathBuf::new();

            let mut it = package.parts().peekable();

            if let Some(root) = it.peek() {
                root_names.insert(root.to_string());
            }

            while let Some(part) = it.next() {
                current = current.join(part);

                if let Some(next) = it.peek() {
                    let mut full_path = current.join(MOD);
                    full_path.set_extension(self.ext());

                    packages
                        .entry(full_path)
                        .or_insert_with(BTreeSet::new)
                        .insert(next.to_string());
                }
            }
        }

        let mut root_mod = RelativePathBuf::new().join(MOD);
        root_mod.set_extension(self.ext());
        packages.insert(root_mod, root_names);

        let handle = self.handle();

        for (full_path, children) in packages {
            // skip writing mod if lib file exists.
            let lib_path = full_path.with_file_name(LIB).with_extension(self.ext());
            let parent = full_path.parent().unwrap_or(RelativePath::new("."));

            if !self.handle.is_dir(&parent) {
                debug!("+dir: {}", parent.display());
                handle.create_dir_all(&parent)?;
            }

            // do not create mod file if there is a lib.rs in the root.
            if lib_path.parent().is_none() && handle.is_file(&lib_path) {
                debug!(
                    "+mod: {} (skip due to: {})",
                    full_path.display(),
                    lib_path.display()
                );
                continue;
            }

            if !handle.is_file(&full_path) {
                debug!("+mod: {}", full_path.display());
                let mut f = handle.create(&full_path)?;

                for child in children {
                    writeln!(f, "pub mod {};", child)?;
                }
            }
        }

        Ok(())
    }
}

impl<'el> PackageProcessor<'el, RustFlavor, RpName> for Compiler<'el> {
    type Out = RustFileSpec<'el>;
    type DeclIter = trans::translated::DeclIter<'el, RustFlavor>;

    fn ext(&self) -> &str {
        EXT
    }

    fn decl_iter(&self) -> Self::DeclIter {
        self.env.decl_iter()
    }

    fn handle(&self) -> &'el Handle {
        self.handle
    }

    fn default_process(&self, _out: &mut Self::Out, _: &RpName) -> Result<()> {
        Ok(())
    }

    fn process_tuple(&self, out: &mut Self::Out, body: &'el RpTupleBody) -> Result<()> {
        let mut fields = Tokens::new();

        for field in &body.fields {
            fields.append(toks!["pub ", self.into_type(field)?]);
        }

        let (name, attributes) = self.convert_type_name(&body.name);

        let mut t = Tokens::new();

        t.push_unless_empty(Comments(&body.comment));
        t.push_unless_empty(attributes);
        t.push(Derives);
        t.push(toks!["pub struct ", name, "(", fields.join(", "), ");",]);

        out.0.push(t);
        Ok(())
    }

    fn process_enum(&self, out: &mut Self::Out, body: &'el RpEnumBody) -> Result<()> {
        let (name, attributes) = self.convert_type_name(&body.name);

        // variant declarations
        let mut variants = Tokens::new();
        // body of value function
        let mut match_body = Tokens::new();

        body.variants.iter().for_each_loc(|variant| {
            let value = if let core::RpEnumOrdinal::String(ref s) = variant.ordinal {
                if s != variant.ident() {
                    variants.push(Rename(s.as_str()));
                }

                s
            } else {
                variant.ident()
            };

            match_body.push(toks![variant.ident(), " => ", value.quoted(), ",",]);

            variants.push_unless_empty(Comments(&variant.comment));
            variants.push(toks![variant.ident(), ","]);
            Ok(()) as Result<()>
        })?;

        out.0.push({
            let mut t = Tokens::new();

            t.push_unless_empty(Comments(&body.comment));
            t.push_unless_empty(attributes);
            t.push(Derives);
            t.push(toks!["pub enum ", name.clone(), " {"]);
            t.nested(variants);
            t.push("}");

            t
        });

        out.0.push({
            let mut t = Tokens::new();

            t.push(toks!["impl ", name.clone(), " {"]);

            t.nested({
                let mut t = Tokens::new();
                t.push(self.enum_value_fn(name.clone(), match_body));
                t.push_unless_empty(code!(&body.codes, core::RpContext::Rust));
                t
            });

            t.push("}");

            t
        });

        Ok(())
    }

    fn process_type(&self, out: &mut Self::Out, body: &'el RpTypeBody) -> Result<()> {
        let (name, attributes) = self.convert_type_name(&body.name);
        let mut t = Tokens::new();

        t.push_unless_empty(Comments(&body.comment));
        t.push_unless_empty(attributes);
        t.push(Derives);
        t.push(toks!["pub struct ", name.clone(), " {"]);

        // fields
        t.nested({
            let mut t = Tokens::new();

            for field in &body.fields {
                t.push({
                    let mut t = Tokens::new();
                    t.push_unless_empty(Comments(&field.comment));
                    t.push(self.field_element(field, true)?);
                    t
                });
            }

            t.join_line_spacing()
        });

        t.push("}");

        out.0.push(t);

        // if custom code is present, punt it into an impl.
        let impl_body = code!(&body.codes, core::RpContext::Rust).into_tokens();

        if !impl_body.is_empty() {
            out.0.push(self.build_impl(name.clone(), impl_body));
        }

        Ok(())
    }

    fn process_interface(&self, out: &mut Self::Out, body: &'el RpInterfaceBody) -> Result<()> {
        let (name, attributes) = self.convert_type_name(&body.name);

        let mut t = Tokens::new();

        t.push_unless_empty(Comments(&body.comment));
        t.push_unless_empty(attributes);
        t.push(Derives);

        match body.sub_type_strategy {
            core::RpSubTypeStrategy::Tagged { ref tag, .. } => {
                t.push(Tag(tag.as_str()));
            }
            core::RpSubTypeStrategy::RequiredFields => {
                t.push(Untagged);
            }
        }

        t.push(toks!["pub enum ", name.clone(), " {"]);

        body.sub_types.iter().for_each_loc(|s| {
            t.nested({
                let mut t = Tokens::new();

                t.push_unless_empty(Comments(&s.comment));

                // TODO: clone should not be needed
                if let Some(ref name) = s.sub_type_name {
                    if name.as_str() != s.ident.as_str() {
                        t.push(Rename(name));
                    }
                }

                t.push(toks![s.ident.as_str(), " {"]);

                t.push({
                    let mut t = Tokens::new();

                    for field in body.fields.iter().chain(s.fields.iter()) {
                        t.nested({
                            let mut t = Tokens::new();
                            t.push_unless_empty(Comments(&field.comment));
                            t.push(self.field_element(field, false)?);
                            t
                        });
                    }

                    t.join_line_spacing()
                });

                t.push("},");

                t
            });

            Ok(()) as Result<()>
        })?;

        t.push("}");

        out.0.push(t);

        let impl_body = code!(&body.codes, core::RpContext::Rust).into_tokens();

        if !impl_body.is_empty() {
            out.0.push(self.build_impl(name.clone(), impl_body));
        }

        Ok(())
    }

    fn process_service(&self, out: &mut Self::Out, body: &'el RpServiceBody) -> Result<()> {
        let (name, attributes) = self.convert_type_name(&body.name);

        for s in &self.options.service {
            s.generate(Service {
                body: body,
                container: &mut out.0,
                name: Cons::from(name.clone()),
                attributes: &attributes,
            })?;
        }

        Ok(())
    }
}
<|endoftext|>