<commit_before>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![feature(plugin, custom_attribute)]
#![plugin(gfx_macros)]

extern crate cgmath;
extern crate gfx;
extern crate gfx_device_gl;
extern crate glfw;
extern crate time;
extern crate rand;
extern crate genmesh;
extern crate noise;

use std::fmt;
use rand::Rng;
use cgmath::FixedArray;
use cgmath::{Matrix4, Point3, Vector3};
use cgmath::{Transform, AffineMatrix3};
use gfx::traits::*;
use glfw::Context;
use genmesh::{Vertices, Triangulate};
use genmesh::generators::{Plane, SharedVertex, IndexedPolygon};
use time::precise_time_s;

use noise::{Seed, perlin2};

#[vertex_format]
#[derive(Clone, Copy)]
struct Vertex {
    #[name = "a_Pos"]
    pos: [f32; 3],

    #[name = "a_Color"]
    color: [f32; 3],
}

impl fmt::Debug for Vertex {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Pos({}, {}, {})", self.pos[0], self.pos[1], self.pos[2])
    }
}

// The shader_param attribute makes sure the following struct can be used to
// pass parameters to a shader.
#[shader_param]
struct Params<R: gfx::Resources> {
    #[name = "u_Model"]
    model: [[f32; 4]; 4],

    #[name = "u_View"]
    view: [[f32; 4]; 4],

    #[name = "u_Proj"]
    proj: [[f32; 4]; 4],

    _dummy: std::marker::PhantomData<R>,
}

static VERTEX_SRC: &'static [u8] = b"
    #version 120

    attribute vec3 a_Pos;
    attribute vec3 a_Color;
    varying vec3 v_Color;

    uniform mat4 u_Model;
    uniform mat4 u_View;
    uniform mat4 u_Proj;

    void main() {
        v_Color = a_Color;
        gl_Position = u_Proj * u_View * u_Model * vec4(a_Pos, 1.0);
    }
";

static FRAGMENT_SRC: &'static [u8] = b"
    #version 120

    varying vec3 v_Color;

    void main() {
        gl_FragColor = vec4(v_Color, 1.0);
    }
";

fn calculate_color(height: f32) -> [f32; 3] {
    if height > 8.0 {
        [0.9, 0.9, 0.9] // white
    } else if height > 0.0 {
        [0.7, 0.7, 0.7] // greay
    } else if height > -5.0 {
        [0.2, 0.7, 0.2] // green
    } else {
        [0.2, 0.2, 0.7] // blue
    }
}

pub fn main() {
    let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();
    let (mut window, events) = glfw
        .create_window(800, 600, "Terrain example", glfw::WindowMode::Windowed)
        .expect("Failed to create GLFW window.");

    window.make_current();
    glfw.set_error_callback(glfw::FAIL_ON_ERRORS);
    window.set_key_polling(true);

    let (w, h) = window.get_framebuffer_size();
    let frame = gfx::Frame::new(w as u16, h as u16);

    let (device, mut factory) = gfx_device_gl::create(|s| window.get_proc_address(s));

    let rand_seed = rand::thread_rng().gen();
    let seed = Seed::new(rand_seed);
    let plane = Plane::subdivide(256, 256);
    let vertex_data: Vec<Vertex> = plane.shared_vertex_iter()
        .map(|(x, y)| {
            let h = perlin2(&seed, &[x, y]) * 32.0;
            Vertex {
                pos: [25.0 * x, 25.0 * y, h],
                color: calculate_color(h),
            }
        })
        .collect();

    let index_data: Vec<u32> = plane.indexed_polygon_iter()
        .triangulate()
        .vertices()
        .map(|i| i as u32)
        .collect();

    let slice = factory
        .create_buffer_index::<u32>(&index_data)
        .to_slice(gfx::PrimitiveType::TriangleList);

    let mesh = factory.create_mesh(&vertex_data);
    let program = factory.link_program(VERTEX_SRC, FRAGMENT_SRC).unwrap();
    let state = gfx::DrawState::new().depth(gfx::state::Comparison::LessEqual, true);

    let mut graphics = (device, factory).into_graphics();

    let aspect = w as f32 / h as f32;
    let data = Params {
        model: Matrix4::identity().into_fixed(),
        view: Matrix4::identity().into_fixed(),
        proj: cgmath::perspective(cgmath::deg(60.0f32), aspect,
                                  0.1, 1000.0).into_fixed(),
        _dummy: std::marker::PhantomData,
    };
    let mut batch = graphics.make_batch(&program, data, &mesh, slice, &state)
                            .unwrap();

    let clear_data = gfx::ClearData {
        color: [0.3, 0.3, 0.3, 1.0],
        depth: 1.0,
        stencil: 0,
    };

    while !window.should_close() {
        glfw.poll_events();
        for (_, event) in glfw::flush_messages(&events) {
            match event {
                glfw::WindowEvent::Key(glfw::Key::Escape, _, glfw::Action::Press, _) =>
                    window.set_should_close(true),
                _ => {},
            }
        }

        let time = precise_time_s() as f32;
        let x = time.sin();
        let y = time.cos();
        let view: AffineMatrix3<f32> = Transform::look_at(
            &Point3::new(x * 32.0, y * 32.0, 16.0),
            &Point3::new(0.0, 0.0, 0.0),
            &Vector3::unit_z(),
        );
        batch.params.view = view.mat.into_fixed();

        graphics.clear(clear_data, gfx::COLOR | gfx::DEPTH, &frame);
        graphics.draw(&batch, &frame).unwrap();
        graphics.end_frame();

        window.swap_buffers();
        graphics.cleanup();
    }
}
<commit_msg>Ported the terrain example<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![feature(plugin, custom_attribute)]
#![plugin(gfx_macros)]

extern crate cgmath;
extern crate gfx;
extern crate gfx_window_glutin;
extern crate glutin;
extern crate time;
extern crate rand;
extern crate genmesh;
extern crate noise;

use std::fmt;
use rand::Rng;
use cgmath::FixedArray;
use cgmath::{Matrix4, Point3, Vector3};
use cgmath::{Transform, AffineMatrix3};
use gfx::traits::*;
use genmesh::{Vertices, Triangulate};
use genmesh::generators::{Plane, SharedVertex, IndexedPolygon};
use time::precise_time_s;

use noise::{Seed, perlin2};

#[vertex_format]
#[derive(Clone, Copy)]
struct Vertex {
    #[name = "a_Pos"]
    pos: [f32; 3],

    #[name = "a_Color"]
    color: [f32; 3],
}

impl fmt::Debug for Vertex {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Pos({}, {}, {})", self.pos[0], self.pos[1], self.pos[2])
    }
}

// The shader_param attribute makes sure the following struct can be used to
// pass parameters to a shader.
#[shader_param]
struct Params<R: gfx::Resources> {
    #[name = "u_Model"]
    model: [[f32; 4]; 4],

    #[name = "u_View"]
    view: [[f32; 4]; 4],

    #[name = "u_Proj"]
    proj: [[f32; 4]; 4],

    _dummy: std::marker::PhantomData<R>,
}

static VERTEX_SRC: &'static [u8] = b"
    #version 120

    attribute vec3 a_Pos;
    attribute vec3 a_Color;
    varying vec3 v_Color;

    uniform mat4 u_Model;
    uniform mat4 u_View;
    uniform mat4 u_Proj;

    void main() {
        v_Color = a_Color;
        gl_Position = u_Proj * u_View * u_Model * vec4(a_Pos, 1.0);
    }
";

static FRAGMENT_SRC: &'static [u8] = b"
    #version 120

    varying vec3 v_Color;

    void main() {
        gl_FragColor = vec4(v_Color, 1.0);
    }
";

fn calculate_color(height: f32) -> [f32; 3] {
    if height > 8.0 {
        [0.9, 0.9, 0.9] // white
    } else if height > 0.0 {
        [0.7, 0.7, 0.7] // greay
    } else if height > -5.0 {
        [0.2, 0.7, 0.2] // green
    } else {
        [0.2, 0.2, 0.7] // blue
    }
}

pub fn main() {
    let (wrap, device, mut factory) =
        gfx_window_glutin::init_titled("Terrain example")
                          .unwrap();

    let rand_seed = rand::thread_rng().gen();
    let seed = Seed::new(rand_seed);
    let plane = Plane::subdivide(256, 256);
    let vertex_data: Vec<Vertex> = plane.shared_vertex_iter()
        .map(|(x, y)| {
            let h = perlin2(&seed, &[x, y]) * 32.0;
            Vertex {
                pos: [25.0 * x, 25.0 * y, h],
                color: calculate_color(h),
            }
        })
        .collect();

    let index_data: Vec<u32> = plane.indexed_polygon_iter()
        .triangulate()
        .vertices()
        .map(|i| i as u32)
        .collect();

    let slice = factory
        .create_buffer_index::<u32>(&index_data)
        .to_slice(gfx::PrimitiveType::TriangleList);

    let mesh = factory.create_mesh(&vertex_data);
    let program = factory.link_program(VERTEX_SRC, FRAGMENT_SRC).unwrap();
    let state = gfx::DrawState::new().depth(gfx::state::Comparison::LessEqual, true);

    let mut graphics = (device, factory).into_graphics();

    let aspect = {
        let (w, h) = wrap.get_size();
        w as f32 / h as f32
    };
    let data = Params {
        model: Matrix4::identity().into_fixed(),
        view: Matrix4::identity().into_fixed(),
        proj: cgmath::perspective(cgmath::deg(60.0f32), aspect,
                                  0.1, 1000.0).into_fixed(),
        _dummy: std::marker::PhantomData,
    };
    let mut batch = graphics.make_batch(&program, data, &mesh, slice, &state)
                            .unwrap();

    let clear_data = gfx::ClearData {
        color: [0.3, 0.3, 0.3, 1.0],
        depth: 1.0,
        stencil: 0,
    };

    'main: loop {
        // quit when Esc is pressed.
        for event in wrap.window.poll_events() {
            match event {
                glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Escape)) => break 'main,
                glutin::Event::Closed => break 'main,
                _ => {},
            }
        }

        let time = precise_time_s() as f32;
        let x = time.sin();
        let y = time.cos();
        let view: AffineMatrix3<f32> = Transform::look_at(
            &Point3::new(x * 32.0, y * 32.0, 16.0),
            &Point3::new(0.0, 0.0, 0.0),
            &Vector3::unit_z(),
        );
        batch.params.view = view.mat.into_fixed();

        graphics.clear(clear_data, gfx::COLOR | gfx::DEPTH, &wrap);
        graphics.draw(&batch, &wrap).unwrap();
        graphics.end_frame();

        wrap.window.swap_buffers();
        graphics.cleanup();
    }
}
<|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.

//! A standard, garbage-collected linked list.

use std::container::Container;

#[deriving(Clone, Eq)]
#[allow(missing_doc)]
pub enum List<T> {
    Cons(T, @List<T>),
    Nil,
}

pub struct Items<'a, T> {
    priv head: &'a List<T>,
    priv next: Option<&'a @List<T>>
}

impl<'a, T> Iterator<&'a T> for Items<'a, T> {
    fn next(&mut self) -> Option<&'a T> {
        match self.next {
            None => match *self.head {
                Nil => None,
                Cons(ref value, ref tail) => {
                    self.next = Some(tail);
                    Some(value)
                }
            },
            Some(next) => match **next {
                Nil => None,
                Cons(ref value, ref tail) => {
                    self.next = Some(tail);
                    Some(value)
                }
            }
        }
    }
}

impl<T> List<T> {
    /// Returns a forward iterator
    pub fn iter<'a>(&'a self) -> Items<'a, T> {
        Items {
            head: self,
            next: None
        }
    }
}

impl<T> Container for List<T> {
    /// Returns the length of a list
    fn len(&self) -> uint { self.iter().len() }

    /// Returns true if the list is empty
    fn is_empty(&self) -> bool { match *self { Nil => true, _ => false } }
}

/// Returns true if a list contains an element with the given value
pub fn has<T:Eq>(list: @List<T>, element: T) -> bool {
    let mut found = false;
    each(list, |e| {
        if *e == element { found = true; false } else { true }
    });
    return found;
}

/// Returns all but the first element of a list
pub fn tail<T>(list: @List<T>) -> @List<T> {
    match *list {
        Cons(_, tail) => return tail,
        Nil => fail!("list empty")
    }
}

/// Returns the first element of a list
pub fn head<T:Clone>(list: @List<T>) -> T {
    match *list {
      Cons(ref head, _) => (*head).clone(),
      // makes me sad
      _ => fail!("head invoked on empty list")
    }
}

/// Appends one list to another
pub fn append<T:Clone + 'static>(list: @List<T>, other: @List<T>) -> @List<T> {
    match *list {
      Nil => return other,
      Cons(ref head, tail) => {
        let rest = append(tail, other);
        return @Cons((*head).clone(), rest);
      }
    }
}

impl<T:'static + Clone> List<T> {
    /// Create a list from a vector
    pub fn from_vec(v: &[T]) -> List<T> {
        match v.len() {
            0 => Nil,
            _ => v.rev_iter().fold(Nil, |tail, value: &T| Cons(value.clone(), @tail))
        }
    }
}

/*
/// Push one element into the front of a list, returning a new list
/// THIS VERSION DOESN'T ACTUALLY WORK
fn push<T:Clone>(ll: &mut @list<T>, vv: T) {
    ll = &mut @cons(vv, *ll)
}
*/

#[cfg(test)]
mod tests {
    use list::{List, Nil, head, tail};
    use list;

    #[test]
    fn test_iter() {
        let list = List::from_vec([0, 1, 2]);
        let mut iter = list.iter();
        assert_eq!(&0, iter.next().unwrap());
        assert_eq!(&1, iter.next().unwrap());
        assert_eq!(&2, iter.next().unwrap());
        assert_eq!(None, iter.next());
    }

    #[test]
    fn test_is_empty() {
        let empty : list::List<int> = List::from_vec([]);
        let full1 = List::from_vec([1]);
        let full2 = List::from_vec(['r', 'u']);

        assert!(empty.is_empty());
        assert!(!full1.is_empty());
        assert!(!full2.is_empty());
    }

    #[test]
    fn test_from_vec() {
        let list = @List::from_vec([0, 1, 2]);

        assert_eq!(head(list), 0);

        let tail_l = tail(list);
        assert_eq!(head(tail_l), 1);

        let tail_tail_l = tail(tail_l);
        assert_eq!(head(tail_tail_l), 2);
    }

    #[test]
    fn test_from_vec_empty() {
        let empty : list::List<int> = List::from_vec([]);
        assert_eq!(empty, Nil::<int>);
    }

    #[test]
    fn test_fold() {
        fn add_(a: uint, b: &uint) -> uint { a + *b }
        fn subtract_(a: uint, b: &uint) -> uint { a - *b }

        let empty = Nil::<uint>;
        assert_eq!(empty.iter().fold(0u, add_), 0u);
        assert_eq!(empty.iter().fold(10u, subtract_), 10u);

        let list = List::from_vec([0u, 1u, 2u, 3u, 4u]);
        assert_eq!(list.iter().fold(0u, add_), 10u);
        assert_eq!(list.iter().fold(10u, subtract_), 0u);
    }

    #[test]
    fn test_find_success() {
        fn match_(i: & &int) -> bool { **i == 2 }

        let list = List::from_vec([0, 1, 2]);
        assert_eq!(list.iter().find(match_).unwrap(), &2);
    }

    #[test]
    fn test_find_fail() {
        fn match_(_i: & &int) -> bool { false }

        let empty = Nil::<int>;
        assert_eq!(empty.iter().find(match_), None);

        let list = List::from_vec([0, 1, 2]);
        assert_eq!(list.iter().find(match_), None);
    }

    #[test]
    fn test_any() {
        fn match_(i: &int) -> bool { *i == 2 }

        let empty = Nil::<int>;
        assert_eq!(empty.iter().any(match_), false);

        let list = List::from_vec([0, 1, 2]);
        assert_eq!(list.iter().any(match_), true);
    }

    #[test]
    fn test_has() {
        let list = @List::from_vec([5, 8, 6]);
        let empty = @list::Nil::<int>;
        assert!((list::has(list, 5)));
        assert!((!list::has(list, 7)));
        assert!((list::has(list, 8)));
        assert!((!list::has(empty, 5)));
    }

    #[test]
    fn test_len() {
        let empty = Nil::<int>;
        assert_eq!(empty.len(), 0u);

        let list = List::from_vec([0, 1, 2]);
        assert_eq!(list.len(), 3u);
    }

    #[test]
    fn test_append() {
        assert!(@List::from_vec([1,2,3,4])
            == list::append(@List::from_vec([1,2]), @List::from_vec([3,4])));
    }
}
<commit_msg>Replaced list::has() with list::contains()<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.

//! A standard, garbage-collected linked list.

use std::container::Container;

#[deriving(Clone, Eq)]
#[allow(missing_doc)]
pub enum List<T> {
    Cons(T, @List<T>),
    Nil,
}

pub struct Items<'a, T> {
    priv head: &'a List<T>,
    priv next: Option<&'a @List<T>>
}

impl<'a, T> Iterator<&'a T> for Items<'a, T> {
    fn next(&mut self) -> Option<&'a T> {
        match self.next {
            None => match *self.head {
                Nil => None,
                Cons(ref value, ref tail) => {
                    self.next = Some(tail);
                    Some(value)
                }
            },
            Some(next) => match **next {
                Nil => None,
                Cons(ref value, ref tail) => {
                    self.next = Some(tail);
                    Some(value)
                }
            }
        }
    }
}

impl<T> List<T> {
    /// Returns a forward iterator
    pub fn iter<'a>(&'a self) -> Items<'a, T> {
        Items {
            head: self,
            next: None
        }
    }
}

impl<T> Container for List<T> {
    /// Returns the length of a list
    fn len(&self) -> uint { self.iter().len() }

    /// Returns true if the list is empty
    fn is_empty(&self) -> bool { match *self { Nil => true, _ => false } }
}

impl<T:Eq> List<T> {
    /// Returns true if a list contains an element with the given value
    pub fn contains(&self, element: T) -> bool {
        self.iter().any(|list_element| *list_element == element)
    }
}

/// Returns all but the first element of a list
pub fn tail<T>(list: @List<T>) -> @List<T> {
    match *list {
        Cons(_, tail) => return tail,
        Nil => fail!("list empty")
    }
}

/// Returns the first element of a list
pub fn head<T:Clone>(list: @List<T>) -> T {
    match *list {
      Cons(ref head, _) => (*head).clone(),
      // makes me sad
      _ => fail!("head invoked on empty list")
    }
}

/// Appends one list to another
pub fn append<T:Clone + 'static>(list: @List<T>, other: @List<T>) -> @List<T> {
    match *list {
      Nil => return other,
      Cons(ref head, tail) => {
        let rest = append(tail, other);
        return @Cons((*head).clone(), rest);
      }
    }
}

impl<T:'static + Clone> List<T> {
    /// Create a list from a vector
    pub fn from_vec(v: &[T]) -> List<T> {
        match v.len() {
            0 => Nil,
            _ => v.rev_iter().fold(Nil, |tail, value: &T| Cons(value.clone(), @tail))
        }
    }
}

/*
/// Push one element into the front of a list, returning a new list
/// THIS VERSION DOESN'T ACTUALLY WORK
fn push<T:Clone>(ll: &mut @list<T>, vv: T) {
    ll = &mut @cons(vv, *ll)
}
*/

#[cfg(test)]
mod tests {
    use list::{List, Nil, head, tail};
    use list;

    #[test]
    fn test_iter() {
        let list = List::from_vec([0, 1, 2]);
        let mut iter = list.iter();
        assert_eq!(&0, iter.next().unwrap());
        assert_eq!(&1, iter.next().unwrap());
        assert_eq!(&2, iter.next().unwrap());
        assert_eq!(None, iter.next());
    }

    #[test]
    fn test_is_empty() {
        let empty : list::List<int> = List::from_vec([]);
        let full1 = List::from_vec([1]);
        let full2 = List::from_vec(['r', 'u']);

        assert!(empty.is_empty());
        assert!(!full1.is_empty());
        assert!(!full2.is_empty());
    }

    #[test]
    fn test_from_vec() {
        let list = @List::from_vec([0, 1, 2]);

        assert_eq!(head(list), 0);

        let tail_l = tail(list);
        assert_eq!(head(tail_l), 1);

        let tail_tail_l = tail(tail_l);
        assert_eq!(head(tail_tail_l), 2);
    }

    #[test]
    fn test_from_vec_empty() {
        let empty : list::List<int> = List::from_vec([]);
        assert_eq!(empty, Nil::<int>);
    }

    #[test]
    fn test_fold() {
        fn add_(a: uint, b: &uint) -> uint { a + *b }
        fn subtract_(a: uint, b: &uint) -> uint { a - *b }

        let empty = Nil::<uint>;
        assert_eq!(empty.iter().fold(0u, add_), 0u);
        assert_eq!(empty.iter().fold(10u, subtract_), 10u);

        let list = List::from_vec([0u, 1u, 2u, 3u, 4u]);
        assert_eq!(list.iter().fold(0u, add_), 10u);
        assert_eq!(list.iter().fold(10u, subtract_), 0u);
    }

    #[test]
    fn test_find_success() {
        fn match_(i: & &int) -> bool { **i == 2 }

        let list = List::from_vec([0, 1, 2]);
        assert_eq!(list.iter().find(match_).unwrap(), &2);
    }

    #[test]
    fn test_find_fail() {
        fn match_(_i: & &int) -> bool { false }

        let empty = Nil::<int>;
        assert_eq!(empty.iter().find(match_), None);

        let list = List::from_vec([0, 1, 2]);
        assert_eq!(list.iter().find(match_), None);
    }

    #[test]
    fn test_any() {
        fn match_(i: &int) -> bool { *i == 2 }

        let empty = Nil::<int>;
        assert_eq!(empty.iter().any(match_), false);

        let list = List::from_vec([0, 1, 2]);
        assert_eq!(list.iter().any(match_), true);
    }

    #[test]
    fn test_contains() {
        let empty = Nil::<int>;
        assert!((!empty.contains(5)));

        let list = List::from_vec([5, 8, 6]);
        assert!((list.contains(5)));
        assert!((!list.contains(7)));
        assert!((list.contains(8)));
    }

    #[test]
    fn test_len() {
        let empty = Nil::<int>;
        assert_eq!(empty.len(), 0u);

        let list = List::from_vec([0, 1, 2]);
        assert_eq!(list.len(), 3u);
    }

    #[test]
    fn test_append() {
        assert!(@List::from_vec([1,2,3,4])
            == list::append(@List::from_vec([1,2]), @List::from_vec([3,4])));
    }
}
<|endoftext|>


<commit_before>//! Instruction Set Architectures.
//!
//! The `isa` module provides a `TargetIsa` trait which provides the behavior specialization needed
//! by the ISA-independent code generator.
//!
//! The sub-modules of this module provide definitions for the instruction sets that Cretonne
//! can target. Each sub-module has it's own implementation of `TargetIsa`.

pub mod riscv;

use ir::dfg::DataFlowGraph;
use ir::entities::Inst;

pub trait TargetIsa {
    /// Encode an instruction after determining it is legal.
    ///
    /// If `inst` can legally be encoded in this ISA, produce the corresponding `Encoding` object.
    /// Otherwise, return `None`.
    ///
    /// This is also the main entry point for determining if an instruction is legal.
    fn encode(&self, dfg: &DataFlowGraph, inst: &Inst) -> Option<Encoding>;
}

/// Bits needed to encode an instruction as binary machine code.
///
/// The encoding consists of two parts, both specific to the target ISA: An encoding *recipe*, and
/// encoding *bits*. The recipe determines the native instruction format and the mapping of
/// operands to encoded bits. The encoding bits provide additional information to the recipe,
/// typically parts of the opcode.
pub struct Encoding(u32);

impl Encoding {
    /// Create a new `Encoding` containing `(recipe, bits)`. The `num_bits` parameter is the
    /// ISA-dependent size of `bits`.
    pub fn new(recipe: u32, bits: u32, num_bits: u8) -> Encoding {
        Encoding((recipe << num_bits) | bits)
    }

    /// Split the encoding into two parts: `(recipe, bits)`. Only the target ISA knows how many
    /// bits are in each part.
    pub fn split(&self, num_bits: u8) -> (u32, u32) {
        (self.0 >> num_bits, self.0 & ((1 << num_bits) - 1))
    }
}
<commit_msg>Document ISA builder.<commit_after>//! Instruction Set Architectures.
//!
//! The `isa` module provides a `TargetIsa` trait which provides the behavior specialization needed
//! by the ISA-independent code generator. The sub-modules of this module provide definitions for
//! the instruction sets that Cretonne can target. Each sub-module has it's own implementation of
//! `TargetIsa`.
//!
//! # Constructing a `TargetIsa` instance
//!
//! The target ISA is build from the following information:
//!
//! - The name of the target ISA as a string. Cretonne is a cross-compiler, so the ISA to target
//!   can be selected dynamically. Individual ISAs can be left out when Cretonne is compiled, so a
//!   string is used to identify the proper sub-module.
//! - Values for settings that apply to all ISAs. This is represented by a `settings::Flags`
//!   instance.
//! - Values for ISA-specific settings.
//!
//! The `isa::lookup()` function is the main entry point which returns an `isa::Builder`
//! appropriate for the requested ISA:
//!
//! ```ignore
//! let isa_builder = isa::lookup("riscv").unwrap();
//! adjust_isa_settings(&mut isa_builder.settings);
//! let isa = builder.finish(shared_settings());
//! ```
//!

pub mod riscv;

use ir::dfg::DataFlowGraph;
use ir::entities::Inst;

pub trait TargetIsa {
    /// Encode an instruction after determining it is legal.
    ///
    /// If `inst` can legally be encoded in this ISA, produce the corresponding `Encoding` object.
    /// Otherwise, return `None`.
    ///
    /// This is also the main entry point for determining if an instruction is legal.
    fn encode(&self, dfg: &DataFlowGraph, inst: &Inst) -> Option<Encoding>;
}

/// Bits needed to encode an instruction as binary machine code.
///
/// The encoding consists of two parts, both specific to the target ISA: An encoding *recipe*, and
/// encoding *bits*. The recipe determines the native instruction format and the mapping of
/// operands to encoded bits. The encoding bits provide additional information to the recipe,
/// typically parts of the opcode.
pub struct Encoding(u32);

impl Encoding {
    /// Create a new `Encoding` containing `(recipe, bits)`. The `num_bits` parameter is the
    /// ISA-dependent size of `bits`.
    pub fn new(recipe: u32, bits: u32, num_bits: u8) -> Encoding {
        Encoding((recipe << num_bits) | bits)
    }

    /// Split the encoding into two parts: `(recipe, bits)`. Only the target ISA knows how many
    /// bits are in each part.
    pub fn split(&self, num_bits: u8) -> (u32, u32) {
        (self.0 >> num_bits, self.0 & ((1 << num_bits) - 1))
    }
}
<|endoftext|>


<commit_before>use super::*;
use super::super::lexer;
use codemap::CodeMap;
use codemap::Spanned;

fn get_tokens(source: &str) -> Vec<Spanned<Token>> {
  let mut map = CodeMap::new();
  let file = map.add_file(String::from("_test"), String::from(source));
  lexer::lex(&file)
}

fn test_parse(source: &str, func: &Fn(&mut ParseIter) -> Parse, expect: Parse) {
  let tokens = get_tokens(source);
  let mut it = tokens.iter().peekable();

  assert_eq!(
    func(&mut it),
    expect
  );

  assert_eq!(
    parse_un_expr(&mut it),
    Err(UnexpectedToken(lexer::Token::End))
  );
  it.next();

  assert_eq!(
    parse_un_expr(&mut it),
    Err(UnexpectedToken(lexer::Token::EOF))
  );
  it.next();

  assert_eq!(parse_un_expr(&mut it), Err(UnexpectedEOF));
}

#[test]
fn test_quark() {
  let source = "null true false 1.3 0.3 2 3 name table";
  let tokens = get_tokens(source);
  let mut it = tokens.iter().peekable();

  assert_eq!(parse_quark(&mut it), Ok(Node::Null));
  assert_eq!(parse_quark(&mut it), Ok(Node::Bool(true)));
  assert_eq!(parse_quark(&mut it), Ok(Node::Bool(false)));
  assert_eq!(parse_quark(&mut it), Ok(Node::Float(1.3)));
  assert_eq!(parse_quark(&mut it), Ok(Node::Float(0.3)));
  assert_eq!(parse_quark(&mut it), Ok(Node::Int(2)));
  assert_eq!(parse_quark(&mut it), Ok(Node::Int(3)));
  assert_eq!(parse_quark(&mut it), Ok(Node::Name(String::from("name"))));
  assert_eq!(parse_quark(&mut it), Ok(Node::Table));
  assert_eq!(
    parse_quark(&mut it),
    Err(UnexpectedToken(lexer::Token::End))
  );
  it.next();
  assert_eq!(
    parse_quark(&mut it),
    Err(UnexpectedToken(lexer::Token::EOF))
  );
  it.next();
  assert_eq!(parse_quark(&mut it), Err(UnexpectedEOF));
}

#[test]
fn test_atom() {
  let source = "null (null)";
  let tokens = get_tokens(source);
  let mut it = tokens.iter().peekable();

  assert_eq!(parse_atom(&mut it), Ok(Node::Null));
  assert_eq!(parse_atom(&mut it), Ok(Node::Null));
  assert_eq!(parse_atom(&mut it), Err(UnexpectedToken(lexer::Token::End)));
  it.next();
  assert_eq!(parse_atom(&mut it), Err(UnexpectedToken(lexer::Token::EOF)));
  it.next();
  assert_eq!(parse_atom(&mut it), Err(UnexpectedEOF));
}

#[test]
fn test_simple() {
  let source = "foo foo.bar foo[bar] foo() foo:bar() foo.bar() foo.bar[baz]:qux()";
  let tokens = get_tokens(source);
  let mut it = tokens.iter().peekable();

  assert_eq!(parse_simple(&mut it), Ok(Node::Name(String::from("foo"))));
  assert_eq!(
    parse_simple(&mut it),
    Ok(Node::Index {
      lhs: Box::new(Node::Name(String::from("foo"))),
      rhs: Box::new(Node::Str(String::from("bar"))),
    })
  );
  assert_eq!(
    parse_simple(&mut it),
    Ok(Node::Index {
      lhs: Box::new(Node::Name(String::from("foo"))),
      rhs: Box::new(Node::Name(String::from("bar"))),
    })
  );
  assert_eq!(
    parse_simple(&mut it),
    Ok(Node::Func {
      func: Box::new(Node::Name(String::from("foo"))),
      args: Vec::new(),
    })
  );
  assert_eq!(
    parse_simple(&mut it),
    Ok(Node::Method {
      owner: Box::new(Node::Name(String::from("foo"))),
      method: Box::new(Node::Str(String::from("bar"))),
      args: Vec::new(),
    })
  );
  assert_eq!(
    parse_simple(&mut it),
    Ok(Node::Func {
      func: Box::new(Node::Index {
        lhs: Box::new(Node::Name(String::from("foo"))),
        rhs: Box::new(Node::Str(String::from("bar"))),
      }),
      args: Vec::new(),
    })
  );
  assert_eq!(
    parse_simple(&mut it),
    Ok(Node::Method {
      owner: Box::new(Node::Index {
        lhs: Box::new(Node::Index {
          lhs: Box::new(Node::Name(String::from("foo"))),
          rhs: Box::new(Node::Str(String::from("bar"))),
        }),
        rhs: Box::new(Node::Name(String::from("baz"))),
      }),
      method: Box::new(Node::Str(String::from("qux"))),
      args: Vec::new(),
    })
  );
  assert_eq!(
    parse_simple(&mut it),
    Err(UnexpectedToken(lexer::Token::End))
  );
  it.next();
  assert_eq!(
    parse_simple(&mut it),
    Err(UnexpectedToken(lexer::Token::EOF))
  );
  it.next();
  assert_eq!(parse_simple(&mut it), Err(UnexpectedEOF));
}

#[test]
fn test_fn_args() {
  let source = "()";
  let tokens = get_tokens(source);
  let mut it = tokens.iter().peekable();

  assert_eq!(parse_fn_args(&mut it), Ok(Vec::new()));
  assert_eq!(
    parse_fn_args(&mut it),
    Err(UnexpectedToken(lexer::Token::End))
  );
  it.next();
  assert_eq!(
    parse_fn_args(&mut it),
    Err(UnexpectedToken(lexer::Token::EOF))
  );
  it.next();
  assert_eq!(parse_fn_args(&mut it), Err(UnexpectedEOF));
}

#[test]
fn test_un_expr() {
  let source = "5 foo() -5 -foo.bar !-5";
  let tokens = get_tokens(source);
  let mut it = tokens.iter().peekable();

  assert_eq!(parse_un_expr(&mut it), Ok(Node::Int(5)));
  assert_eq!(
    parse_un_expr(&mut it),
    Ok(Node::Func {
      func: Box::new(Node::Name(String::from("foo"))),
      args: Vec::new(),
    })
  );
  assert_eq!(
    parse_un_expr(&mut it),
    Ok(Node::UnExpr {
      op: lexer::Token::Sub,
      val: Box::new(Node::Int(5)),
    })
  );
  assert_eq!(
    parse_un_expr(&mut it),
    Ok(Node::UnExpr {
      op: lexer::Token::Sub,
      val: Box::new(Node::Index {
        lhs: Box::new(Node::Name(String::from("foo"))),
        rhs: Box::new(Node::Str(String::from("bar"))),
      }),
    })
  );
  assert_eq!(
    parse_un_expr(&mut it),
    Ok(Node::UnExpr {
      op: lexer::Token::Not,
      val: Box::new(Node::UnExpr {
        op: lexer::Token::Sub,
        val: Box::new(Node::Int(5)),
      }),
    })
  );
  assert_eq!(
    parse_un_expr(&mut it),
    Err(UnexpectedToken(lexer::Token::End))
  );
  it.next();
  assert_eq!(
    parse_un_expr(&mut it),
    Err(UnexpectedToken(lexer::Token::EOF))
  );
  it.next();
  assert_eq!(parse_un_expr(&mut it), Err(UnexpectedEOF));
}

#[test]
fn test_bin_expr() {
  test_parse(
    "1 + 2",
    &parse_bin_expr,
    Ok(Node::BinExpr {
      lhs: Box::new(Node::Int(1)),
      op: lexer::Token::Add,
      rhs: Box::new(Node::Int(2)),
    })
  );

  test_parse(
    "(1 + 2)",
    &parse_bin_expr,
    Ok(Node::BinExpr {
      lhs: Box::new(Node::Int(1)),
      op: lexer::Token::Add,
      rhs: Box::new(Node::Int(2)),
    })
  );

  test_parse(
    "1 + 2 * 3",
    &parse_bin_expr,
    Ok(Node::BinExpr {
      lhs: Box::new(Node::Int(1)),
      op: lexer::Token::Add,
      rhs: Box::new(Node::BinExpr {
        lhs: Box::new(Node::Int(2)),
        op: lexer::Token::Mul,
        rhs: Box::new(Node::Int(3)),
      }),
    })
  );
}

#[test]
fn test_fn_expr() {
  let source = "|| 5 |x| 5 |x,| 5 |x, y| 5";
  let tokens = get_tokens(source);
  let mut it = tokens.iter().peekable();

  assert_eq!(
    parse_il_expr(&mut it),
    Ok(Node::Lambda {
      params: Vec::new(),
      expr: Box::new(Node::Int(5)),
    })
  );
  assert_eq!(
    parse_il_expr(&mut it),
    Ok(Node::Lambda {
      params: vec![String::from("x")],
      expr: Box::new(Node::Int(5)),
    })
  );
  assert_eq!(
    parse_il_expr(&mut it),
    Ok(Node::Lambda {
      params: vec![String::from("x")],
      expr: Box::new(Node::Int(5)),
    })
  );
  assert_eq!(
    parse_il_expr(&mut it),
    Ok(Node::Lambda {
      params: vec![String::from("x"), String::from("y")],
      expr: Box::new(Node::Int(5)),
    })
  );
  assert_eq!(
    parse_un_expr(&mut it),
    Err(UnexpectedToken(lexer::Token::End))
  );
  it.next();
  assert_eq!(
    parse_un_expr(&mut it),
    Err(UnexpectedToken(lexer::Token::EOF))
  );
  it.next();
  assert_eq!(parse_un_expr(&mut it), Err(UnexpectedEOF));
}
<commit_msg>tests.parser: Retrofit test_parse into old tests<commit_after>use super::*;
use super::super::lexer;
use codemap::CodeMap;
use codemap::Spanned;

fn get_tokens(source: &str) -> Vec<Spanned<Token>> {
  let mut map = CodeMap::new();
  let file = map.add_file(String::from("_test"), String::from(source));
  lexer::lex(&file)
}

fn test_parse(source: &str, func: &Fn(&mut ParseIter) -> Parse, expect: Parse) {
  let tokens = get_tokens(source);
  let mut it = tokens.iter().peekable();

  assert_eq!(
    func(&mut it),
    expect
  );

  assert_eq!(
    parse_un_expr(&mut it),
    Err(UnexpectedToken(lexer::Token::End))
  );
  it.next();

  assert_eq!(
    parse_un_expr(&mut it),
    Err(UnexpectedToken(lexer::Token::EOF))
  );
  it.next();

  assert_eq!(parse_un_expr(&mut it), Err(UnexpectedEOF));
}

#[test]
fn test_quark() {
  test_parse("null", &parse_quark, Ok(Node::Null));
  test_parse("true", &parse_quark, Ok(Node::Bool(true)));
  test_parse("false", &parse_quark, Ok(Node::Bool(false)));
  test_parse("1.3", &parse_quark, Ok(Node::Float(1.3)));
  test_parse("0.3", &parse_quark, Ok(Node::Float(0.3)));
  test_parse("2", &parse_quark, Ok(Node::Int(2)));
  test_parse("3", &parse_quark, Ok(Node::Int(3)));
  test_parse("name", &parse_quark, Ok(Node::Name(String::from("name"))));
  test_parse("table", &parse_quark, Ok(Node::Table));
}

#[test]
fn test_atom() {
  test_parse(
    "null",
    &parse_atom,
    Ok(Node::Null)
    );

  test_parse(
    "(null)",
    &parse_atom,
    Ok(Node::Null)
    );
}

#[test]
fn test_simple() {
  test_parse(
    "foo",
    &parse_simple,
    Ok(Node::Name(String::from("foo")))
    );
  test_parse(
    "foo.bar",
    &parse_simple,
    Ok(Node::Index {
      lhs: Box::new(Node::Name(String::from("foo"))),
      rhs: Box::new(Node::Str(String::from("bar"))),
    })
  );
  test_parse(
    "foo[bar]",
    &parse_simple,
    Ok(Node::Index {
      lhs: Box::new(Node::Name(String::from("foo"))),
      rhs: Box::new(Node::Name(String::from("bar"))),
    })
  );
  test_parse(
    "foo()",
    &parse_simple,
    Ok(Node::Func {
      func: Box::new(Node::Name(String::from("foo"))),
      args: Vec::new(),
    })
  );
  test_parse(
    "foo:bar()",
    &parse_simple,
    Ok(Node::Method {
      owner: Box::new(Node::Name(String::from("foo"))),
      method: Box::new(Node::Str(String::from("bar"))),
      args: Vec::new(),
    })
  );
  test_parse(
    "foo.bar()",
    &parse_simple,
    Ok(Node::Func {
      func: Box::new(Node::Index {
        lhs: Box::new(Node::Name(String::from("foo"))),
        rhs: Box::new(Node::Str(String::from("bar"))),
      }),
      args: Vec::new(),
    })
  );
  test_parse(
    "foo.bar[baz]:qux()",
    &parse_simple,
    Ok(Node::Method {
      owner: Box::new(Node::Index {
        lhs: Box::new(Node::Index {
          lhs: Box::new(Node::Name(String::from("foo"))),
          rhs: Box::new(Node::Str(String::from("bar"))),
        }),
        rhs: Box::new(Node::Name(String::from("baz"))),
      }),
      method: Box::new(Node::Str(String::from("qux"))),
      args: Vec::new(),
    })
  );
}

#[test]
fn test_fn_args() {
  let source = "()";
  let tokens = get_tokens(source);
  let mut it = tokens.iter().peekable();

  assert_eq!(parse_fn_args(&mut it), Ok(Vec::new()));
  assert_eq!(
    parse_fn_args(&mut it),
    Err(UnexpectedToken(lexer::Token::End))
  );
  it.next();
  assert_eq!(
    parse_fn_args(&mut it),
    Err(UnexpectedToken(lexer::Token::EOF))
  );
  it.next();
  assert_eq!(parse_fn_args(&mut it), Err(UnexpectedEOF));
}

#[test]
fn test_un_expr() {
  test_parse(
    "5",
    &parse_un_expr,
    Ok(Node::Int(5))
  );

  test_parse(
    "foo()",
    &parse_un_expr,
    Ok(Node::Func {
      func: Box::new(Node::Name(String::from("foo"))),
      args: Vec::new(),
    })
  );

  test_parse(
    "-5",
    &parse_un_expr,
    Ok(Node::UnExpr {
      op: lexer::Token::Sub,
      val: Box::new(Node::Int(5)),
    })
  );

  test_parse(
    "-foo.bar",
    &parse_un_expr,
    Ok(Node::UnExpr {
      op: lexer::Token::Sub,
      val: Box::new(Node::Index {
        lhs: Box::new(Node::Name(String::from("foo"))),
        rhs: Box::new(Node::Str(String::from("bar"))),
      }),
    })
  );

  test_parse(
    "!-5",
    &parse_un_expr,
    Ok(Node::UnExpr {
      op: lexer::Token::Not,
      val: Box::new(Node::UnExpr {
        op: lexer::Token::Sub,
        val: Box::new(Node::Int(5)),
      }),
    })
  );
}

#[test]
fn test_bin_expr() {
  test_parse(
    "1 + 2",
    &parse_bin_expr,
    Ok(Node::BinExpr {
      lhs: Box::new(Node::Int(1)),
      op: lexer::Token::Add,
      rhs: Box::new(Node::Int(2)),
    })
  );

  test_parse(
    "(1 + 2)",
    &parse_bin_expr,
    Ok(Node::BinExpr {
      lhs: Box::new(Node::Int(1)),
      op: lexer::Token::Add,
      rhs: Box::new(Node::Int(2)),
    })
  );

  test_parse(
    "1 + 2 * 3",
    &parse_bin_expr,
    Ok(Node::BinExpr {
      lhs: Box::new(Node::Int(1)),
      op: lexer::Token::Add,
      rhs: Box::new(Node::BinExpr {
        lhs: Box::new(Node::Int(2)),
        op: lexer::Token::Mul,
        rhs: Box::new(Node::Int(3)),
      }),
    })
  );
}

#[test]
fn test_fn_expr() {
  test_parse(
    "|| 5",
    &parse_il_expr,
    Ok(Node::Lambda {
      params: Vec::new(),
      expr: Box::new(Node::Int(5)),
    })
  );

  test_parse(
    "|x| 5",
    &parse_il_expr,
    Ok(Node::Lambda {
      params: vec![String::from("x")],
      expr: Box::new(Node::Int(5)),
    })
  );

  test_parse(
    "|x,| 5",
    &parse_il_expr,
    Ok(Node::Lambda {
      params: vec![String::from("x")],
      expr: Box::new(Node::Int(5)),
    })
  );

  test_parse(
    "|x,y| 5",
    &parse_il_expr,
    Ok(Node::Lambda {
      params: vec![String::from("x"), String::from("y")],
      expr: Box::new(Node::Int(5)),
    })
  );
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use super::super::{strfmt, Fmt};

#[test]
fn test_values() {
    let mut vars: HashMap<String, String> = HashMap::new();
    let too_long = "toooloooong".to_string();
    vars.insert("x".to_string(), "X".to_string());
    vars.insert("long".to_string(), too_long.clone());  // len=10
    vars.insert("hi".to_string(), "hi".to_string());

    // format, expected, error
    let values = vec![
        // simple positioning
        ("{x}", "X", false),
        ("{x:}", "X", false),
        ("{x:3}", "  X", false),
        ("{x:>3}", "  X", false),
        ("{x:<3}", "X  ", false),
        ("{x:^3}", " X ", false),
        ("{x:^4}", " X  ", false),

        // extra text
        (" {x}yz", " Xyz", false),
        (" hi {x:^4}-you rock", " hi  X  -you rock", false),

        // fill confusion
        ("{x:10}", "         X", false),
        ("{long:.3}", "too", false),
        ("{long:<5.3}", "too  ", false),
        ("{long:5.3}", "  too", false),
        ("{long:5.7}", "toooloo", false),
        ("{long:<5.7}", "toooloo", false),
        ("{long:^5.7}", "toooloo", false),
        ("{long:<}", &too_long, false),
        ("{long:<<}", &too_long, false),
        ("{long:<<5}", &too_long, false),

        // fun
        ("{x:<>}", "X", false),
        ("{x:<>3}", "<<X", false),
        ("{{}}", "{}", false),
        ("{{{x}}}", "{X}", false),
        ("{{{x}{{{{{{", "{X{{{", false),
        ("{x}}}}}", "X}}", false),

        // invalid
        ("{}", "", true),
        ("{:3}", "", true),
        ("{x:*}", "", true),
        ("{x::}", "", true),
        ("{x:<<<}", "", true),
        ("{xxx:  <88.3}", "", true),
        ("}", "", true),
        ("{{}}}", "", true),
        ("hi } there", "", true),
        ("hi }", "", true),
        ("w { ho", "", true),

        // escape
        ("{{}}", "{}", false),
        ("{{long}}", "{long}", false),
        ("{{{x}}}", "{X}", false),

        // escape errors
    ];

    for (fmtstr, expected, expect_err) in values {
        let result = strfmt(fmtstr, &vars);
        let failure = expect_err != result.is_err();

        if failure {
            println!("FAIL:");
            println!("     input: {:?}", (fmtstr, expected, expect_err));
            println!("    output: {:?}", result);
            if expect_err {
                println!("    expected: error");
            } else {
                println!("    expected: {:?}", expected);
            }
            assert!(false);
        }
    }
}

// #[bench]
// fn bench_strfmt(b: &mut Bencher) {
//     let mut vars: HashMap<String, String> = HashMap::new();
//     let too_long = "toooloooong".to_string();
//     vars.insert("x".to_string(), "X".to_string());
//     let fmtstr = "short: {x:*^10.3} long: {long:%<14.9}";
//     b.iter(|| strfmt(fmtstr, &vars));
// }

<commit_msg>unused import<commit_after>use std::collections::HashMap;
use super::super::strfmt;

#[test]
fn test_values() {
    let mut vars: HashMap<String, String> = HashMap::new();
    let too_long = "toooloooong".to_string();
    vars.insert("x".to_string(), "X".to_string());
    vars.insert("long".to_string(), too_long.clone());  // len=10
    vars.insert("hi".to_string(), "hi".to_string());

    // format, expected, error
    let values = vec![
        // simple positioning
        ("{x}", "X", false),
        ("{x:}", "X", false),
        ("{x:3}", "  X", false),
        ("{x:>3}", "  X", false),
        ("{x:<3}", "X  ", false),
        ("{x:^3}", " X ", false),
        ("{x:^4}", " X  ", false),

        // extra text
        (" {x}yz", " Xyz", false),
        (" hi {x:^4}-you rock", " hi  X  -you rock", false),

        // fill confusion
        ("{x:10}", "         X", false),
        ("{long:.3}", "too", false),
        ("{long:<5.3}", "too  ", false),
        ("{long:5.3}", "  too", false),
        ("{long:5.7}", "toooloo", false),
        ("{long:<5.7}", "toooloo", false),
        ("{long:^5.7}", "toooloo", false),
        ("{long:<}", &too_long, false),
        ("{long:<<}", &too_long, false),
        ("{long:<<5}", &too_long, false),

        // fun
        ("{x:<>}", "X", false),
        ("{x:<>3}", "<<X", false),
        ("{{}}", "{}", false),
        ("{{{x}}}", "{X}", false),
        ("{{{x}{{{{{{", "{X{{{", false),
        ("{x}}}}}", "X}}", false),

        // invalid
        ("{}", "", true),
        ("{:3}", "", true),
        ("{x:*}", "", true),
        ("{x::}", "", true),
        ("{x:<<<}", "", true),
        ("{xxx:  <88.3}", "", true),
        ("}", "", true),
        ("{{}}}", "", true),
        ("hi } there", "", true),
        ("hi }", "", true),
        ("w { ho", "", true),

        // escape
        ("{{}}", "{}", false),
        ("{{long}}", "{long}", false),
        ("{{{x}}}", "{X}", false),

        // escape errors
    ];

    for (fmtstr, expected, expect_err) in values {
        let result = strfmt(fmtstr, &vars);
        let failure = expect_err != result.is_err();

        if failure {
            println!("FAIL:");
            println!("     input: {:?}", (fmtstr, expected, expect_err));
            println!("    output: {:?}", result);
            if expect_err {
                println!("    expected: error");
            } else {
                println!("    expected: {:?}", expected);
            }
            assert!(false);
        }
    }
}

// #[bench]
// fn bench_strfmt(b: &mut Bencher) {
//     let mut vars: HashMap<String, String> = HashMap::new();
//     let too_long = "toooloooong".to_string();
//     vars.insert("x".to_string(), "X".to_string());
//     let fmtstr = "short: {x:*^10.3} long: {long:%<14.9}";
//     b.iter(|| strfmt(fmtstr, &vars));
// }

<|endoftext|>


<commit_before>// Copyright 2014 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.

/*!

typeck.rs, an introduction

The type checker is responsible for:

1. Determining the type of each expression
2. Resolving methods and traits
3. Guaranteeing that most type rules are met ("most?", you say, "why most?"
   Well, dear reader, read on)

The main entry point is `check_crate()`.  Type checking operates in
several major phases:

1. The collect phase first passes over all items and determines their
   type, without examining their "innards".

2. Variance inference then runs to compute the variance of each parameter

3. Coherence checks for overlapping or orphaned impls

4. Finally, the check phase then checks function bodies and so forth.
   Within the check phase, we check each function body one at a time
   (bodies of function expressions are checked as part of the
   containing function).  Inference is used to supply types wherever
   they are unknown. The actual checking of a function itself has
   several phases (check, regionck, writeback), as discussed in the
   documentation for the `check` module.

The type checker is defined into various submodules which are documented
independently:

- astconv: converts the AST representation of types
  into the `ty` representation

- collect: computes the types of each top-level item and enters them into
  the `cx.tcache` table for later use

- coherence: enforces coherence rules, builds some tables

- variance: variance inference

- check: walks over function bodies and type checks them, inferring types for
  local variables, type parameters, etc as necessary.

- infer: finds the types to use for each type variable such that
  all subtyping and assignment constraints are met.  In essence, the check
  module specifies the constraints, and the infer module solves them.

# Note

This API is completely unstable and subject to change.

*/
// Do not remove on snapshot creation. Needed for bootstrap. (Issue #22364)
#![cfg_attr(stage0, feature(custom_attribute))]
#![crate_name = "rustc_typeck"]
#![unstable(feature = "rustc_private")]
#![staged_api]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
      html_favicon_url = "http://www.rust-lang.org/favicon.ico",
      html_root_url = "http://doc.rust-lang.org/nightly/")]

#![allow(non_camel_case_types)]

#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(collections)]
#![feature(core)]
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
#![feature(staged_api)]

#[macro_use] extern crate log;
#[macro_use] extern crate syntax;

extern crate arena;
extern crate fmt_macros;
extern crate rustc;

pub use rustc::lint;
pub use rustc::metadata;
pub use rustc::middle;
pub use rustc::session;
pub use rustc::util;

use middle::def;
use middle::infer;
use middle::subst;
use middle::ty::{self, Ty};
use session::config;
use util::common::time;
use util::ppaux::Repr;
use util::ppaux;

use syntax::codemap::Span;
use syntax::print::pprust::*;
use syntax::{ast, ast_map, abi};
use syntax::ast_util::local_def;

use std::cell::RefCell;

// NB: This module needs to be declared first so diagnostics are
// registered before they are used.
pub mod diagnostics;

mod check;
mod rscope;
mod astconv;
mod collect;
mod constrained_type_params;
mod coherence;
mod variance;

pub struct TypeAndSubsts<'tcx> {
    pub substs: subst::Substs<'tcx>,
    pub ty: Ty<'tcx>,
}

pub struct CrateCtxt<'a, 'tcx: 'a> {
    // A mapping from method call sites to traits that have that method.
    trait_map: ty::TraitMap,
    /// A vector of every trait accessible in the whole crate
    /// (i.e. including those from subcrates). This is used only for
    /// error reporting, and so is lazily initialised and generally
    /// shouldn't taint the common path (hence the RefCell).
    all_traits: RefCell<Option<check::method::AllTraitsVec>>,
    tcx: &'a ty::ctxt<'tcx>,
}

// Functions that write types into the node type table
fn write_ty_to_tcx<'tcx>(tcx: &ty::ctxt<'tcx>, node_id: ast::NodeId, ty: Ty<'tcx>) {
    debug!("write_ty_to_tcx({}, {})", node_id, ppaux::ty_to_string(tcx, ty));
    assert!(!ty::type_needs_infer(ty));
    tcx.node_type_insert(node_id, ty);
}

fn write_substs_to_tcx<'tcx>(tcx: &ty::ctxt<'tcx>,
                                 node_id: ast::NodeId,
                                 item_substs: ty::ItemSubsts<'tcx>) {
    if !item_substs.is_noop() {
        debug!("write_substs_to_tcx({}, {})",
               node_id,
               item_substs.repr(tcx));

        assert!(item_substs.substs.types.all(|t| !ty::type_needs_infer(*t)));

        tcx.item_substs.borrow_mut().insert(node_id, item_substs);
    }
}

fn lookup_full_def(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) -> def::Def {
    match tcx.def_map.borrow().get(&id) {
        Some(x) => x.full_def(),
        None => {
            span_fatal!(tcx.sess, sp, E0242, "internal error looking up a definition")
        }
    }
}

fn require_same_types<'a, 'tcx, M>(tcx: &ty::ctxt<'tcx>,
                                   maybe_infcx: Option<&infer::InferCtxt<'a, 'tcx>>,
                                   t1_is_expected: bool,
                                   span: Span,
                                   t1: Ty<'tcx>,
                                   t2: Ty<'tcx>,
                                   msg: M)
                                   -> bool where
    M: FnOnce() -> String,
{
    let result = match maybe_infcx {
        None => {
            let infcx = infer::new_infer_ctxt(tcx);
            infer::mk_eqty(&infcx, t1_is_expected, infer::Misc(span), t1, t2)
        }
        Some(infcx) => {
            infer::mk_eqty(infcx, t1_is_expected, infer::Misc(span), t1, t2)
        }
    };

    match result {
        Ok(_) => true,
        Err(ref terr) => {
            span_err!(tcx.sess, span, E0211,
                              "{}: {}",
                                      msg(),
                                      ty::type_err_to_str(tcx,
                                                          terr));
            ty::note_and_explain_type_err(tcx, terr, span);
            false
        }
    }
}

fn check_main_fn_ty(ccx: &CrateCtxt,
                    main_id: ast::NodeId,
                    main_span: Span) {
    let tcx = ccx.tcx;
    let main_t = ty::node_id_to_type(tcx, main_id);
    match main_t.sty {
        ty::ty_bare_fn(..) => {
            match tcx.map.find(main_id) {
                Some(ast_map::NodeItem(it)) => {
                    match it.node {
                        ast::ItemFn(_, _, _, ref ps, _)
                        if ps.is_parameterized() => {
                            span_err!(ccx.tcx.sess, main_span, E0131,
                                      "main function is not allowed to have type parameters");
                            return;
                        }
                        _ => ()
                    }
                }
                _ => ()
            }
            let se_ty = ty::mk_bare_fn(tcx, Some(local_def(main_id)), tcx.mk_bare_fn(ty::BareFnTy {
                unsafety: ast::Unsafety::Normal,
                abi: abi::Rust,
                sig: ty::Binder(ty::FnSig {
                    inputs: Vec::new(),
                    output: ty::FnConverging(ty::mk_nil(tcx)),
                    variadic: false
                })
            }));

            require_same_types(tcx, None, false, main_span, main_t, se_ty,
                || {
                    format!("main function expects type: `{}`",
                            ppaux::ty_to_string(ccx.tcx, se_ty))
                });
        }
        _ => {
            tcx.sess.span_bug(main_span,
                              &format!("main has a non-function type: found \
                                       `{}`",
                                      ppaux::ty_to_string(tcx,
                                                       main_t)));
        }
    }
}

fn check_start_fn_ty(ccx: &CrateCtxt,
                     start_id: ast::NodeId,
                     start_span: Span) {
    let tcx = ccx.tcx;
    let start_t = ty::node_id_to_type(tcx, start_id);
    match start_t.sty {
        ty::ty_bare_fn(..) => {
            match tcx.map.find(start_id) {
                Some(ast_map::NodeItem(it)) => {
                    match it.node {
                        ast::ItemFn(_,_,_,ref ps,_)
                        if ps.is_parameterized() => {
                            span_err!(tcx.sess, start_span, E0132,
                                      "start function is not allowed to have type parameters");
                            return;
                        }
                        _ => ()
                    }
                }
                _ => ()
            }

            let se_ty = ty::mk_bare_fn(tcx, Some(local_def(start_id)), tcx.mk_bare_fn(ty::BareFnTy {
                unsafety: ast::Unsafety::Normal,
                abi: abi::Rust,
                sig: ty::Binder(ty::FnSig {
                    inputs: vec!(
                        tcx.types.isize,
                        ty::mk_imm_ptr(tcx, ty::mk_imm_ptr(tcx, tcx.types.u8))
                    ),
                    output: ty::FnConverging(tcx.types.isize),
                    variadic: false,
                }),
            }));

            require_same_types(tcx, None, false, start_span, start_t, se_ty,
                || {
                    format!("start function expects type: `{}`",
                            ppaux::ty_to_string(ccx.tcx, se_ty))
                });

        }
        _ => {
            tcx.sess.span_bug(start_span,
                              &format!("start has a non-function type: found \
                                       `{}`",
                                      ppaux::ty_to_string(tcx, start_t)));
        }
    }
}

fn check_for_entry_fn(ccx: &CrateCtxt) {
    let tcx = ccx.tcx;
    match *tcx.sess.entry_fn.borrow() {
        Some((id, sp)) => match tcx.sess.entry_type.get() {
            Some(config::EntryMain) => check_main_fn_ty(ccx, id, sp),
            Some(config::EntryStart) => check_start_fn_ty(ccx, id, sp),
            Some(config::EntryNone) => {}
            None => tcx.sess.bug("entry function without a type")
        },
        None => {}
    }
}

pub fn check_crate(tcx: &ty::ctxt, trait_map: ty::TraitMap) {
    let time_passes = tcx.sess.time_passes();
    let ccx = CrateCtxt {
        trait_map: trait_map,
        all_traits: RefCell::new(None),
        tcx: tcx
    };

    time(time_passes, "type collecting", (), |_|
         collect::collect_item_types(tcx));

    // this ensures that later parts of type checking can assume that items
    // have valid types and not error
    tcx.sess.abort_if_errors();

    time(time_passes, "variance inference", (), |_|
         variance::infer_variance(tcx));

    time(time_passes, "coherence checking", (), |_|
        coherence::check_coherence(&ccx));

    time(time_passes, "type checking", (), |_|
        check::check_item_types(&ccx));

    check_for_entry_fn(&ccx);
    tcx.sess.abort_if_errors();
}

#[cfg(stage0)]
__build_diagnostic_array! { DIAGNOSTICS }
#[cfg(not(stage0))]
__build_diagnostic_array! { librustc_typeck, DIAGNOSTICS }
<commit_msg>rustc_typeck: export modules and fields for sub-passes.<commit_after>// Copyright 2014 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.

/*!

typeck.rs, an introduction

The type checker is responsible for:

1. Determining the type of each expression
2. Resolving methods and traits
3. Guaranteeing that most type rules are met ("most?", you say, "why most?"
   Well, dear reader, read on)

The main entry point is `check_crate()`.  Type checking operates in
several major phases:

1. The collect phase first passes over all items and determines their
   type, without examining their "innards".

2. Variance inference then runs to compute the variance of each parameter

3. Coherence checks for overlapping or orphaned impls

4. Finally, the check phase then checks function bodies and so forth.
   Within the check phase, we check each function body one at a time
   (bodies of function expressions are checked as part of the
   containing function).  Inference is used to supply types wherever
   they are unknown. The actual checking of a function itself has
   several phases (check, regionck, writeback), as discussed in the
   documentation for the `check` module.

The type checker is defined into various submodules which are documented
independently:

- astconv: converts the AST representation of types
  into the `ty` representation

- collect: computes the types of each top-level item and enters them into
  the `cx.tcache` table for later use

- coherence: enforces coherence rules, builds some tables

- variance: variance inference

- check: walks over function bodies and type checks them, inferring types for
  local variables, type parameters, etc as necessary.

- infer: finds the types to use for each type variable such that
  all subtyping and assignment constraints are met.  In essence, the check
  module specifies the constraints, and the infer module solves them.

# Note

This API is completely unstable and subject to change.

*/
// Do not remove on snapshot creation. Needed for bootstrap. (Issue #22364)
#![cfg_attr(stage0, feature(custom_attribute))]
#![crate_name = "rustc_typeck"]
#![unstable(feature = "rustc_private")]
#![staged_api]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
      html_favicon_url = "http://www.rust-lang.org/favicon.ico",
      html_root_url = "http://doc.rust-lang.org/nightly/")]

#![allow(non_camel_case_types)]

#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(collections)]
#![feature(core)]
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
#![feature(staged_api)]

#[macro_use] extern crate log;
#[macro_use] extern crate syntax;

extern crate arena;
extern crate fmt_macros;
extern crate rustc;

pub use rustc::lint;
pub use rustc::metadata;
pub use rustc::middle;
pub use rustc::session;
pub use rustc::util;

use middle::def;
use middle::infer;
use middle::subst;
use middle::ty::{self, Ty};
use session::config;
use util::common::time;
use util::ppaux::Repr;
use util::ppaux;

use syntax::codemap::Span;
use syntax::print::pprust::*;
use syntax::{ast, ast_map, abi};
use syntax::ast_util::local_def;

use std::cell::RefCell;

// NB: This module needs to be declared first so diagnostics are
// registered before they are used.
pub mod diagnostics;

pub mod check;
mod rscope;
mod astconv;
pub mod collect;
mod constrained_type_params;
pub mod coherence;
pub mod variance;

pub struct TypeAndSubsts<'tcx> {
    pub substs: subst::Substs<'tcx>,
    pub ty: Ty<'tcx>,
}

pub struct CrateCtxt<'a, 'tcx: 'a> {
    // A mapping from method call sites to traits that have that method.
    pub trait_map: ty::TraitMap,
    /// A vector of every trait accessible in the whole crate
    /// (i.e. including those from subcrates). This is used only for
    /// error reporting, and so is lazily initialised and generally
    /// shouldn't taint the common path (hence the RefCell).
    pub all_traits: RefCell<Option<check::method::AllTraitsVec>>,
    pub tcx: &'a ty::ctxt<'tcx>,
}

// Functions that write types into the node type table
fn write_ty_to_tcx<'tcx>(tcx: &ty::ctxt<'tcx>, node_id: ast::NodeId, ty: Ty<'tcx>) {
    debug!("write_ty_to_tcx({}, {})", node_id, ppaux::ty_to_string(tcx, ty));
    assert!(!ty::type_needs_infer(ty));
    tcx.node_type_insert(node_id, ty);
}

fn write_substs_to_tcx<'tcx>(tcx: &ty::ctxt<'tcx>,
                                 node_id: ast::NodeId,
                                 item_substs: ty::ItemSubsts<'tcx>) {
    if !item_substs.is_noop() {
        debug!("write_substs_to_tcx({}, {})",
               node_id,
               item_substs.repr(tcx));

        assert!(item_substs.substs.types.all(|t| !ty::type_needs_infer(*t)));

        tcx.item_substs.borrow_mut().insert(node_id, item_substs);
    }
}

fn lookup_full_def(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) -> def::Def {
    match tcx.def_map.borrow().get(&id) {
        Some(x) => x.full_def(),
        None => {
            span_fatal!(tcx.sess, sp, E0242, "internal error looking up a definition")
        }
    }
}

fn require_same_types<'a, 'tcx, M>(tcx: &ty::ctxt<'tcx>,
                                   maybe_infcx: Option<&infer::InferCtxt<'a, 'tcx>>,
                                   t1_is_expected: bool,
                                   span: Span,
                                   t1: Ty<'tcx>,
                                   t2: Ty<'tcx>,
                                   msg: M)
                                   -> bool where
    M: FnOnce() -> String,
{
    let result = match maybe_infcx {
        None => {
            let infcx = infer::new_infer_ctxt(tcx);
            infer::mk_eqty(&infcx, t1_is_expected, infer::Misc(span), t1, t2)
        }
        Some(infcx) => {
            infer::mk_eqty(infcx, t1_is_expected, infer::Misc(span), t1, t2)
        }
    };

    match result {
        Ok(_) => true,
        Err(ref terr) => {
            span_err!(tcx.sess, span, E0211,
                              "{}: {}",
                                      msg(),
                                      ty::type_err_to_str(tcx,
                                                          terr));
            ty::note_and_explain_type_err(tcx, terr, span);
            false
        }
    }
}

fn check_main_fn_ty(ccx: &CrateCtxt,
                    main_id: ast::NodeId,
                    main_span: Span) {
    let tcx = ccx.tcx;
    let main_t = ty::node_id_to_type(tcx, main_id);
    match main_t.sty {
        ty::ty_bare_fn(..) => {
            match tcx.map.find(main_id) {
                Some(ast_map::NodeItem(it)) => {
                    match it.node {
                        ast::ItemFn(_, _, _, ref ps, _)
                        if ps.is_parameterized() => {
                            span_err!(ccx.tcx.sess, main_span, E0131,
                                      "main function is not allowed to have type parameters");
                            return;
                        }
                        _ => ()
                    }
                }
                _ => ()
            }
            let se_ty = ty::mk_bare_fn(tcx, Some(local_def(main_id)), tcx.mk_bare_fn(ty::BareFnTy {
                unsafety: ast::Unsafety::Normal,
                abi: abi::Rust,
                sig: ty::Binder(ty::FnSig {
                    inputs: Vec::new(),
                    output: ty::FnConverging(ty::mk_nil(tcx)),
                    variadic: false
                })
            }));

            require_same_types(tcx, None, false, main_span, main_t, se_ty,
                || {
                    format!("main function expects type: `{}`",
                            ppaux::ty_to_string(ccx.tcx, se_ty))
                });
        }
        _ => {
            tcx.sess.span_bug(main_span,
                              &format!("main has a non-function type: found \
                                       `{}`",
                                      ppaux::ty_to_string(tcx,
                                                       main_t)));
        }
    }
}

fn check_start_fn_ty(ccx: &CrateCtxt,
                     start_id: ast::NodeId,
                     start_span: Span) {
    let tcx = ccx.tcx;
    let start_t = ty::node_id_to_type(tcx, start_id);
    match start_t.sty {
        ty::ty_bare_fn(..) => {
            match tcx.map.find(start_id) {
                Some(ast_map::NodeItem(it)) => {
                    match it.node {
                        ast::ItemFn(_,_,_,ref ps,_)
                        if ps.is_parameterized() => {
                            span_err!(tcx.sess, start_span, E0132,
                                      "start function is not allowed to have type parameters");
                            return;
                        }
                        _ => ()
                    }
                }
                _ => ()
            }

            let se_ty = ty::mk_bare_fn(tcx, Some(local_def(start_id)), tcx.mk_bare_fn(ty::BareFnTy {
                unsafety: ast::Unsafety::Normal,
                abi: abi::Rust,
                sig: ty::Binder(ty::FnSig {
                    inputs: vec!(
                        tcx.types.isize,
                        ty::mk_imm_ptr(tcx, ty::mk_imm_ptr(tcx, tcx.types.u8))
                    ),
                    output: ty::FnConverging(tcx.types.isize),
                    variadic: false,
                }),
            }));

            require_same_types(tcx, None, false, start_span, start_t, se_ty,
                || {
                    format!("start function expects type: `{}`",
                            ppaux::ty_to_string(ccx.tcx, se_ty))
                });

        }
        _ => {
            tcx.sess.span_bug(start_span,
                              &format!("start has a non-function type: found \
                                       `{}`",
                                      ppaux::ty_to_string(tcx, start_t)));
        }
    }
}

fn check_for_entry_fn(ccx: &CrateCtxt) {
    let tcx = ccx.tcx;
    match *tcx.sess.entry_fn.borrow() {
        Some((id, sp)) => match tcx.sess.entry_type.get() {
            Some(config::EntryMain) => check_main_fn_ty(ccx, id, sp),
            Some(config::EntryStart) => check_start_fn_ty(ccx, id, sp),
            Some(config::EntryNone) => {}
            None => tcx.sess.bug("entry function without a type")
        },
        None => {}
    }
}

pub fn check_crate(tcx: &ty::ctxt, trait_map: ty::TraitMap) {
    let time_passes = tcx.sess.time_passes();
    let ccx = CrateCtxt {
        trait_map: trait_map,
        all_traits: RefCell::new(None),
        tcx: tcx
    };

    time(time_passes, "type collecting", (), |_|
         collect::collect_item_types(tcx));

    // this ensures that later parts of type checking can assume that items
    // have valid types and not error
    tcx.sess.abort_if_errors();

    time(time_passes, "variance inference", (), |_|
         variance::infer_variance(tcx));

    time(time_passes, "coherence checking", (), |_|
        coherence::check_coherence(&ccx));

    time(time_passes, "type checking", (), |_|
        check::check_item_types(&ccx));

    check_for_entry_fn(&ccx);
    tcx.sess.abort_if_errors();
}

#[cfg(stage0)]
__build_diagnostic_array! { DIAGNOSTICS }
#[cfg(not(stage0))]
__build_diagnostic_array! { librustc_typeck, DIAGNOSTICS }
<|endoftext|>


<commit_before>use bencode::BEncode;
use std::path::PathBuf;
use std::collections::BTreeMap;
use std::{io, fs};
use sha1::Sha1;

#[derive(Clone, Debug)]
pub struct Info {
    pub announce: String,
    pub piece_len: usize,
    pub total_len: usize,
    pub hashes: Vec<Vec<u8>>,
    pub hash: [u8; 20],
    pub files: Vec<File>,
}

#[derive(Clone, Debug)]
pub struct File {
    pub path: PathBuf,
    pub length: usize,
}

impl File {
    fn from_bencode(data: BEncode) -> Result<File, &'static str> {
        let mut d = data.to_dict().ok_or("File must be a dictionary type!")?;
        match (d.remove("name"), d.remove("path"), d.remove("length")) {
            (Some(v), None, Some(l)) => {
                let f = File {
                    path: PathBuf::from(v.to_string().ok_or("Path must be a valid string.")?),
                    length: l.to_int().ok_or("File length must be a valid int")? as usize,
                };
                Ok(f)
            }
            (None, Some(path), Some(l)) => {
                let mut p = PathBuf::new();
                for dir in path.to_list().ok_or("File path should be a list")? {
                    p.push(dir.to_string().ok_or("File path parts should be strings")?);
                }
                let f = File {
                    path: p,
                    length: l.to_int().ok_or("File length must be a valid int")? as usize,
                };
                Ok(f)
            }
            _ => Err("File dict must contain length and name or path"),
        }
    }

    fn create(&self) -> Result<(), io::Error> {
        if let Some(parent) = self.path.parent() {
            fs::create_dir_all(parent)?;
        }
        let f = fs::OpenOptions::new().write(true).create(true).open(&self.path)?;
        f.set_len(self.length as u64)?;
        Ok(())
    }
}

impl Info {
    pub fn from_bencode(data: BEncode) -> Result<Info, &'static str> {
        data.to_dict()
            .and_then(|mut d| d.remove("info").and_then(|i| i.to_dict()).map(|i| (d, i)))
            .ok_or("")
            .and_then(|(mut d, mut i)| {
                let mut m = Sha1::new();
                let mut info_bytes = Vec::new();
                // TODO: Deal with this error/maybe convert everything to io::Error
                BEncode::Dict(i.clone()).encode(&mut info_bytes).unwrap();
                m.update(&info_bytes);
                let hash = m.digest().bytes();

                let a = d.remove("announce")
                    .and_then(|a| a.to_string())
                    .ok_or("Info must have announce url")?;
                let pl = i.remove("piece length")
                    .and_then(|i| i.to_int())
                    .ok_or("Info must specify piece length")?;
                let hashes = i.remove("pieces")
                    .and_then(|p| p.to_bytes())
                    .map(|mut p| {
                        let mut v = Vec::new();
                        while p.len() != 0 {
                            let remaining = p.split_off(20);
                            v.push(p);
                            p = remaining;
                        }
                        v
                    })
                    .ok_or("Info must provide valid hashes")?;
                let files = parse_bencode_files(i)?;
                let total_len = files.iter().map(|f| f.length).sum();
                Ok(Info {
                    announce: a,
                    piece_len: pl as usize,
                    hashes,
                    hash,
                    files,
                    total_len,
                })
            })
    }

    pub fn create_files(&self) -> Result<(), io::Error> {
        for file in self.files.iter() {
            file.create()?;
        }
        Ok(())
    }

    pub fn last_piece_len(&self) -> u32 {
        let res = (self.total_len % 16384) as u32;
        if res == 0 {
            16384
        } else {
            res
        }
    }

    pub fn is_last_piece(&self, (idx, offset): (u32, u32)) -> bool {
        let last_piece_len = (self.total_len - self.piece_len * (self.pieces() as usize - 1)) as u32;
        if offset < last_piece_len {
            let last_offset = last_piece_len - offset;
            idx == self.pieces() - 1 && last_offset <= 16384
        } else {
            false
        }
    }

    pub fn pieces(&self) -> u32 {
        self.hashes.len() as u32
    }
}

fn parse_bencode_files(mut data: BTreeMap<String, BEncode>) -> Result<Vec<File>, &'static str> {
    match data.remove("files").and_then(|l| l.to_list()) {
        Some(fs) => {
            let mut path = PathBuf::new();
            path.push(data.remove("name")
                .and_then(|v| v.to_string())
                .ok_or("Multifile mode must have a name field")?);
            let mut files = Vec::new();
            for f in fs {
                let mut file = File::from_bencode(f)?;
                file.path = path.join(file.path);
                files.push(file);
            }
            return Ok(files);
        }
        None => File::from_bencode(BEncode::Dict(data)).map(|f| vec![f]),
    }
}
<commit_msg>Add name parsing to torrent info<commit_after>use bencode::BEncode;
use std::path::PathBuf;
use std::collections::BTreeMap;
use std::{io, fs};
use sha1::Sha1;

#[derive(Clone, Debug)]
pub struct Info {
    pub name: String,
    pub announce: String,
    pub piece_len: usize,
    pub total_len: usize,
    pub hashes: Vec<Vec<u8>>,
    pub hash: [u8; 20],
    pub files: Vec<File>,
}

#[derive(Clone, Debug)]
pub struct File {
    pub path: PathBuf,
    pub length: usize,
}

impl File {
    fn from_bencode(data: BEncode) -> Result<File, &'static str> {
        let mut d = data.to_dict().ok_or("File must be a dictionary type!")?;
        match (d.remove("name"), d.remove("path"), d.remove("length")) {
            (Some(v), None, Some(l)) => {
                let f = File {
                    path: PathBuf::from(v.to_string().ok_or("Path must be a valid string.")?),
                    length: l.to_int().ok_or("File length must be a valid int")? as usize,
                };
                Ok(f)
            }
            (None, Some(path), Some(l)) => {
                let mut p = PathBuf::new();
                for dir in path.to_list().ok_or("File path should be a list")? {
                    p.push(dir.to_string().ok_or("File path parts should be strings")?);
                }
                let f = File {
                    path: p,
                    length: l.to_int().ok_or("File length must be a valid int")? as usize,
                };
                Ok(f)
            }
            _ => Err("File dict must contain length and name or path"),
        }
    }

    fn create(&self) -> Result<(), io::Error> {
        if let Some(parent) = self.path.parent() {
            fs::create_dir_all(parent)?;
        }
        let f = fs::OpenOptions::new().write(true).create(true).open(&self.path)?;
        f.set_len(self.length as u64)?;
        Ok(())
    }
}

impl Info {
    pub fn from_bencode(data: BEncode) -> Result<Info, &'static str> {
        data.to_dict()
            .and_then(|mut d| d.remove("info").and_then(|i| i.to_dict()).map(|i| (d, i)))
            .ok_or("")
            .and_then(|(mut d, mut i)| {
                let mut m = Sha1::new();
                let mut info_bytes = Vec::new();
                // TODO: Deal with this error/maybe convert everything to io::Error
                BEncode::Dict(i.clone()).encode(&mut info_bytes).unwrap();
                m.update(&info_bytes);
                let hash = m.digest().bytes();

                let a = d.remove("announce")
                    .and_then(|a| a.to_string())
                    .ok_or("Info must have announce url")?;
                let pl = i.remove("piece length")
                    .and_then(|i| i.to_int())
                    .ok_or("Info must specify piece length")?;
                let hashes = i.remove("pieces")
                    .and_then(|p| p.to_bytes())
                    .map(|mut p| {
                        let mut v = Vec::new();
                        while p.len() != 0 {
                            let remaining = p.split_off(20);
                            v.push(p);
                            p = remaining;
                        }
                        v
                    })
                    .ok_or("Info must provide valid hashes")?;
                let files = parse_bencode_files(i)?;
                let name = if files.len() == 0 {
                    files[0].path.clone().into_os_string().into_string().unwrap()
                } else if !files[0].path.has_root() {
                    let mut piter = files[0].path.components();
                    piter.next().unwrap().as_os_str().to_os_string().into_string().unwrap()
                } else {
                    unreachable!();
                };
                let total_len = files.iter().map(|f| f.length).sum();
                Ok(Info {
                    name,
                    announce: a,
                    piece_len: pl as usize,
                    hashes,
                    hash,
                    files,
                    total_len,
                })
            })
    }

    pub fn create_files(&self) -> Result<(), io::Error> {
        for file in self.files.iter() {
            file.create()?;
        }
        Ok(())
    }

    pub fn last_piece_len(&self) -> u32 {
        let res = (self.total_len % 16384) as u32;
        if res == 0 {
            16384
        } else {
            res
        }
    }

    pub fn is_last_piece(&self, (idx, offset): (u32, u32)) -> bool {
        let last_piece_len = (self.total_len - self.piece_len * (self.pieces() as usize - 1)) as u32;
        if offset < last_piece_len {
            let last_offset = last_piece_len - offset;
            idx == self.pieces() - 1 && last_offset <= 16384
        } else {
            false
        }
    }

    pub fn pieces(&self) -> u32 {
        self.hashes.len() as u32
    }
}

fn parse_bencode_files(mut data: BTreeMap<String, BEncode>) -> Result<Vec<File>, &'static str> {
    match data.remove("files").and_then(|l| l.to_list()) {
        Some(fs) => {
            let mut path = PathBuf::new();
            path.push(data.remove("name")
                .and_then(|v| v.to_string())
                .ok_or("Multifile mode must have a name field")?);
            let mut files = Vec::new();
            for f in fs {
                let mut file = File::from_bencode(f)?;
                file.path = path.join(file.path);
                files.push(file);
            }
            return Ok(files);
        }
        None => File::from_bencode(BEncode::Dict(data)).map(|f| vec![f]),
    }
}
<|endoftext|>


<commit_before>use std::rc::*;

use rustc_serialize::*;

use super::encoder::*;
use super::treenode::*;
use super::values::*;

///
/// Used to help decode tree nodes into other types
///
struct TreeNodeDecoder {
    current_node: Rc<TreeNode>
}

#[derive(Debug)]
pub enum TreeNodeDecodingError {
    UnsupportedType,
    NodeHasInvalidType,
    ValueOutOfRange,
    MissingField,
    GenericError(String)
}

impl TreeNodeDecoder {
    fn read_current(&self) -> &TreeValue {
        self.current_node.get_value()
    }
}

impl Decoder for TreeNodeDecoder {
    type Error = TreeNodeDecodingError;

    fn read_nil(&mut self) -> Result<(), Self::Error> {
        match *self.read_current() {
            TreeValue::Nothing  => Ok(()),
            _                   => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_i32(&mut self) -> Result<i32, Self::Error> {
        match *self.read_current() {
            TreeValue::Int(ref x)   => Ok(*x),
            _                       => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_i16(&mut self) -> Result<i16, Self::Error> {
        match *self.read_current() {
            TreeValue::Int(ref x)   => if (*x >= i16::min_value() as i32) && (*x <= i16::max_value() as i32) { Ok(*x as i16) } else { Err(TreeNodeDecodingError::ValueOutOfRange) },
            _                       => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_i8(&mut self) -> Result<i8, Self::Error> {
        match *self.read_current() {
            TreeValue::Int(ref x)   => if (*x >= i8::min_value() as i32) && (*x <= i8::max_value() as i32) { Ok(*x as i8) } else { Err(TreeNodeDecodingError::ValueOutOfRange) },
            _                       => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_str(&mut self) -> Result<String, Self::Error> {
        match *self.read_current() {
            TreeValue::String(ref x)    => Ok(x.to_owned()),
            _                           => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_bool(&mut self) -> Result<bool, Self::Error> {
        match *self.read_current() {
            TreeValue::Bool(ref x)  => Ok(*x),
            _                       => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_f64(&mut self) -> Result<f64, Self::Error> {
        match *self.read_current() {
            TreeValue::Real(ref x)  => Ok(*x),
            _                       => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_f32(&mut self) -> Result<f32, Self::Error> {
        match *self.read_current() {
            TreeValue::Real(ref x)  => Ok(*x as f32),
            _                       => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_struct<T, F>(&mut self, s_name: &str, len: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        f(self)
    }

    fn read_struct_field<T, F>(&mut self, f_name: &str, f_idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        // Look up the field
        // TODO: could hash the field names to avoid doing a linear search every time (not clear if there are substantial benefits for this given the small number of fields in most structures)
        let field = self.current_node.get_child_ref_at(f_name);

        match field {
            None        => Err(TreeNodeDecodingError::MissingField),
            Some(ref x) => {
                // Move into the field node
                let previous_node = self.current_node.to_owned();
                self.current_node = x.to_owned();

                // Decode it
                let result = f(self);

                // Move back out
                self.current_node = previous_node.to_owned();

                result
            }
        }
    }

    fn read_usize(&mut self) -> Result<usize, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_u64(&mut self) -> Result<u64, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_u32(&mut self) -> Result<u32, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_u16(&mut self) -> Result<u16, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_u8(&mut self) -> Result<u8, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_isize(&mut self) -> Result<isize, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_i64(&mut self) -> Result<i64, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_char(&mut self) -> Result<char, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_enum<T, F>(&mut self, name: &str, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_enum_variant<T, F>(&mut self, names: &[&str], f: F) -> Result<T, Self::Error> where F: FnMut(&mut Self, usize) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_enum_variant_arg<T, F>(&mut self, a_idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_enum_struct_variant<T, F>(&mut self, names: &[&str], f: F) -> Result<T, Self::Error> where F: FnMut(&mut Self, usize) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_enum_struct_variant_field<T, F>(&mut self, f_name: &str, f_idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_tuple<T, F>(&mut self, len: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_tuple_arg<T, F>(&mut self, a_idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_tuple_struct<T, F>(&mut self, s_name: &str, len: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_tuple_struct_arg<T, F>(&mut self, a_idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_option<T, F>(&mut self, f: F) -> Result<T, Self::Error> where F: FnMut(&mut Self, bool) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_seq<T, F>(&mut self, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self, usize) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_seq_elt<T, F>(&mut self, idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_map<T, F>(&mut self, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self, usize) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_map_elt_key<T, F>(&mut self, idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_map_elt_val<T, F>(&mut self, idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn error(&mut self, err: &str) -> Self::Error {
        TreeNodeDecodingError::GenericError(err.to_string())
    }
}

///
/// Trait implemented by things that can be decoded from a tree node
///
pub trait DecodeFromTreeNode : Sized {
    ///
    /// Creates a new object from a tree node
    ///
    fn new_from_tree(tree: &Rc<TreeNode>) -> Result<Self, TreeNodeDecodingError>;
}

impl<T: Decodable + EncodeToTreeNode> DecodeFromTreeNode for T {
    ///
    /// Creates a new object from a tree node
    ///
    fn new_from_tree(tree: &Rc<TreeNode>) -> Result<T, TreeNodeDecodingError> {
        let mut decoder = TreeNodeDecoder { current_node: tree.to_owned() };

        T::decode(&mut decoder)
    }
}
<commit_msg>Add a basic test for the decoder<commit_after>use std::rc::*;

use rustc_serialize::*;

use super::encoder::*;
use super::treenode::*;
use super::values::*;

///
/// Used to help decode tree nodes into other types
///
struct TreeNodeDecoder {
    current_node: Rc<TreeNode>
}

#[derive(Debug)]
pub enum TreeNodeDecodingError {
    UnsupportedType,
    NodeHasInvalidType,
    ValueOutOfRange,
    MissingField,
    GenericError(String)
}

impl TreeNodeDecoder {
    fn read_current(&self) -> &TreeValue {
        self.current_node.get_value()
    }
}

impl Decoder for TreeNodeDecoder {
    type Error = TreeNodeDecodingError;

    fn read_nil(&mut self) -> Result<(), Self::Error> {
        match *self.read_current() {
            TreeValue::Nothing  => Ok(()),
            _                   => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_i32(&mut self) -> Result<i32, Self::Error> {
        match *self.read_current() {
            TreeValue::Int(ref x)   => Ok(*x),
            _                       => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_i16(&mut self) -> Result<i16, Self::Error> {
        match *self.read_current() {
            TreeValue::Int(ref x)   => if (*x >= i16::min_value() as i32) && (*x <= i16::max_value() as i32) { Ok(*x as i16) } else { Err(TreeNodeDecodingError::ValueOutOfRange) },
            _                       => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_i8(&mut self) -> Result<i8, Self::Error> {
        match *self.read_current() {
            TreeValue::Int(ref x)   => if (*x >= i8::min_value() as i32) && (*x <= i8::max_value() as i32) { Ok(*x as i8) } else { Err(TreeNodeDecodingError::ValueOutOfRange) },
            _                       => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_str(&mut self) -> Result<String, Self::Error> {
        match *self.read_current() {
            TreeValue::String(ref x)    => Ok(x.to_owned()),
            _                           => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_bool(&mut self) -> Result<bool, Self::Error> {
        match *self.read_current() {
            TreeValue::Bool(ref x)  => Ok(*x),
            _                       => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_f64(&mut self) -> Result<f64, Self::Error> {
        match *self.read_current() {
            TreeValue::Real(ref x)  => Ok(*x),
            _                       => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_f32(&mut self) -> Result<f32, Self::Error> {
        match *self.read_current() {
            TreeValue::Real(ref x)  => Ok(*x as f32),
            _                       => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_struct<T, F>(&mut self, s_name: &str, len: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        f(self)
    }

    fn read_struct_field<T, F>(&mut self, f_name: &str, f_idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        // Look up the field
        // TODO: could hash the field names to avoid doing a linear search every time (not clear if there are substantial benefits for this given the small number of fields in most structures)
        let field = self.current_node.get_child_ref_at(f_name);

        match field {
            None        => Err(TreeNodeDecodingError::MissingField),
            Some(ref x) => {
                // Move into the field node
                let previous_node = self.current_node.to_owned();
                self.current_node = x.to_owned();

                // Decode it
                let result = f(self);

                // Move back out
                self.current_node = previous_node.to_owned();

                result
            }
        }
    }

    fn read_usize(&mut self) -> Result<usize, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_u64(&mut self) -> Result<u64, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_u32(&mut self) -> Result<u32, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_u16(&mut self) -> Result<u16, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_u8(&mut self) -> Result<u8, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_isize(&mut self) -> Result<isize, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_i64(&mut self) -> Result<i64, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_char(&mut self) -> Result<char, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_enum<T, F>(&mut self, name: &str, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_enum_variant<T, F>(&mut self, names: &[&str], f: F) -> Result<T, Self::Error> where F: FnMut(&mut Self, usize) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_enum_variant_arg<T, F>(&mut self, a_idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_enum_struct_variant<T, F>(&mut self, names: &[&str], f: F) -> Result<T, Self::Error> where F: FnMut(&mut Self, usize) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_enum_struct_variant_field<T, F>(&mut self, f_name: &str, f_idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_tuple<T, F>(&mut self, len: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_tuple_arg<T, F>(&mut self, a_idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_tuple_struct<T, F>(&mut self, s_name: &str, len: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_tuple_struct_arg<T, F>(&mut self, a_idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_option<T, F>(&mut self, f: F) -> Result<T, Self::Error> where F: FnMut(&mut Self, bool) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_seq<T, F>(&mut self, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self, usize) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_seq_elt<T, F>(&mut self, idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_map<T, F>(&mut self, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self, usize) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_map_elt_key<T, F>(&mut self, idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_map_elt_val<T, F>(&mut self, idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn error(&mut self, err: &str) -> Self::Error {
        TreeNodeDecodingError::GenericError(err.to_string())
    }
}

///
/// Trait implemented by things that can be decoded from a tree node
///
pub trait DecodeFromTreeNode : Sized {
    ///
    /// Creates a new object from a tree node
    ///
    fn new_from_tree(tree: &Rc<TreeNode>) -> Result<Self, TreeNodeDecodingError>;
}

impl<T: Decodable + EncodeToTreeNode> DecodeFromTreeNode for T {
    ///
    /// Creates a new object from a tree node
    ///
    fn new_from_tree(tree: &Rc<TreeNode>) -> Result<T, TreeNodeDecodingError> {
        let mut decoder = TreeNodeDecoder { current_node: tree.to_owned() };

        T::decode(&mut decoder)
    }
}

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

    #[derive(RustcEncodable, RustcDecodable)]
    struct Test {
        field1: i32,
        field2: String,
        field3: bool
    }

    impl EncodeToTreeNode for Test { }

    #[test]
    fn encode_decode_structure() {
        let initial_structure = Test { field1: 42, field2: "test string".to_string(), field3: true };

        let encoded = initial_structure.to_tree_node();
        let decoded = Test::new_from_tree(&encoded);

        assert!(decoded.is_ok());

        let result = decoded.unwrap();

        assert!(result.field1 == 42);
        assert!(result.field2 == "test string");
        assert!(result.field3);
    }
}
<|endoftext|>