<commit_before>#[deny(missing_docs)]

extern crate input;
extern crate piston_window;
extern crate rustc_serialize;
extern crate viewport;

mod builder;

use input::{Input, Button, Motion};
use piston_window::Size;
use std::collections::HashMap;
use std::default::Default;
use viewport::Viewport;

pub use builder::InputTranslatorBuilder;

/// Represents a logical action to be bound to a particular button press, e.g.
/// jump, attack, or move forward
pub trait Action: Copy + PartialEq + Eq { }

/// A translated action.
#[derive(Debug, Copy, Clone)]
pub enum Translated<A: Action> {
    /// A keypress event which was bound to an action
    Press(A),

    /// A key release event which was bound to an action
    Release(A),

    /// A translated mouse motion. The logical origin of a translated MouseCursor event
    /// is in the top left corner of the window, and the logical scroll is non-natural.
    /// Relative events are unchanged for now.
    Move(Motion)
}

/// An object which translates piston::input::Input events into input_map::Translated<A> events
#[derive(Clone)]
pub struct InputTranslator<A: Action> {
    keymap: KeyMap<A>,
    mouse_translator: MouseTranslator
}

impl<A: Action> InputTranslator<A> {

    /// Creates an empty InputTranslator.
    pub fn new(size: Size) -> Self {
        InputTranslator {
            keymap: KeyMap::new(),
            mouse_translator: MouseTranslator::new(size)
        }
    }

    /// Translate an Input into a Translated<A> event
    pub fn translate(&self, input: &Input) -> Option<Translated<A>> {
        macro_rules! translate_button(($but_state:ident, $but_var:ident) => (
            match self.keymap.translate($but_var) {
                Some(act) => Some(Translated::$but_state(act)),
                None => None
            });
        );

        match input {
            &Input::Press(button) => translate_button!(Press, button),
            &Input::Release(button) => translate_button!(Release, button),
            &Input::Move(motion) =>
                Some(Translated::Move(self.mouse_translator.translate(motion))),
            _ => None
        }
    }

    pub fn rebind_button(&mut self, _but: Button, _act: A) {
        // TODO implement
    }

    pub fn add_binding(&mut self, but: Button, act: A) {
        self.keymap.add_mapping(but, act);
    }

    /// Get all the bindings for an action
    pub fn get_bindings_for_action(&self, _act: A) -> ButtonTuple {
        ButtonTuple(None, None, None) // TODO implement
    }

    /// Re-set the mouse bounds size used for calculating mouse events
    pub fn set_size(&mut self, size: Size) {
        self.mouse_translator.viewport_size = size
    }

    /// Re-set the mouse bounds size from a viewport
    pub fn set_size_from_viewport(&mut self, vp: Viewport) {
        self.set_size(Size::from(vp.draw_size));
    }
}

#[derive(Clone)]
struct MouseTranslator {
    pub x_axis_motion_inverted: bool,
    pub y_axis_motion_inverted: bool,
    pub x_axis_scroll_inverted: bool,
    pub y_axis_scroll_inverted: bool,
    pub viewport_size: Size
}

impl MouseTranslator {
    fn new(size: Size) -> Self {
        MouseTranslator {
            x_axis_motion_inverted: false,
            y_axis_motion_inverted: false,
            x_axis_scroll_inverted: false,
            y_axis_scroll_inverted: false,
            viewport_size: size
        }
    }

    fn translate(&self, motion: Motion) -> Motion {
        match motion {
            Motion::MouseCursor(x, y) => {
                let (sw, sh) = {
                    let Size {width, height} = self.viewport_size;
                    (width as f64, height as f64)
                };

                let cx = if self.x_axis_motion_inverted { sw - x } else { x };
                let cy = if self.y_axis_motion_inverted { sh - y } else { y };

                Motion::MouseCursor(cx, cy)
            },
            Motion::MouseScroll(x, y) => {
                let mx = if self.x_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                let my = if self.y_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                Motion::MouseScroll(x * mx, y * my)
            },
            relative => relative
        }
    }
}

#[derive(Clone, Debug)]
struct KeyMap<A: Action> {
    btn_map: HashMap<ButtonTuple, A>
}

impl<A: Action> KeyMap<A> {
    fn new() -> Self {
        KeyMap {
            btn_map: HashMap::new()
        }
    }

    fn add_mapping(&mut self, button: Button, action: A) {
        let mut bt = self.get_bindings_for_action(action).unwrap_or(ButtonTuple::new());
        let bt = if bt.insert_inplace(button) {bt} else {ButtonTuple::new()};
        self.btn_map.insert(bt, action);
    }

    fn get_bindings_for_action(&self, action: A) -> Option<ButtonTuple> {
        self.btn_map.iter().find(|&(_, &a)| a == action).map(|(&bt, _)| bt)
    }

    #[allow(dead_code)]
    fn get_ref_bindings_for_action(&self, action: A) -> Option<&ButtonTuple> {
        self.btn_map.iter().find(|&(_, &a)| a == action).map(|(bt, _)| bt)
    }

    #[cfg(unimplemented)] // This gives a compile error
    fn get_ref_bindings_for_action_mut(&mut self, action: A) -> Option<&mut ButtonTuple> {
        self.btn_map.iter_mut().find(|&(_, &mut a)| a == action).as_mut().map(|&mut (bt, _)| bt)
    }

    fn translate(&self, button: Button) -> Option<A> {
        self.btn_map.iter().find(|&(&bt, _)| bt.contains(button)).map(|(_, &a)| a)
    }
}

/// A three-element tuple of Option<Button>. Used as the key of an InputTranslator
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct ButtonTuple(pub Option<Button>, pub Option<Button>, pub Option<Button>);

impl ButtonTuple {
    fn new() -> Self { Default::default() }

    fn contains(&self, btn: Button) -> bool {
        let sbtn = Some(btn);
        self.0 == sbtn || self.1 == sbtn || self.2 == sbtn
    }

    #[allow(dead_code)]
    fn remove_inplace(&mut self, btn: Button) {
        let sbtn = Some(btn);
        if self.0 == sbtn {self.0 = None}
        if self.1 == sbtn {self.1 = None}
        if self.2 == sbtn {self.2 = None}
    }

    #[allow(dead_code)]
    fn replace_inplace(&mut self, btn_idx: u32, btn: Button) -> bool {
        match btn_idx {
            0 => {self.0 = Some(btn); true},
            1 => {self.1 = Some(btn); true},
            2 => {self.2 = Some(btn); true},
            _ => false
        }
    }

    fn insert_inplace(&mut self, btn: Button) -> bool {
        match self {
            &mut ButtonTuple(a, b, c) if a.is_none() => {*self = ButtonTuple(Some(btn), b, c); true},
            &mut ButtonTuple(a, b, c) if b.is_none() => {*self = ButtonTuple(a, Some(btn), c); true},
            &mut ButtonTuple(a, b, c) if c.is_none() => {*self = ButtonTuple(a, b, Some(btn)); true}
            _ => false
        }
    }
}

impl Default for ButtonTuple {
    fn default() -> Self { ButtonTuple(None, None, None) }
}
<commit_msg>Remove unnecessary methods<commit_after>#[deny(missing_docs)]

extern crate input;
extern crate piston_window;
extern crate rustc_serialize;
extern crate viewport;

mod builder;

use input::{Input, Button, Motion};
use piston_window::Size;
use std::collections::HashMap;
use std::default::Default;
use viewport::Viewport;

pub use builder::InputTranslatorBuilder;

/// Represents a logical action to be bound to a particular button press, e.g.
/// jump, attack, or move forward
pub trait Action: Copy + PartialEq + Eq { }

/// A translated action.
#[derive(Debug, Copy, Clone)]
pub enum Translated<A: Action> {
    /// A keypress event which was bound to an action
    Press(A),

    /// A key release event which was bound to an action
    Release(A),

    /// A translated mouse motion. The logical origin of a translated MouseCursor event
    /// is in the top left corner of the window, and the logical scroll is non-natural.
    /// Relative events are unchanged for now.
    Move(Motion)
}

/// An object which translates piston::input::Input events into input_map::Translated<A> events
#[derive(Clone)]
pub struct InputTranslator<A: Action> {
    keymap: KeyMap<A>,
    mouse_translator: MouseTranslator
}

impl<A: Action> InputTranslator<A> {

    /// Creates an empty InputTranslator.
    pub fn new(size: Size) -> Self {
        InputTranslator {
            keymap: KeyMap::new(),
            mouse_translator: MouseTranslator::new(size)
        }
    }

    /// Translate an Input into a Translated<A> event
    pub fn translate(&self, input: &Input) -> Option<Translated<A>> {
        macro_rules! translate_button(($but_state:ident, $but_var:ident) => (
            match self.keymap.translate($but_var) {
                Some(act) => Some(Translated::$but_state(act)),
                None => None
            });
        );

        match input {
            &Input::Press(button) => translate_button!(Press, button),
            &Input::Release(button) => translate_button!(Release, button),
            &Input::Move(motion) =>
                Some(Translated::Move(self.mouse_translator.translate(motion))),
            _ => None
        }
    }

    pub fn add_binding(&mut self, but: Button, act: A) {
        self.keymap.add_mapping(but, act);
    }

    /// Re-set the mouse bounds size used for calculating mouse events
    pub fn set_size(&mut self, size: Size) {
        self.mouse_translator.viewport_size = size
    }

    /// Re-set the mouse bounds size from a viewport
    pub fn set_size_from_viewport(&mut self, vp: Viewport) {
        self.set_size(Size::from(vp.draw_size));
    }
}

#[derive(Clone)]
struct MouseTranslator {
    pub x_axis_motion_inverted: bool,
    pub y_axis_motion_inverted: bool,
    pub x_axis_scroll_inverted: bool,
    pub y_axis_scroll_inverted: bool,
    pub viewport_size: Size
}

impl MouseTranslator {
    fn new(size: Size) -> Self {
        MouseTranslator {
            x_axis_motion_inverted: false,
            y_axis_motion_inverted: false,
            x_axis_scroll_inverted: false,
            y_axis_scroll_inverted: false,
            viewport_size: size
        }
    }

    fn translate(&self, motion: Motion) -> Motion {
        match motion {
            Motion::MouseCursor(x, y) => {
                let (sw, sh) = {
                    let Size {width, height} = self.viewport_size;
                    (width as f64, height as f64)
                };

                let cx = if self.x_axis_motion_inverted { sw - x } else { x };
                let cy = if self.y_axis_motion_inverted { sh - y } else { y };

                Motion::MouseCursor(cx, cy)
            },
            Motion::MouseScroll(x, y) => {
                let mx = if self.x_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                let my = if self.y_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                Motion::MouseScroll(x * mx, y * my)
            },
            relative => relative
        }
    }
}

#[derive(Clone, Debug)]
struct KeyMap<A: Action> {
    btn_map: HashMap<ButtonTuple, A>
}

impl<A: Action> KeyMap<A> {
    fn new() -> Self {
        KeyMap {
            btn_map: HashMap::new()
        }
    }

    fn add_mapping(&mut self, button: Button, action: A) {
        let mut bt = self.get_bindings_for_action(action).unwrap_or(ButtonTuple::new());
        let bt = if bt.insert_inplace(button) {bt} else {ButtonTuple::new()};
        self.btn_map.insert(bt, action);
    }

    fn get_bindings_for_action(&self, action: A) -> Option<ButtonTuple> {
        self.btn_map.iter().find(|&(_, &a)| a == action).map(|(&bt, _)| bt)
    }

    #[allow(dead_code)]
    fn get_ref_bindings_for_action(&self, action: A) -> Option<&ButtonTuple> {
        self.btn_map.iter().find(|&(_, &a)| a == action).map(|(bt, _)| bt)
    }

    #[cfg(unimplemented)] // This gives a compile error
    fn get_ref_bindings_for_action_mut(&mut self, action: A) -> Option<&mut ButtonTuple> {
        self.btn_map.iter_mut().find(|&(_, &mut a)| a == action).as_mut().map(|&mut (bt, _)| bt)
    }

    fn translate(&self, button: Button) -> Option<A> {
        self.btn_map.iter().find(|&(&bt, _)| bt.contains(button)).map(|(_, &a)| a)
    }
}

/// A three-element tuple of Option<Button>. Used as the key of an InputTranslator
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct ButtonTuple(pub Option<Button>, pub Option<Button>, pub Option<Button>);

impl ButtonTuple {
    fn new() -> Self { Default::default() }

    fn contains(&self, btn: Button) -> bool {
        let sbtn = Some(btn);
        self.0 == sbtn || self.1 == sbtn || self.2 == sbtn
    }

    #[allow(dead_code)]
    fn remove_inplace(&mut self, btn: Button) {
        let sbtn = Some(btn);
        if self.0 == sbtn {self.0 = None}
        if self.1 == sbtn {self.1 = None}
        if self.2 == sbtn {self.2 = None}
    }

    #[allow(dead_code)]
    fn replace_inplace(&mut self, btn_idx: u32, btn: Button) -> bool {
        match btn_idx {
            0 => {self.0 = Some(btn); true},
            1 => {self.1 = Some(btn); true},
            2 => {self.2 = Some(btn); true},
            _ => false
        }
    }

    fn insert_inplace(&mut self, btn: Button) -> bool {
        match self {
            &mut ButtonTuple(a, b, c) if a.is_none() => {*self = ButtonTuple(Some(btn), b, c); true},
            &mut ButtonTuple(a, b, c) if b.is_none() => {*self = ButtonTuple(a, Some(btn), c); true},
            &mut ButtonTuple(a, b, c) if c.is_none() => {*self = ButtonTuple(a, b, Some(btn)); true}
            _ => false
        }
    }
}

impl Default for ButtonTuple {
    fn default() -> Self { ButtonTuple(None, None, None) }
}
<|endoftext|>


<commit_before>extern crate byteorder;
extern crate chrono;

use std::io::{Write};

use byteorder::{WriteBytesExt};

use chrono::{DateTime, UTC};

#[derive(Clone)]
pub struct ObjectIdentifier {
    data: Vec<u8>
}

fn encode_base128_int(data: &mut Vec<u8>, n: u32) {
    if n == 0 {
        data.push(0);
        return;
    }
    let mut l = 0;
    let mut i = n;
    while i > 0 {
        l += 1;
        i >>= 7;
    }

    for i in (0..l).rev() {
        let mut o = (n >> (i * 7)) as u8;
        o &= 0x7f;
        if i != 0 {
            o |= 0x80;
        }
        data.push(o);
    }
}

impl ObjectIdentifier {
    pub fn new(oid: Vec<u32>) -> Option<ObjectIdentifier> {
        if oid.len() < 2 || oid[0] > 2 || (oid[0] < 2 && oid[1] >= 40) {
            return None;
        }

        let mut data = Vec::new();
        encode_base128_int(&mut data, 40 * oid[0] + oid[1]);
        for el in oid.iter().skip(2) {
            encode_base128_int(&mut data, *el);
        }
        return Some(ObjectIdentifier {
            data: data
        });
    }
}

pub struct Serializer<'a> {
    writer: &'a mut Vec<u8>
}

impl<'a> Serializer<'a> {
    pub fn new(writer: &'a mut Vec<u8>) -> Serializer<'a> {
        return Serializer {
            writer: writer,
        }
    }

    fn _write_length(&mut self, length: usize) {
        assert!(length < 128);
        self.writer.write_u8(length as u8).unwrap();
    }

    fn _write_with_tag<F>(&mut self, tag: u8, body: F) where F: Fn() -> Vec<u8> {
        self.writer.write_u8(tag).unwrap();
        let body = body();
        self._write_length(body.len());
        self.writer.write_all(&body).unwrap();
    }

    pub fn write_bool(&mut self, v: bool) {
        return self._write_with_tag(1, || {
            if v {
                return b"\xff".to_vec();
            } else {
                return b"\x00".to_vec();
            }
        })
    }

    fn _int_length(&self, v: i64) -> usize {
        let mut num_bytes = 1;
        let mut i = v;

        while i > 127 || i < -128 {
            num_bytes += 1;
            i >>= 8;
        }
        return num_bytes;
    }

    pub fn write_int(&mut self, v: i64) {
        let n = self._int_length(v);
        return self._write_with_tag(2, || {
            let mut result = Vec::with_capacity(n);
            for i in (1..n+1).rev() {
                result.push((v >> ((i - 1) * 8)) as u8);
            }
            return result;
        })
    }

    pub fn write_octet_string(&mut self, v: &Vec<u8>) {
        return self._write_with_tag(4, || {
            return v.to_vec();
        })
    }

    pub fn write_object_identifier(&mut self, v: ObjectIdentifier) {
        return self._write_with_tag(6, || {
            return v.data.to_vec();
        })
    }

    pub fn write_utctime(&mut self, v: DateTime<UTC>) {
        return self._write_with_tag(23, || {
            return format!("{}", v.format("%y%m%d%H%M%SZ")).into_bytes();
        });
    }

    pub fn write_sequence<F>(&mut self, v: F) where F: Fn(&mut Serializer) {
        return self._write_with_tag(48, || {
            return to_vec(&v);
        });
    }
}

pub fn to_vec<F>(f: F) -> Vec<u8> where F: Fn(&mut Serializer) {
    let mut out = Vec::new();
    {
        let mut serializer = Serializer::new(&mut out);
        f(&mut serializer);
    }
    return out;
}

#[cfg(test)]
mod tests {
    use chrono::{TimeZone, UTC};

    use super::{ObjectIdentifier, Serializer, to_vec};

    fn assert_serializes<T, F>(values: Vec<(T, Vec<u8>)>, f: F)
            where T: Clone,  F: Fn(&mut Serializer, T) {
        for (value, expected) in values {
            let out = to_vec(|s| f(s, value.clone()));
            assert_eq!(out, expected);
        }
    }

    #[test]
    fn test_write_bool() {
        assert_serializes(vec![
            (true, b"\x01\x01\xff".to_vec()),
            (false, b"\x01\x01\x00".to_vec()),
        ], |serializer, v| {
            serializer.write_bool(v);
        });
    }

    #[test]
    fn test_write_int() {
        assert_serializes(vec![
            (0, b"\x02\x01\x00".to_vec()),
            (127, b"\x02\x01\x7f".to_vec()),
            (128, b"\x02\x02\x00\x80".to_vec()),
            (256, b"\x02\x02\x01\x00".to_vec()),
            (-128, b"\x02\x01\x80".to_vec()),
            (-129, b"\x02\x02\xff\x7f".to_vec()),
        ], |serializer, v| {
            serializer.write_int(v);
        })
    }

    #[test]
    fn test_write_octet_string() {
        assert_serializes(vec![
            (b"\x01\x02\x03".to_vec(), b"\x04\x03\x01\x02\x03".to_vec()),
        ], |serializer, v| {
            serializer.write_octet_string(&v);
        })
    }

    #[test]
    fn test_write_object_identifier() {
        assert_serializes(vec![
            (
                ObjectIdentifier::new(vec![1, 2, 840, 113549]).unwrap(),
                b"\x06\x06\x2a\x86\x48\x86\xf7\x0d".to_vec()
            ),
            (
                ObjectIdentifier::new(vec![1, 2, 3, 4]).unwrap(),
                b"\x06\x03\x2a\x03\x04".to_vec(),
            ),
            (
                ObjectIdentifier::new(vec![1, 2, 840, 133549, 1, 1, 5]).unwrap(),
                b"\x06\x09\x2a\x86\x48\x88\x93\x2d\x01\x01\x05".to_vec(),
            ),
            (
                ObjectIdentifier::new(vec![2, 100, 3]).unwrap(),
                b"\x06\x03\x81\x34\x03".to_vec(),
            ),
        ], |serializer, oid| {
            serializer.write_object_identifier(oid);
        })
    }

    #[test]
    fn test_write_utctime() {
        assert_serializes(vec![
            (
                UTC.ymd(1991, 5, 6).and_hms(23, 45, 40),
                b"\x17\x0d\x39\x31\x30\x35\x30\x36\x32\x33\x34\x35\x34\x30\x5a".to_vec(),
            ),
            (
                UTC.timestamp(0, 0),
                b"\x17\x0d\x37\x30\x30\x31\x30\x31\x30\x30\x30\x30\x30\x30\x5a".to_vec(),
            ),
            (
                UTC.timestamp(1258325776, 0),
                b"\x17\x0d\x30\x39\x31\x31\x31\x35\x32\x32\x35\x36\x31\x36\x5a".to_vec(),
            ),
        ], |serializer, v| {
            serializer.write_utctime(v);
        });
    }

    #[test]
    fn test_write_sequence() {
        assert_serializes(vec![
            ((1, 2), b"\x30\x06\x02\x01\x01\x02\x01\x02".to_vec()),
        ], |serializer, (x, y)| {
            serializer.write_sequence(|s| {
                s.write_int(x);
                s.write_int(y);
            });
        })
    }
}
<commit_msg>added printable string and encoding of objects longer than 128 bytes<commit_after>extern crate byteorder;
extern crate chrono;

use std::ascii::{AsciiExt};
use std::io::{Write};

use byteorder::{WriteBytesExt};

use chrono::{DateTime, UTC};

#[derive(Clone)]
pub struct ObjectIdentifier {
    data: Vec<u8>
}

fn encode_base128_int(data: &mut Vec<u8>, n: u32) {
    if n == 0 {
        data.push(0);
        return;
    }
    let mut l = 0;
    let mut i = n;
    while i > 0 {
        l += 1;
        i >>= 7;
    }

    for i in (0..l).rev() {
        let mut o = (n >> (i * 7)) as u8;
        o &= 0x7f;
        if i != 0 {
            o |= 0x80;
        }
        data.push(o);
    }
}

impl ObjectIdentifier {
    pub fn new(oid: Vec<u32>) -> Option<ObjectIdentifier> {
        if oid.len() < 2 || oid[0] > 2 || (oid[0] < 2 && oid[1] >= 40) {
            return None;
        }

        let mut data = Vec::new();
        encode_base128_int(&mut data, 40 * oid[0] + oid[1]);
        for el in oid.iter().skip(2) {
            encode_base128_int(&mut data, *el);
        }
        return Some(ObjectIdentifier {
            data: data
        });
    }
}

pub struct Serializer<'a> {
    writer: &'a mut Vec<u8>
}

impl<'a> Serializer<'a> {
    pub fn new(writer: &'a mut Vec<u8>) -> Serializer<'a> {
        return Serializer {
            writer: writer,
        }
    }

    fn _length_length(&self, length: usize) -> usize {
        let mut i = length;
        let mut num_bytes = 1;
        while i > 255 {
            num_bytes += 1;
            i >>= 8;
        }
        return num_bytes;
    }

    fn _write_length(&mut self, length: usize) {
        if length >= 128 {
            let n = self._length_length(length);
            self.writer.write_u8(0x80 | (n as u8)).unwrap();
            for i in (1..n+1).rev() {
                self.writer.write_u8((length >> ((i - 1) * 8)) as u8).unwrap();
            }
        } else {
            self.writer.write_u8(length as u8).unwrap();
        }
    }

    fn _write_with_tag<F>(&mut self, tag: u8, body: F) where F: Fn() -> Vec<u8> {
        self.writer.write_u8(tag).unwrap();
        let body = body();
        self._write_length(body.len());
        self.writer.write_all(&body).unwrap();
    }

    pub fn write_bool(&mut self, v: bool) {
        return self._write_with_tag(1, || {
            if v {
                return b"\xff".to_vec();
            } else {
                return b"\x00".to_vec();
            }
        })
    }

    fn _int_length(&self, v: i64) -> usize {
        let mut num_bytes = 1;
        let mut i = v;

        while i > 127 || i < -128 {
            num_bytes += 1;
            i >>= 8;
        }
        return num_bytes;
    }

    pub fn write_int(&mut self, v: i64) {
        let n = self._int_length(v);
        return self._write_with_tag(2, || {
            let mut result = Vec::with_capacity(n);
            for i in (1..n+1).rev() {
                result.push((v >> ((i - 1) * 8)) as u8);
            }
            return result;
        })
    }

    pub fn write_octet_string(&mut self, v: &Vec<u8>) {
        return self._write_with_tag(4, || {
            return v.to_vec();
        })
    }

    pub fn write_printable_string(&mut self, v: String) {
        for c in v.chars() {
            if !c.is_ascii() || (
                !c.is_uppercase() &&
                !c.is_lowercase() &&
                !c.is_digit(10) &&
                ![' ', '\'', '(', ')', '+', ',', '-', '.', '/', ':', '=', '?'].contains(&c)
            ) {
                panic!("Non-printable characters.")
            }
        }
        return self._write_with_tag(19, || {
            return v.as_bytes().to_vec();
        });
    }

    pub fn write_object_identifier(&mut self, v: ObjectIdentifier) {
        return self._write_with_tag(6, || {
            return v.data.to_vec();
        })
    }

    pub fn write_utctime(&mut self, v: DateTime<UTC>) {
        return self._write_with_tag(23, || {
            return format!("{}", v.format("%y%m%d%H%M%SZ")).into_bytes();
        });
    }

    pub fn write_sequence<F>(&mut self, v: F) where F: Fn(&mut Serializer) {
        return self._write_with_tag(48, || {
            return to_vec(&v);
        });
    }
}

pub fn to_vec<F>(f: F) -> Vec<u8> where F: Fn(&mut Serializer) {
    let mut out = Vec::new();
    {
        let mut serializer = Serializer::new(&mut out);
        f(&mut serializer);
    }
    return out;
}

#[cfg(test)]
mod tests {
    use chrono::{TimeZone, UTC};

    use super::{ObjectIdentifier, Serializer, to_vec};

    fn assert_serializes<T, F>(values: Vec<(T, Vec<u8>)>, f: F)
            where T: Clone,  F: Fn(&mut Serializer, T) {
        for (value, expected) in values {
            let out = to_vec(|s| f(s, value.clone()));
            assert_eq!(out, expected);
        }
    }

    #[test]
    fn test_write_bool() {
        assert_serializes(vec![
            (true, b"\x01\x01\xff".to_vec()),
            (false, b"\x01\x01\x00".to_vec()),
        ], |serializer, v| {
            serializer.write_bool(v);
        });
    }

    #[test]
    fn test_write_int() {
        assert_serializes(vec![
            (0, b"\x02\x01\x00".to_vec()),
            (127, b"\x02\x01\x7f".to_vec()),
            (128, b"\x02\x02\x00\x80".to_vec()),
            (256, b"\x02\x02\x01\x00".to_vec()),
            (-128, b"\x02\x01\x80".to_vec()),
            (-129, b"\x02\x02\xff\x7f".to_vec()),
        ], |serializer, v| {
            serializer.write_int(v);
        })
    }

    #[test]
    fn test_write_octet_string() {
        assert_serializes(vec![
            (b"\x01\x02\x03".to_vec(), b"\x04\x03\x01\x02\x03".to_vec()),
        ], |serializer, v| {
            serializer.write_octet_string(&v);
        })
    }

    #[test]
    fn test_printable_string() {
        assert_serializes(vec![
            (
                "Test User 1".to_string(),
                b"\x13\x0b\x54\x65\x73\x74\x20\x55\x73\x65\x72\x20\x31".to_vec()
            ),
            (
                "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx".to_string(),
                b"\x13\x81\x80\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78".to_vec()
            ),
        ], |serializer, v| {
            serializer.write_printable_string(v);
        })
    }

    #[test]
    fn test_write_object_identifier() {
        assert_serializes(vec![
            (
                ObjectIdentifier::new(vec![1, 2, 840, 113549]).unwrap(),
                b"\x06\x06\x2a\x86\x48\x86\xf7\x0d".to_vec()
            ),
            (
                ObjectIdentifier::new(vec![1, 2, 3, 4]).unwrap(),
                b"\x06\x03\x2a\x03\x04".to_vec(),
            ),
            (
                ObjectIdentifier::new(vec![1, 2, 840, 133549, 1, 1, 5]).unwrap(),
                b"\x06\x09\x2a\x86\x48\x88\x93\x2d\x01\x01\x05".to_vec(),
            ),
            (
                ObjectIdentifier::new(vec![2, 100, 3]).unwrap(),
                b"\x06\x03\x81\x34\x03".to_vec(),
            ),
        ], |serializer, oid| {
            serializer.write_object_identifier(oid);
        })
    }

    #[test]
    fn test_write_utctime() {
        assert_serializes(vec![
            (
                UTC.ymd(1991, 5, 6).and_hms(23, 45, 40),
                b"\x17\x0d\x39\x31\x30\x35\x30\x36\x32\x33\x34\x35\x34\x30\x5a".to_vec(),
            ),
            (
                UTC.timestamp(0, 0),
                b"\x17\x0d\x37\x30\x30\x31\x30\x31\x30\x30\x30\x30\x30\x30\x5a".to_vec(),
            ),
            (
                UTC.timestamp(1258325776, 0),
                b"\x17\x0d\x30\x39\x31\x31\x31\x35\x32\x32\x35\x36\x31\x36\x5a".to_vec(),
            ),
        ], |serializer, v| {
            serializer.write_utctime(v);
        });
    }

    #[test]
    fn test_write_sequence() {
        assert_serializes(vec![
            ((1, 2), b"\x30\x06\x02\x01\x01\x02\x01\x02".to_vec()),
        ], |serializer, (x, y)| {
            serializer.write_sequence(|s| {
                s.write_int(x);
                s.write_int(y);
            });
        })
    }
}
<|endoftext|>


<commit_before>//! `textwrap` provides functions for word wrapping and filling text.

extern crate unicode_width;

use std::iter;
use unicode_width::UnicodeWidthStr;

/// A Wrapper holds settings for wrapping text.
pub struct Wrapper {
    width: usize,
}

impl Wrapper {
    /// Create a new Wrapper for wrapping at the specified width.
    pub fn new(width: usize) -> Wrapper {
        Wrapper { width: width }
    }

    /// Fill a line of text at `self.width` characters. Strings are
    /// wrapped based on their displayed width, not their size in
    /// bytes.
    ///
    /// The result is a string with newlines between each line. Use
    /// the `wrap` method if you need access to the individual lines.
    ///
    /// ```
    /// use textwrap::Wrapper;
    ///
    /// let wrapper = Wrapper::new(15);
    /// assert_eq!(wrapper.fill("Memory safety without garbage collection."),
    ///            "Memory safety\nwithout garbage\ncollection.");
    /// ```
    pub fn fill(&self, s: &str) -> String {
        self.wrap(&s).join("\n")
    }

    /// Wrap  a line of  text at `self.width` characters.  Strings are
    ///  wrapped based  on their  displayed width,  not their  size in
    /// bytes.
    ///
    /// ```
    /// use textwrap::Wrapper;
    ///
    /// let wrap15 = Wrapper::new(15);
    /// assert_eq!(wrap15.wrap("Concurrency without data races."),
    ///            vec!["Concurrency",
    ///                 "without data",
    ///                 "races."]);
    ///
    /// let wrap20 = Wrapper::new(20);
    /// assert_eq!(wrap20.wrap("Concurrency without data races."),
    ///            vec!["Concurrency without",
    ///                 "data races."]);
    /// ```
    pub fn wrap(&self, s: &str) -> Vec<String> {
        let mut result = Vec::new();
        let mut line = Vec::new();
        let mut line_width = 0;

        for mut word in s.split_whitespace() {
            while !word.is_empty() {
                let splits = split_word(&word);
                let (smallest, longest) = splits[0];
                let min_width = smallest.width();

                // Add a new line if even the smallest split doesn't
                // fit.
                if !line.is_empty() && line_width + line.len() + min_width > self.width {
                    result.push(line.join(" "));
                    line = Vec::new();
                    line_width = 0;
                }

                // Find a split that fits on the current line.
                for &(head, tail) in splits.iter().rev() {
                    if line_width + line.len() + head.width() <= self.width {
                        line.push(head);
                        line_width += head.width();
                        word = tail;
                        break;
                    }
                }

                // If nothing got added, we forcibly add the smallest
                // split and continue with the longest tail.
                if line_width == 0 {
                    result.push(String::from(smallest));
                    line_width = 0;
                    word = longest;
                }
            }
        }
        if !line.is_empty() {
            result.push(line.join(" "));
        }
        return result;
    }
}

/// Fill a line of text at `width` characters. Strings are wrapped
/// based on their displayed width, not their size in bytes.
///
/// The result is a string with newlines between each line. Use `wrap`
/// if you need access to the individual lines.
///
/// ```
/// use textwrap::fill;
///
/// assert_eq!(fill("Memory safety without garbage collection.", 15),
///            "Memory safety\nwithout garbage\ncollection.");
/// ```
///
/// This function creates a Wrapper on the fly. If you need to wrap
/// many strings, it can be more efficient to create a single Wrapper
/// and call its [`fill` method](struct.Wrapper.html#method.fill).
pub fn fill(s: &str, width: usize) -> String {
    wrap(s, width).join("\n")
}

/// Wrap a line of text at `width` characters. Strings are wrapped
/// based on their displayed width, not their size in bytes.
///
/// ```
/// use textwrap::wrap;
///
/// assert_eq!(wrap("Concurrency without data races.", 15),
///            vec!["Concurrency",
///                 "without data",
///                 "races."]);
///
/// assert_eq!(wrap("Concurrency without data races.", 20),
///            vec!["Concurrency without",
///                 "data races."]);
/// ```
///
/// This function creates a Wrapper on the fly. If you need to wrap
/// many strings, it can be more efficient to create a single Wrapper
/// and call its [`wrap` method](struct.Wrapper.html#method.wrap).
pub fn wrap(s: &str, width: usize) -> Vec<String> {
    Wrapper::new(width).wrap(s)
}

/// Split word into all possible parts (head, tail). Word must be
/// non-empty. The returned vector will always be non-empty.
fn split_word(word: &str) -> Vec<(&str, &str)> {
    let hyphens = word.match_indices('-');
    let word_end = iter::once((word.len() - 1, ""));
    return hyphens.chain(word_end)
        .map(|(n, _)| word.split_at(n + 1))
        .collect();
}

/// Add prefix to each non-empty line.
///
/// ```
/// use textwrap::indent;
///
/// assert_eq!(indent("Foo\nBar\n", "  "), "  Foo\n  Bar\n");
/// ```
///
/// Empty lines (lines consisting only of whitespace) are not indented
/// and the whitespace is replaced by a single newline (`\n`):
///
/// ```
/// use textwrap::indent;
///
/// assert_eq!(indent("Foo\n\nBar\n  \t  \nBaz\n", "  "),
///            "  Foo\n\n  Bar\n\n  Baz\n");
/// ```
///
/// Leading and trailing whitespace on non-empty lines is kept
/// unchanged:
///
/// ```
/// use textwrap::indent;
///
/// assert_eq!(indent(" \t  Foo   ", "  "), "   \t  Foo   \n");
/// ```
pub fn indent(s: &str, prefix: &str) -> String {
    let mut result = String::new();
    for line in s.lines() {
        if line.chars().any(|c| !c.is_whitespace()) {
            result.push_str(prefix);
            result.push_str(line);
        }
        result.push('\n');
    }
    return result;
}

/// Removes common leading whitespace from each line.
///
/// This will look at each non-empty line and determine the maximum
/// amount of whitespace that can be removed from the line.
///
/// ```
/// use textwrap::dedent;
///
/// assert_eq!(dedent("  1st line\n  2nd line\n"),
///            "1st line\n2nd line\n");
/// ```
pub fn dedent(s: &str) -> String {
    let mut prefix = String::new();
    let mut lines = s.lines();

    // We first search for a non-empty line to find a prefix.
    for line in &mut lines {
        let whitespace = line.chars()
            .take_while(|c| c.is_whitespace())
            .collect::<String>();
        // Check if the line had anything but whitespace
        if whitespace.len() < line.len() {
            prefix = whitespace;
            break;
        }
    }

    // We then continue looking through the remaining lines to
    // possibly shorten the prefix.
    for line in &mut lines {
        let whitespace = line.chars()
            .zip(prefix.chars())
            .take_while(|&(a, b)| a == b)
            .map(|(_, b)| b)
            .collect::<String>();
        // Check if we have found a shorter prefix
        if whitespace.len() < prefix.len() {
            prefix = whitespace;
        }
    }

    // We now go over the lines a second time to build the result.
    let mut result = String::new();
    for line in s.lines() {
        if line.starts_with(&prefix) && line.chars().any(|c| !c.is_whitespace()) {
            let (_, tail) = line.split_at(prefix.len());
            result.push_str(tail);
        }
        result.push('\n');
    }
    return result;
}

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

    /// Add newlines. Ensures that the final line in the vector also
    /// has a newline.
    fn add_nl(lines: &Vec<&str>) -> String {
        lines.join("\n") + "\n"
    }

    #[test]
    fn no_wrap() {
        assert_eq!(wrap("foo", 10), vec!["foo"]);
    }

    #[test]
    fn simple() {
        assert_eq!(wrap("foo bar baz", 5), vec!["foo", "bar", "baz"]);
    }

    #[test]
    fn multi_word_on_line() {
        assert_eq!(wrap("foo bar baz", 10), vec!["foo bar", "baz"]);
    }

    #[test]
    fn long_word() {
        assert_eq!(wrap("foo", 0), vec!["foo"]);
    }

    #[test]
    fn long_words() {
        assert_eq!(wrap("foo bar", 0), vec!["foo", "bar"]);
    }

    #[test]
    fn whitespace_is_squeezed() {
        assert_eq!(wrap(" foo \t  bar  ", 10), vec!["foo bar"]);
    }

    #[test]
    fn wide_character_handling() {
        assert_eq!(wrap("Hello, World!", 15), vec!["Hello, World!"]);
        assert_eq!(wrap("Ｈｅｌｌｏ, Ｗｏｒｌｄ!", 15),
                   vec!["Ｈｅｌｌｏ,", "Ｗｏｒｌｄ!"]);
    }

    #[test]
    fn hyphens() {
        assert_eq!(wrap("foo-bar", 5), vec!["foo-", "bar"]);
    }

    #[test]
    fn trailing_hyphen() {
        assert_eq!(wrap("foobar-", 5), vec!["foobar-"]);
    }

    #[test]
    fn multiple_hyphens() {
        assert_eq!(wrap("foo-bar-baz", 5), vec!["foo-", "bar-", "baz"]);
    }

    #[test]
    fn multiple_splits() {
        assert_eq!(wrap("foo-bar-baz", 9), vec!["foo-bar-", "baz"]);
    }

    #[test]
    fn forced_split() {
        assert_eq!(wrap("foobar-baz", 5), vec!["foobar-", "baz"]);
    }

    #[test]
    fn test_fill() {
        assert_eq!(fill("foo bar baz", 10), "foo bar\nbaz");
    }

    #[test]
    fn test_indent_empty() {
        assert_eq!(indent("\n", "  "), "\n");
    }

    #[test]
    #[cfg_attr(rustfmt, rustfmt_skip)]
    fn test_indent_nonempty() {
        let x = vec!["  foo",
                     "bar",
                     "  baz"];
        let y = vec!["//  foo",
                     "//bar",
                     "//  baz"];
        assert_eq!(indent(&add_nl(&x), "//"), add_nl(&y));
    }

    #[test]
    #[cfg_attr(rustfmt, rustfmt_skip)]
    fn test_indent_empty_line() {
        let x = vec!["  foo",
                     "bar",
                     "",
                     "  baz"];
        let y = vec!["//  foo",
                     "//bar",
                     "",
                     "//  baz"];
        assert_eq!(indent(&add_nl(&x), "//"), add_nl(&y));
    }

    #[test]
    fn test_dedent_empty() {
        assert_eq!(dedent(""), "");
    }

    #[test]
    #[cfg_attr(rustfmt, rustfmt_skip)]
    fn test_dedent_multi_line() {
        let x = vec!["    foo",
                     "  bar",
                     "    baz"];
        let y = vec!["  foo",
                     "bar",
                     "  baz"];
        assert_eq!(dedent(&add_nl(&x)), add_nl(&y));
    }

    #[test]
    #[cfg_attr(rustfmt, rustfmt_skip)]
    fn test_dedent_empty_line() {
        let x = vec!["    foo",
                     "  bar",
                     "   ",
                     "    baz"];
        let y = vec!["  foo",
                     "bar",
                     "",
                     "  baz"];
        assert_eq!(dedent(&add_nl(&x)), add_nl(&y));
    }

    #[test]
    #[cfg_attr(rustfmt, rustfmt_skip)]
    fn test_dedent_mixed_whitespace() {
        let x = vec!["\tfoo",
                     "  bar"];
        let y = vec!["\tfoo",
                     "  bar"];
        assert_eq!(dedent(&add_nl(&x)), add_nl(&y));
    }
}
<commit_msg>Wrapper: make split_word a method<commit_after>//! `textwrap` provides functions for word wrapping and filling text.

extern crate unicode_width;

use std::iter;
use unicode_width::UnicodeWidthStr;

/// A Wrapper holds settings for wrapping text.
pub struct Wrapper {
    width: usize,
}

impl Wrapper {
    /// Create a new Wrapper for wrapping at the specified width.
    pub fn new(width: usize) -> Wrapper {
        Wrapper { width: width }
    }

    /// Fill a line of text at `self.width` characters. Strings are
    /// wrapped based on their displayed width, not their size in
    /// bytes.
    ///
    /// The result is a string with newlines between each line. Use
    /// the `wrap` method if you need access to the individual lines.
    ///
    /// ```
    /// use textwrap::Wrapper;
    ///
    /// let wrapper = Wrapper::new(15);
    /// assert_eq!(wrapper.fill("Memory safety without garbage collection."),
    ///            "Memory safety\nwithout garbage\ncollection.");
    /// ```
    pub fn fill(&self, s: &str) -> String {
        self.wrap(&s).join("\n")
    }

    /// Wrap  a line of  text at `self.width` characters.  Strings are
    ///  wrapped based  on their  displayed width,  not their  size in
    /// bytes.
    ///
    /// ```
    /// use textwrap::Wrapper;
    ///
    /// let wrap15 = Wrapper::new(15);
    /// assert_eq!(wrap15.wrap("Concurrency without data races."),
    ///            vec!["Concurrency",
    ///                 "without data",
    ///                 "races."]);
    ///
    /// let wrap20 = Wrapper::new(20);
    /// assert_eq!(wrap20.wrap("Concurrency without data races."),
    ///            vec!["Concurrency without",
    ///                 "data races."]);
    /// ```
    pub fn wrap(&self, s: &str) -> Vec<String> {
        let mut result = Vec::new();
        let mut line = Vec::new();
        let mut line_width = 0;

        for mut word in s.split_whitespace() {
            while !word.is_empty() {
                let splits = self.split_word(&word);
                let (smallest, longest) = splits[0];
                let min_width = smallest.width();

                // Add a new line if even the smallest split doesn't
                // fit.
                if !line.is_empty() && line_width + line.len() + min_width > self.width {
                    result.push(line.join(" "));
                    line = Vec::new();
                    line_width = 0;
                }

                // Find a split that fits on the current line.
                for &(head, tail) in splits.iter().rev() {
                    if line_width + line.len() + head.width() <= self.width {
                        line.push(head);
                        line_width += head.width();
                        word = tail;
                        break;
                    }
                }

                // If nothing got added, we forcibly add the smallest
                // split and continue with the longest tail.
                if line_width == 0 {
                    result.push(String::from(smallest));
                    line_width = 0;
                    word = longest;
                }
            }
        }
        if !line.is_empty() {
            result.push(line.join(" "));
        }
        return result;
    }

    /// Split word into all possible parts (head, tail). Word must be
    /// non-empty. The returned vector will always be non-empty.
    fn split_word<'b>(&self, word: &'b str) -> Vec<(&'b str, &'b str)> {
        let hyphens = word.match_indices('-');
        let word_end = iter::once((word.len() - 1, ""));
        return hyphens.chain(word_end)
            .map(|(n, _)| word.split_at(n + 1))
            .collect();
    }
}

/// Fill a line of text at `width` characters. Strings are wrapped
/// based on their displayed width, not their size in bytes.
///
/// The result is a string with newlines between each line. Use `wrap`
/// if you need access to the individual lines.
///
/// ```
/// use textwrap::fill;
///
/// assert_eq!(fill("Memory safety without garbage collection.", 15),
///            "Memory safety\nwithout garbage\ncollection.");
/// ```
///
/// This function creates a Wrapper on the fly. If you need to wrap
/// many strings, it can be more efficient to create a single Wrapper
/// and call its [`fill` method](struct.Wrapper.html#method.fill).
pub fn fill(s: &str, width: usize) -> String {
    wrap(s, width).join("\n")
}

/// Wrap a line of text at `width` characters. Strings are wrapped
/// based on their displayed width, not their size in bytes.
///
/// ```
/// use textwrap::wrap;
///
/// assert_eq!(wrap("Concurrency without data races.", 15),
///            vec!["Concurrency",
///                 "without data",
///                 "races."]);
///
/// assert_eq!(wrap("Concurrency without data races.", 20),
///            vec!["Concurrency without",
///                 "data races."]);
/// ```
///
/// This function creates a Wrapper on the fly. If you need to wrap
/// many strings, it can be more efficient to create a single Wrapper
/// and call its [`wrap` method](struct.Wrapper.html#method.wrap).
pub fn wrap(s: &str, width: usize) -> Vec<String> {
    Wrapper::new(width).wrap(s)
}

/// Add prefix to each non-empty line.
///
/// ```
/// use textwrap::indent;
///
/// assert_eq!(indent("Foo\nBar\n", "  "), "  Foo\n  Bar\n");
/// ```
///
/// Empty lines (lines consisting only of whitespace) are not indented
/// and the whitespace is replaced by a single newline (`\n`):
///
/// ```
/// use textwrap::indent;
///
/// assert_eq!(indent("Foo\n\nBar\n  \t  \nBaz\n", "  "),
///            "  Foo\n\n  Bar\n\n  Baz\n");
/// ```
///
/// Leading and trailing whitespace on non-empty lines is kept
/// unchanged:
///
/// ```
/// use textwrap::indent;
///
/// assert_eq!(indent(" \t  Foo   ", "  "), "   \t  Foo   \n");
/// ```
pub fn indent(s: &str, prefix: &str) -> String {
    let mut result = String::new();
    for line in s.lines() {
        if line.chars().any(|c| !c.is_whitespace()) {
            result.push_str(prefix);
            result.push_str(line);
        }
        result.push('\n');
    }
    return result;
}

/// Removes common leading whitespace from each line.
///
/// This will look at each non-empty line and determine the maximum
/// amount of whitespace that can be removed from the line.
///
/// ```
/// use textwrap::dedent;
///
/// assert_eq!(dedent("  1st line\n  2nd line\n"),
///            "1st line\n2nd line\n");
/// ```
pub fn dedent(s: &str) -> String {
    let mut prefix = String::new();
    let mut lines = s.lines();

    // We first search for a non-empty line to find a prefix.
    for line in &mut lines {
        let whitespace = line.chars()
            .take_while(|c| c.is_whitespace())
            .collect::<String>();
        // Check if the line had anything but whitespace
        if whitespace.len() < line.len() {
            prefix = whitespace;
            break;
        }
    }

    // We then continue looking through the remaining lines to
    // possibly shorten the prefix.
    for line in &mut lines {
        let whitespace = line.chars()
            .zip(prefix.chars())
            .take_while(|&(a, b)| a == b)
            .map(|(_, b)| b)
            .collect::<String>();
        // Check if we have found a shorter prefix
        if whitespace.len() < prefix.len() {
            prefix = whitespace;
        }
    }

    // We now go over the lines a second time to build the result.
    let mut result = String::new();
    for line in s.lines() {
        if line.starts_with(&prefix) && line.chars().any(|c| !c.is_whitespace()) {
            let (_, tail) = line.split_at(prefix.len());
            result.push_str(tail);
        }
        result.push('\n');
    }
    return result;
}

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

    /// Add newlines. Ensures that the final line in the vector also
    /// has a newline.
    fn add_nl(lines: &Vec<&str>) -> String {
        lines.join("\n") + "\n"
    }

    #[test]
    fn no_wrap() {
        assert_eq!(wrap("foo", 10), vec!["foo"]);
    }

    #[test]
    fn simple() {
        assert_eq!(wrap("foo bar baz", 5), vec!["foo", "bar", "baz"]);
    }

    #[test]
    fn multi_word_on_line() {
        assert_eq!(wrap("foo bar baz", 10), vec!["foo bar", "baz"]);
    }

    #[test]
    fn long_word() {
        assert_eq!(wrap("foo", 0), vec!["foo"]);
    }

    #[test]
    fn long_words() {
        assert_eq!(wrap("foo bar", 0), vec!["foo", "bar"]);
    }

    #[test]
    fn whitespace_is_squeezed() {
        assert_eq!(wrap(" foo \t  bar  ", 10), vec!["foo bar"]);
    }

    #[test]
    fn wide_character_handling() {
        assert_eq!(wrap("Hello, World!", 15), vec!["Hello, World!"]);
        assert_eq!(wrap("Ｈｅｌｌｏ, Ｗｏｒｌｄ!", 15),
                   vec!["Ｈｅｌｌｏ,", "Ｗｏｒｌｄ!"]);
    }

    #[test]
    fn hyphens() {
        assert_eq!(wrap("foo-bar", 5), vec!["foo-", "bar"]);
    }

    #[test]
    fn trailing_hyphen() {
        assert_eq!(wrap("foobar-", 5), vec!["foobar-"]);
    }

    #[test]
    fn multiple_hyphens() {
        assert_eq!(wrap("foo-bar-baz", 5), vec!["foo-", "bar-", "baz"]);
    }

    #[test]
    fn multiple_splits() {
        assert_eq!(wrap("foo-bar-baz", 9), vec!["foo-bar-", "baz"]);
    }

    #[test]
    fn forced_split() {
        assert_eq!(wrap("foobar-baz", 5), vec!["foobar-", "baz"]);
    }

    #[test]
    fn test_fill() {
        assert_eq!(fill("foo bar baz", 10), "foo bar\nbaz");
    }

    #[test]
    fn test_indent_empty() {
        assert_eq!(indent("\n", "  "), "\n");
    }

    #[test]
    #[cfg_attr(rustfmt, rustfmt_skip)]
    fn test_indent_nonempty() {
        let x = vec!["  foo",
                     "bar",
                     "  baz"];
        let y = vec!["//  foo",
                     "//bar",
                     "//  baz"];
        assert_eq!(indent(&add_nl(&x), "//"), add_nl(&y));
    }

    #[test]
    #[cfg_attr(rustfmt, rustfmt_skip)]
    fn test_indent_empty_line() {
        let x = vec!["  foo",
                     "bar",
                     "",
                     "  baz"];
        let y = vec!["//  foo",
                     "//bar",
                     "",
                     "//  baz"];
        assert_eq!(indent(&add_nl(&x), "//"), add_nl(&y));
    }

    #[test]
    fn test_dedent_empty() {
        assert_eq!(dedent(""), "");
    }

    #[test]
    #[cfg_attr(rustfmt, rustfmt_skip)]
    fn test_dedent_multi_line() {
        let x = vec!["    foo",
                     "  bar",
                     "    baz"];
        let y = vec!["  foo",
                     "bar",
                     "  baz"];
        assert_eq!(dedent(&add_nl(&x)), add_nl(&y));
    }

    #[test]
    #[cfg_attr(rustfmt, rustfmt_skip)]
    fn test_dedent_empty_line() {
        let x = vec!["    foo",
                     "  bar",
                     "   ",
                     "    baz"];
        let y = vec!["  foo",
                     "bar",
                     "",
                     "  baz"];
        assert_eq!(dedent(&add_nl(&x)), add_nl(&y));
    }

    #[test]
    #[cfg_attr(rustfmt, rustfmt_skip)]
    fn test_dedent_mixed_whitespace() {
        let x = vec!["\tfoo",
                     "  bar"];
        let y = vec!["\tfoo",
                     "  bar"];
        assert_eq!(dedent(&add_nl(&x)), add_nl(&y));
    }
}
<|endoftext|>


<commit_before>extern crate euclid;

use std::mem;
use std::ops::Range;
use std::collections::HashMap;
use euclid::{Rect, Point2D, Size2D};

/// An immediate mode graphical user interface context.
///
/// The context persists over a frame and receives commands that combine GUI
/// description and input handling. At the end of the frame, the commands are
/// converted into rendering instructions for the GUI.
pub struct Context<T, V> {
    draw_list: Vec<DrawBatch<T, V>>,
    /// Texture value used for solid-color drawing
    solid_texture: T,

    // TODO: This is for demo purposes, need a proper layout state.
    layout_pos: Point2D<f32>,

    mouse_pos: Point2D<f32>,
    click_state: ClickState,

    fonts: Vec<FontData<T>>,

    text_input: Vec<KeyInput>,

    tick: u64,
}

impl<T, V: Vertex> Context<T, V>
    where T: Clone + PartialEq
{
    /// Construct a new interface context instance.
    ///
    /// The client must provide an initial texture instance that is used for
    /// drawing solid shapes. This can be a texture that consists of a single
    /// opaque white pixel.
    pub fn new(solid_texture: T) -> Context<T, V> {
        Context {
            draw_list: Vec::new(),
            solid_texture: solid_texture,

            layout_pos: Point2D::new(0.0, 0.0),

            mouse_pos: Point2D::new(0.0, 0.0),
            click_state: ClickState::Unpressed,

            fonts: Vec::new(),

            text_input: Vec::new(),

            tick: 0,
        }
    }

    pub fn begin_frame(&mut self) {
        self.tick += 1;

        self.layout_pos = Point2D::new(10.0, 10.0);

        // TODO
    }

    pub fn draw_text(&mut self, font: Font, mut pos: Point2D<f32>, color: [f32; 4], text: &str) {
        assert!(self.fonts.len() >= font.0);
        let id = font.0;
        let t = self.fonts[id].texture.clone();
        let h = self.fonts[id].height;
        self.start_texture(t);

        for c in text.chars() {
            // FIXME: Gratuitous cloning because of borrow checker.
            let x = self.fonts[id].chars.get(&c).cloned();
            // TODO: Draw some sort of symbol for characters missing from font.
            if let Some(f) = x {
                self.tex_rect(Rect::new(pos - f.draw_offset, Size2D::new(f.advance, h)),
                              f.texcoords,
                              color);
                pos.x += f.advance;
            }
        }
    }

    fn default_font(&self) -> Font {
        Font(0)
    }

    pub fn button(&mut self, caption: &str) -> bool {
        let font = self.default_font();
        let area = self.fonts[font.0]
                       .render_size(caption)
                       .inflate(4.0, 4.0)
                       .translate(&self.layout_pos);

        self.layout_pos.y += area.size.height + 2.0;

        let hover = area.contains(&self.mouse_pos);
        let press = self.click_state.is_pressed() && area.contains(&self.mouse_pos);

        let color = if press {
            [1.0, 1.0, 0.0, 1.0]
        } else if hover {
            [0.5, 1.0, 0.0, 1.0]
        } else {
            [0.0, 1.0, 0.0, 1.0]
        };

        self.fill_rect(area, color);
        self.fill_rect(area.inflate(-1.0, -1.0), [0.0, 0.0, 0.0, 1.0]);
        self.draw_text(font,
                       area.origin + Point2D::new(4.0, area.size.height - 4.0),
                       color,
                       caption);

        press && self.click_state.is_release()
    }

    pub fn tex_rect(&mut self, area: Rect<f32>, texcoords: Rect<f32>, color: [f32; 4]) {
        let (p1, p2) = (area.origin, area.bottom_right());
        let (t1, t2) = (texcoords.origin, texcoords.bottom_right());
        let idx = self.draw_list.len() - 1;
        let batch = &mut self.draw_list[idx];
        let idx_offset = batch.vertices.len() as u16;

        batch.vertices.push(Vertex::new([p1.x, p1.y], color, [t1.x, t1.y]));
        batch.vertices.push(Vertex::new([p2.x, p1.y], color, [t2.x, t1.y]));
        batch.vertices.push(Vertex::new([p2.x, p2.y], color, [t2.x, t2.y]));
        batch.vertices.push(Vertex::new([p1.x, p2.y], color, [t1.x, t2.y]));

        batch.triangle_indices.push(idx_offset);
        batch.triangle_indices.push(idx_offset + 1);
        batch.triangle_indices.push(idx_offset + 2);

        batch.triangle_indices.push(idx_offset);
        batch.triangle_indices.push(idx_offset + 2);
        batch.triangle_indices.push(idx_offset + 3);
    }

    pub fn fill_rect(&mut self, area: Rect<f32>, color: [f32; 4]) {
        self.start_solid_texture();
        self.tex_rect(area,
                      Rect::new(Point2D::new(0.0, 0.0), Size2D::new(0.0, 0.0)),
                      color);
    }

    pub fn text_input(&mut self,
                      font: Font,
                      pos: Point2D<f32>,
                      color: [f32; 4],
                      text_buffer: &mut String) {
        // TODO: Focus system. Only accept input if current input widget is focused.
        // (Also needs widget identifiers to know which is which.)
        for c in self.text_input.iter() {
            match *c {
                KeyInput::Printable(c) => {
                    if c >= ' ' {
                        text_buffer.push(c);
                    }
                }
                KeyInput::Other(Keycode::Backspace) => {
                    text_buffer.pop();
                }
                KeyInput::Other(_) => {}
            }
        }

        // TODO: Option to draw cursor mid-string (font may be
        // variable-width...), track cursor pos somehow (external ref or
        // internal cache)

        // TODO: Arrow keys move cursor

        // TODO: Filter function for input, eg. numbers only.

        // Nasty hack to show a blinking cursor. Will only work for cursor
        // always at the end of the input.

        // TODO: Maybe want to use wall clock time instead of GUI context ticks for this?
        if (self.tick / 30) % 3 == 0 {
            self.draw_text(font, pos, color, text_buffer);
        } else {
            self.draw_text(font, pos, color, &format!("{}_", text_buffer));
        }
    }

    fn start_solid_texture(&mut self) {
        let tex = self.solid_texture.clone();
        self.start_texture(tex);
    }

    /// Ensure that there current draw batch has solid texture.
    fn start_texture(&mut self, texture: T) {
        // TODO: Actually have the solid texture value stashed somewhere.
        if self.draw_list.is_empty() ||
           self.draw_list[self.draw_list.len() - 1].texture != texture {
            self.draw_list.push(DrawBatch {
                texture: texture,
                clip: None,
                vertices: Vec::new(),
                triangle_indices: Vec::new(),
            });
        }
    }

    pub fn end_frame(&mut self) -> Vec<DrawBatch<T, V>> {
        // Clean up transient mouse click info.
        self.click_state = self.click_state.tick();

        // Clean up text buffer
        self.text_input.clear();

        let mut ret = Vec::new();
        mem::swap(&mut ret, &mut self.draw_list);
        ret
    }

    /// Register mouse button state.
    pub fn input_mouse_button(&mut self, id: MouseButton, is_down: bool) {
        if id == MouseButton::Left {
            if is_down {
                self.click_state = self.click_state.input_press(self.mouse_pos);
            } else {
                self.click_state = self.click_state.input_release(self.mouse_pos);
            }
        }
        // TODO handle other buttons
    }

    /// Register mouse motion.
    pub fn input_mouse_move(&mut self, x: i32, y: i32) {
        self.mouse_pos = Point2D::new(x as f32, y as f32);
    }

    /// Register printable character input.
    pub fn input_char(&mut self, c: char) {
        self.text_input.push(KeyInput::Printable(c));
    }

    /// Register a nonprintable key state.
    pub fn input_key_state(&mut self, k: Keycode, is_down: bool) {
        if is_down {
            self.text_input.push(KeyInput::Other(k));
        }
    }

    /// Build a font atlas from a TTF and construct a texture object.
    ///
    /// The output will be have 8 alpha channel bits per pixel.
    ///
    /// TODO: Font customization, point size, character ranges.
    pub fn init_font<F>(&mut self,
                        ttf_data: &[u8],
                        point_size: f32,
                        chars: Range<usize>,
                        register_texture: F)
                        -> Result<Font, ()>
        where F: FnOnce(&[u8], u32, u32) -> T
    {
        unimplemented!();
    }

    pub fn init_default_font<F>(&mut self, register_texture: F) -> Font
        where F: FnOnce(&[u8], u32, u32) -> T
    {
        static DEFAULT_FONT: &'static [u8] = include_bytes!("unscii16-256x112.raw");
        let (width, height) = (256, 112);
        let start_char = 32;
        let end_char = 127;
        let (char_width, char_height) = (8, 16);
        let columns = width / char_width;

        let t = register_texture(DEFAULT_FONT, width, height);

        let mut map = HashMap::new();

        for i in start_char..end_char {
            let x = char_width * ((i - start_char) % columns);
            let y = char_height * ((i - start_char) / columns);

            let texcoords = Rect::new(Point2D::new(x as f32 / width as f32,
                                                   y as f32 / height as f32),
                                      Size2D::new(char_width as f32 / width as f32,
                                                  char_height as f32 / height as f32));

            map.insert(std::char::from_u32(i).unwrap(),
                       CharData {
                           texcoords: texcoords,
                           draw_offset: Point2D::new(0.0, char_height as f32),
                           advance: char_width as f32,
                       });
        }

        self.fonts.push(FontData {
            texture: t,
            chars: map,
            height: char_height as f32,
        });

        Font(self.fonts.len() - 1)
    }
}

/// A sequence of primitive draw operarations.
pub struct DrawBatch<T, V> {
    /// Texture used for the current batch, details depend on backend
    /// implementation
    pub texture: T,
    /// Clipping rectangle for the current batch
    pub clip: Option<Rect<f32>>,
    /// Vertex data
    pub vertices: Vec<V>,
    /// Indices into the vertex array for the triangles that make up the batch
    pub triangle_indices: Vec<u16>,
}

pub trait Vertex {
    fn new(pos: [f32; 2], color: [f32; 4], texcoord: [f32; 2]) -> Self;
}

/// Text alignment.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Align {
    Left,
    Center,
    Right,
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum MouseButton {
    Left,
    Middle,
    Right,
}

#[derive(Copy, Clone, PartialEq, Debug)]
enum ClickState {
    Unpressed,
    Press(Point2D<f32>),
    Drag(Point2D<f32>),
    Release(Point2D<f32>, Point2D<f32>),
}

impl ClickState {
    fn tick(self) -> ClickState {
        match self {
            ClickState::Unpressed => ClickState::Unpressed,
            ClickState::Press(p) => ClickState::Drag(p),
            ClickState::Drag(p) => ClickState::Drag(p),
            ClickState::Release(_, _) => ClickState::Unpressed,
        }
    }

    fn input_press(self, pos: Point2D<f32>) -> ClickState {
        match self {
            ClickState::Unpressed => ClickState::Press(pos),
            ClickState::Press(p) => ClickState::Drag(p),
            ClickState::Drag(p) => ClickState::Drag(p),
            ClickState::Release(_, _) => ClickState::Press(pos),
        }
    }

    fn input_release(self, pos: Point2D<f32>) -> ClickState {
        match self {
            ClickState::Unpressed => ClickState::Unpressed,
            ClickState::Press(p) => ClickState::Release(p, pos),
            ClickState::Drag(p) => ClickState::Release(p, pos),
            ClickState::Release(p, _) => ClickState::Release(p, pos),
        }
    }

    fn is_pressed(&self) -> bool {
        match *self {
            ClickState::Press(_) |
            ClickState::Drag(_) |
            ClickState::Release(_, _) => true,
            ClickState::Unpressed => false,
        }
    }

    fn is_release(&self) -> bool {
        if let ClickState::Release(_, _) = *self {
            true
        } else {
            false
        }
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Keycode {
    Tab,
    Shift,
    Ctrl,
    Enter,
    Backspace,
    Del,
    Up,
    Down,
    Left,
    Right,
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
enum KeyInput {
    Printable(char),
    Other(Keycode),
}

#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Font(usize);

pub struct FontData<T> {
    texture: T,
    chars: HashMap<char, CharData>,
    height: f32,
}

impl<T> FontData<T> {
    pub fn render_size(&self, text: &str) -> Rect<f32> {
        let mut w = 0.0;

        for c in text.chars() {
            if let Some(f) = self.chars.get(&c) {
                w += f.advance;
            }
        }

        Rect::new(Point2D::new(0.0, 0.0), Size2D::new(w, self.height))
    }
}

#[derive(Clone, Debug)]
struct CharData {
    texcoords: Rect<f32>,
    draw_offset: Point2D<f32>,
    advance: f32,
}
<commit_msg>Skeleton for style configuration values<commit_after>extern crate euclid;

use std::mem;
use std::ops::Range;
use std::collections::HashMap;
use euclid::{Rect, Point2D, Size2D};

/// Configuration for rendering style.
#[derive(Clone, PartialEq)]
pub struct Style {
    pub foreground_color: [f32; 4],
    pub background_color: [f32; 4],
    pub font: Font,
    // Private field so that the struct doesn't show up as fully public and
    // fixed in the visible API.
    _reserved: std::marker::PhantomData<()>,
}

impl Default for Style {
    fn default() -> Self {
        Style {
            foreground_color: [1.0, 1.0, 1.0, 1.0],
            background_color: [0.0, 0.0, 0.0, 1.0],
            font: Font(0),
            _reserved: std::marker::PhantomData,
        }
    }
}

/// An immediate mode graphical user interface context.
///
/// The context persists over a frame and receives commands that combine GUI
/// description and input handling. At the end of the frame, the commands are
/// converted into rendering instructions for the GUI.
pub struct Context<T, V> {
    draw_list: Vec<DrawBatch<T, V>>,
    /// Texture value used for solid-color drawing
    solid_texture: T,

    // TODO: This is for demo purposes, need a proper layout state.
    layout_pos: Point2D<f32>,

    mouse_pos: Point2D<f32>,
    click_state: ClickState,

    fonts: Vec<FontData<T>>,

    text_input: Vec<KeyInput>,

    tick: u64,
}

impl<T, V: Vertex> Context<T, V>
    where T: Clone + PartialEq
{
    /// Construct a new interface context instance.
    ///
    /// The client must provide an initial texture instance that is used for
    /// drawing solid shapes. This can be a texture that consists of a single
    /// opaque white pixel.
    pub fn new(solid_texture: T) -> Context<T, V> {
        Context {
            draw_list: Vec::new(),
            solid_texture: solid_texture,

            layout_pos: Point2D::new(0.0, 0.0),

            mouse_pos: Point2D::new(0.0, 0.0),
            click_state: ClickState::Unpressed,

            fonts: Vec::new(),

            text_input: Vec::new(),

            tick: 0,
        }
    }

    pub fn begin_frame(&mut self) {
        self.tick += 1;

        self.layout_pos = Point2D::new(10.0, 10.0);

        // TODO
    }

    pub fn draw_text(&mut self, font: Font, mut pos: Point2D<f32>, color: [f32; 4], text: &str) {
        assert!(self.fonts.len() >= font.0);
        let id = font.0;
        let t = self.fonts[id].texture.clone();
        let h = self.fonts[id].height;
        self.start_texture(t);

        for c in text.chars() {
            // FIXME: Gratuitous cloning because of borrow checker.
            let x = self.fonts[id].chars.get(&c).cloned();
            // TODO: Draw some sort of symbol for characters missing from font.
            if let Some(f) = x {
                self.tex_rect(Rect::new(pos - f.draw_offset, Size2D::new(f.advance, h)),
                              f.texcoords,
                              color);
                pos.x += f.advance;
            }
        }
    }

    fn default_font(&self) -> Font {
        Font(0)
    }

    pub fn button(&mut self, caption: &str) -> bool {
        let font = self.default_font();
        let area = self.fonts[font.0]
                       .render_size(caption)
                       .inflate(4.0, 4.0)
                       .translate(&self.layout_pos);

        self.layout_pos.y += area.size.height + 2.0;

        let hover = area.contains(&self.mouse_pos);
        let press = self.click_state.is_pressed() && area.contains(&self.mouse_pos);

        let color = if press {
            [1.0, 1.0, 0.0, 1.0]
        } else if hover {
            [0.5, 1.0, 0.0, 1.0]
        } else {
            [0.0, 1.0, 0.0, 1.0]
        };

        self.fill_rect(area, color);
        self.fill_rect(area.inflate(-1.0, -1.0), [0.0, 0.0, 0.0, 1.0]);
        self.draw_text(font,
                       area.origin + Point2D::new(4.0, area.size.height - 4.0),
                       color,
                       caption);

        press && self.click_state.is_release()
    }

    pub fn tex_rect(&mut self, area: Rect<f32>, texcoords: Rect<f32>, color: [f32; 4]) {
        let (p1, p2) = (area.origin, area.bottom_right());
        let (t1, t2) = (texcoords.origin, texcoords.bottom_right());
        let idx = self.draw_list.len() - 1;
        let batch = &mut self.draw_list[idx];
        let idx_offset = batch.vertices.len() as u16;

        batch.vertices.push(Vertex::new([p1.x, p1.y], color, [t1.x, t1.y]));
        batch.vertices.push(Vertex::new([p2.x, p1.y], color, [t2.x, t1.y]));
        batch.vertices.push(Vertex::new([p2.x, p2.y], color, [t2.x, t2.y]));
        batch.vertices.push(Vertex::new([p1.x, p2.y], color, [t1.x, t2.y]));

        batch.triangle_indices.push(idx_offset);
        batch.triangle_indices.push(idx_offset + 1);
        batch.triangle_indices.push(idx_offset + 2);

        batch.triangle_indices.push(idx_offset);
        batch.triangle_indices.push(idx_offset + 2);
        batch.triangle_indices.push(idx_offset + 3);
    }

    pub fn fill_rect(&mut self, area: Rect<f32>, color: [f32; 4]) {
        self.start_solid_texture();
        self.tex_rect(area,
                      Rect::new(Point2D::new(0.0, 0.0), Size2D::new(0.0, 0.0)),
                      color);
    }

    pub fn text_input(&mut self,
                      font: Font,
                      pos: Point2D<f32>,
                      color: [f32; 4],
                      text_buffer: &mut String) {
        // TODO: Focus system. Only accept input if current input widget is focused.
        // (Also needs widget identifiers to know which is which.)
        for c in self.text_input.iter() {
            match *c {
                KeyInput::Printable(c) => {
                    if c >= ' ' {
                        text_buffer.push(c);
                    }
                }
                KeyInput::Other(Keycode::Backspace) => {
                    text_buffer.pop();
                }
                KeyInput::Other(_) => {}
            }
        }

        // TODO: Option to draw cursor mid-string (font may be
        // variable-width...), track cursor pos somehow (external ref or
        // internal cache)

        // TODO: Arrow keys move cursor

        // TODO: Filter function for input, eg. numbers only.

        // Nasty hack to show a blinking cursor. Will only work for cursor
        // always at the end of the input.

        // TODO: Maybe want to use wall clock time instead of GUI context ticks for this?
        if (self.tick / 30) % 3 == 0 {
            self.draw_text(font, pos, color, text_buffer);
        } else {
            self.draw_text(font, pos, color, &format!("{}_", text_buffer));
        }
    }

    fn start_solid_texture(&mut self) {
        let tex = self.solid_texture.clone();
        self.start_texture(tex);
    }

    /// Ensure that there current draw batch has solid texture.
    fn start_texture(&mut self, texture: T) {
        // TODO: Actually have the solid texture value stashed somewhere.
        if self.draw_list.is_empty() ||
           self.draw_list[self.draw_list.len() - 1].texture != texture {
            self.draw_list.push(DrawBatch {
                texture: texture,
                clip: None,
                vertices: Vec::new(),
                triangle_indices: Vec::new(),
            });
        }
    }

    pub fn end_frame(&mut self) -> Vec<DrawBatch<T, V>> {
        // Clean up transient mouse click info.
        self.click_state = self.click_state.tick();

        // Clean up text buffer
        self.text_input.clear();

        let mut ret = Vec::new();
        mem::swap(&mut ret, &mut self.draw_list);
        ret
    }

    /// Register mouse button state.
    pub fn input_mouse_button(&mut self, id: MouseButton, is_down: bool) {
        if id == MouseButton::Left {
            if is_down {
                self.click_state = self.click_state.input_press(self.mouse_pos);
            } else {
                self.click_state = self.click_state.input_release(self.mouse_pos);
            }
        }
        // TODO handle other buttons
    }

    /// Register mouse motion.
    pub fn input_mouse_move(&mut self, x: i32, y: i32) {
        self.mouse_pos = Point2D::new(x as f32, y as f32);
    }

    /// Register printable character input.
    pub fn input_char(&mut self, c: char) {
        self.text_input.push(KeyInput::Printable(c));
    }

    /// Register a nonprintable key state.
    pub fn input_key_state(&mut self, k: Keycode, is_down: bool) {
        if is_down {
            self.text_input.push(KeyInput::Other(k));
        }
    }

    /// Build a font atlas from a TTF and construct a texture object.
    ///
    /// The output will be have 8 alpha channel bits per pixel.
    ///
    /// TODO: Font customization, point size, character ranges.
    pub fn init_font<F>(&mut self,
                        ttf_data: &[u8],
                        point_size: f32,
                        chars: Range<usize>,
                        register_texture: F)
                        -> Result<Font, ()>
        where F: FnOnce(&[u8], u32, u32) -> T
    {
        unimplemented!();
    }

    pub fn init_default_font<F>(&mut self, register_texture: F) -> Font
        where F: FnOnce(&[u8], u32, u32) -> T
    {
        static DEFAULT_FONT: &'static [u8] = include_bytes!("unscii16-256x112.raw");
        let (width, height) = (256, 112);
        let start_char = 32;
        let end_char = 127;
        let (char_width, char_height) = (8, 16);
        let columns = width / char_width;

        let t = register_texture(DEFAULT_FONT, width, height);

        let mut map = HashMap::new();

        for i in start_char..end_char {
            let x = char_width * ((i - start_char) % columns);
            let y = char_height * ((i - start_char) / columns);

            let texcoords = Rect::new(Point2D::new(x as f32 / width as f32,
                                                   y as f32 / height as f32),
                                      Size2D::new(char_width as f32 / width as f32,
                                                  char_height as f32 / height as f32));

            map.insert(std::char::from_u32(i).unwrap(),
                       CharData {
                           texcoords: texcoords,
                           draw_offset: Point2D::new(0.0, char_height as f32),
                           advance: char_width as f32,
                       });
        }

        self.fonts.push(FontData {
            texture: t,
            chars: map,
            height: char_height as f32,
        });

        Font(self.fonts.len() - 1)
    }
}

/// A sequence of primitive draw operarations.
pub struct DrawBatch<T, V> {
    /// Texture used for the current batch, details depend on backend
    /// implementation
    pub texture: T,
    /// Clipping rectangle for the current batch
    pub clip: Option<Rect<f32>>,
    /// Vertex data
    pub vertices: Vec<V>,
    /// Indices into the vertex array for the triangles that make up the batch
    pub triangle_indices: Vec<u16>,
}

pub trait Vertex {
    fn new(pos: [f32; 2], color: [f32; 4], texcoord: [f32; 2]) -> Self;
}

/// Text alignment.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Align {
    Left,
    Center,
    Right,
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum MouseButton {
    Left,
    Middle,
    Right,
}

#[derive(Copy, Clone, PartialEq, Debug)]
enum ClickState {
    Unpressed,
    Press(Point2D<f32>),
    Drag(Point2D<f32>),
    Release(Point2D<f32>, Point2D<f32>),
}

impl ClickState {
    fn tick(self) -> ClickState {
        match self {
            ClickState::Unpressed => ClickState::Unpressed,
            ClickState::Press(p) => ClickState::Drag(p),
            ClickState::Drag(p) => ClickState::Drag(p),
            ClickState::Release(_, _) => ClickState::Unpressed,
        }
    }

    fn input_press(self, pos: Point2D<f32>) -> ClickState {
        match self {
            ClickState::Unpressed => ClickState::Press(pos),
            ClickState::Press(p) => ClickState::Drag(p),
            ClickState::Drag(p) => ClickState::Drag(p),
            ClickState::Release(_, _) => ClickState::Press(pos),
        }
    }

    fn input_release(self, pos: Point2D<f32>) -> ClickState {
        match self {
            ClickState::Unpressed => ClickState::Unpressed,
            ClickState::Press(p) => ClickState::Release(p, pos),
            ClickState::Drag(p) => ClickState::Release(p, pos),
            ClickState::Release(p, _) => ClickState::Release(p, pos),
        }
    }

    fn is_pressed(&self) -> bool {
        match *self {
            ClickState::Press(_) |
            ClickState::Drag(_) |
            ClickState::Release(_, _) => true,
            ClickState::Unpressed => false,
        }
    }

    fn is_release(&self) -> bool {
        if let ClickState::Release(_, _) = *self {
            true
        } else {
            false
        }
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Keycode {
    Tab,
    Shift,
    Ctrl,
    Enter,
    Backspace,
    Del,
    Up,
    Down,
    Left,
    Right,
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
enum KeyInput {
    Printable(char),
    Other(Keycode),
}

#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Font(usize);

pub struct FontData<T> {
    texture: T,
    chars: HashMap<char, CharData>,
    height: f32,
}

impl<T> FontData<T> {
    pub fn render_size(&self, text: &str) -> Rect<f32> {
        let mut w = 0.0;

        for c in text.chars() {
            if let Some(f) = self.chars.get(&c) {
                w += f.advance;
            }
        }

        Rect::new(Point2D::new(0.0, 0.0), Size2D::new(w, self.height))
    }
}

#[derive(Clone, Debug)]
struct CharData {
    texcoords: Rect<f32>,
    draw_offset: Point2D<f32>,
    advance: f32,
}
<|endoftext|>


<commit_before>#![doc(html_root_url = "https://dtolnay.github.io/syn")]

#![cfg_attr(feature = "cargo-clippy", allow(
    const_static_lifetime,
    doc_markdown,
    large_enum_variant,
    redundant_closure,
))]

extern crate proc_macro;
extern crate proc_macro2;
extern crate unicode_xid;

#[cfg(any(feature = "printing", feature = "parsing"))]
extern crate quote;

#[cfg(feature = "parsing")]
#[macro_use]
#[doc(hidden)]
pub mod parsers;

#[macro_use]
mod macros;

#[cfg(feature = "parsing")]
#[doc(hidden)]
#[macro_use]
pub mod helper;

#[macro_use]
pub mod token;

mod attr;
pub use attr::{Attribute, AttrStyle, MetaItem, NestedMetaItem, MetaItemList,
               MetaNameValue};

mod data;
pub use data::{Field, Variant, VariantData, Visibility, VisRestricted, VisCrate,
               VisPublic, VisInherited};

mod expr;
pub use expr::{Expr, ExprKind, ExprBox, ExprInPlace, ExprArray, ExprCall,
               ExprMethodCall, ExprTuple, ExprBinary, ExprUnary, ExprCast,
               ExprType, ExprIf, ExprIfLet, ExprWhile, ExprWhileLet,
               ExprForLoop, ExprLoop, ExprMatch, ExprClosure, ExprBlock,
               ExprAssign, ExprAssignOp, ExprField, ExprTupField, ExprIndex,
               ExprRange, ExprPath, ExprAddrOf, ExprBreak, ExprContinue,
               ExprRet, ExprStruct, ExprRepeat, ExprParen, ExprTry, ExprCatch,
               ExprGroup, ExprYield, ExprUnsafe};

#[cfg(feature = "full")]
pub use expr::{Arm, BindingMode, Block, CaptureBy, FieldPat, FieldValue, Local,
               MacStmtStyle, Pat, RangeLimits, Stmt, PatIdent, PatWild,
               PatStruct, PatTuple, PatTupleStruct, PatPath, PatBox, PatRef,
               PatLit, PatRange, PatSlice, InPlaceKind};

mod generics;
pub use generics::{Generics, GenericParam, LifetimeDef, TraitBoundModifier, TypeParam, TypeParamBound,
                   WhereBoundPredicate, WhereClause, WhereEqPredicate, WherePredicate,
                   WhereRegionPredicate, BoundLifetimes, ConstParam};
#[cfg(feature = "printing")]
pub use generics::{ImplGenerics, Turbofish, TypeGenerics};

mod ident;
pub use ident::Ident;

#[cfg(feature = "full")]
mod item;
#[cfg(feature = "full")]
pub use item::{Constness, Defaultness, FnArg, FnDecl, ForeignItem, ItemForeignMod,
               ImplItem, ImplPolarity, Item, MethodSig,
               TraitItem, ItemExternCrate, ItemUse,
               ItemStatic, ItemConst, ItemFn, ItemMacro, ItemMacro2, ItemMod, ItemType, ItemEnum,
               ItemStruct, ItemUnion, ItemTrait, ItemDefaultImpl, ItemImpl,
               UsePath, UseGlob, UseList, ForeignItemFn, ForeignItemStatic, ForeignItemType,
               TraitItemConst, TraitItemMacro, TraitItemMethod, TraitItemType,
               ImplItemConst, ImplItemMacro, ImplItemMethod, ImplItemType, ArgSelfRef,
               ArgSelf, ArgCaptured, UseTree};

#[cfg(feature = "full")]
mod file;
#[cfg(feature = "full")]
pub use file::File;

mod lifetime;
pub use lifetime::Lifetime;

mod lit;
pub use lit::{Lit, LitKind};

mod mac;
pub use mac::{Macro, TokenTree};

mod derive;
pub use derive::{Body, DeriveInput, BodyEnum, BodyStruct};

mod op;
pub use op::{BinOp, UnOp};

mod ty;
pub use ty::{Abi, AbiKind, AngleBracketedGenericArguments, BareFnArg,
             BareFnArgName, BareFnType, ReturnType, MutType, Mutability,
             ParenthesizedGenericArguments, Path, PathArguments, PathSegment,
             PolyTraitRef, QSelf, Type, TypeBinding, Unsafety, TypeSlice,
             TypeArray, TypePtr, TypeReference, TypeBareFn, TypeNever, TypeTuple,
             TypePath, TypeTraitObject, TypeImplTrait, TypeParen, TypeInfer,
             TypeGroup, GenericArgument};
#[cfg(feature = "printing")]
pub use ty::PathTokens;

#[cfg(feature = "parsing")]
mod cursor;
#[cfg(feature = "parsing")]
pub mod synom;
pub mod delimited;

mod gen {
    #[cfg(feature = "visit")]
    pub mod visit;

    #[cfg(feature = "visit_mut")]
    pub mod visit_mut;

    #[cfg(feature = "fold")]
    pub mod fold;
}
pub use gen::*;

////////////////////////////////////////////////////////////////////////////////

#[cfg(feature = "parsing")]
use synom::Synom;
#[cfg(feature = "parsing")]
use cursor::SynomBuffer;

#[cfg(feature = "parsing")]
mod error;
#[cfg(feature = "parsing")]
pub use error::{PResult, ParseError};

// Not public API.
#[cfg(feature = "parsing")]
#[doc(hidden)]
pub use error::parse_error;

/// Parse tokens of source code into the chosen syn data type.
///
/// This is preferred over parsing a string because tokens are able to preserve
/// information about where in the user's code they were originally written (the
/// "span" of the token), possibly allowing the compiler to produce better error
/// messages.
///
/// # Examples
///
/// ```rust
/// extern crate proc_macro;
/// use proc_macro::TokenStream;
///
/// extern crate syn;
///
/// #[macro_use]
/// extern crate quote;
///
/// use syn::DeriveInput;
///
/// # const IGNORE_TOKENS: &str = stringify! {
/// #[proc_macro_derive(MyMacro)]
/// # };
/// pub fn my_macro(input: TokenStream) -> TokenStream {
///     // Parse the tokens into a syntax tree
///     let ast: DeriveInput = syn::parse(input).unwrap();
///
///     // Build the output, possibly using quasi-quotation
///     let expanded = quote! {
///         /* ... */
///     };
///
///     // Convert into a token stream and return it
///     expanded.into()
/// }
/// #
/// # fn main() {}
/// ```
#[cfg(feature = "parsing")]
pub fn parse<T>(tokens: proc_macro::TokenStream) -> Result<T, ParseError>
    where T: Synom,
{
    _parse(tokens.into())
}

#[cfg(feature = "parsing")]
fn _parse<T>(tokens: proc_macro2::TokenStream) -> Result<T, ParseError>
    where T: Synom,
{
    let buf = SynomBuffer::new(tokens);
    let result = T::parse(buf.begin());
    let err = match result {
        Ok((rest, t)) => {
            if rest.eof() {
                return Ok(t);
            } else if rest == buf.begin() {
                // parsed nothing
                ParseError::new("failed to parse anything")
            } else {
                ParseError::new("failed to parse all tokens")
            }
        }
        Err(err) => err,
    };
    match T::description() {
        Some(s) => Err(ParseError::new(format!("failed to parse {}: {}", s, err))),
        None => Err(err),
    }
}

/// Parse a `quote::Tokens` of Rust code into the chosen syn data type.
///
/// # Examples
///
/// ```rust
/// extern crate syn;
/// #
/// # #[macro_use]
/// # extern crate quote;
/// #
/// # type Result<T> = std::result::Result<T, Box<std::error::Error>>;
///
/// use syn::Expr;
///
/// fn run() -> Result<()> {
///     let code = quote!(assert_eq!(u8::max_value(), 255));
///     let expr = syn::parse_token::<Expr>(code)?;
///     println!("{:#?}", expr);
///     Ok(())
/// }
/// #
/// # fn main() { run().unwrap() }
/// ```
#[cfg(feature = "parsing")]
pub fn parse_tokens<T: Synom>(tokens: quote::Tokens) -> Result<T, ParseError> {
    _parse(tokens.into())
}

/// Parse a string of Rust code into the chosen syn data type.
///
/// # Examples
///
/// ```rust
/// extern crate syn;
/// #
/// #
/// # type Result<T> = std::result::Result<T, Box<std::error::Error>>;
///
/// use syn::Expr;
///
/// fn run() -> Result<()> {
///     let code = "assert_eq!(u8::max_value(), 255)";
///     let expr = syn::parse_str::<Expr>(code)?;
///     println!("{:#?}", expr);
///     Ok(())
/// }
/// #
/// # fn main() { run().unwrap() }
/// ```
#[cfg(feature = "parsing")]
pub fn parse_str<T: Synom>(s: &str) -> Result<T, ParseError> {
    _parse(s.parse()?)
}

// FIXME the name parse_file makes it sound like you might pass in a path to a
// file, rather than the content.
/// Parse the content of a file of Rust code.
///
/// This is different from `syn::parse_str::<File>(content)` in two ways:
///
/// - It discards a leading byte order mark `\u{FEFF}` if the file has one.
/// - It preserves the shebang line of the file, such as `#!/usr/bin/env rustx`.
///
/// If present, either of these would be an error using `from_str`.
///
/// # Examples
///
/// ```rust,no_run
/// extern crate syn;
/// #
/// #
/// # type Result<T> = std::result::Result<T, Box<std::error::Error>>;
///
/// use std::fs::File;
/// use std::io::Read;
///
/// fn run() -> Result<()> {
///     let mut file = File::open("path/to/code.rs")?;
///     let mut content = String::new();
///     file.read_to_string(&mut content)?;
///
///     let ast = syn::parse_file(&content)?;
///     if let Some(shebang) = ast.shebang {
///         println!("{}", shebang);
///     }
///     println!("{} items", ast.items.len());
///
///     Ok(())
/// }
/// #
/// # fn main() { run().unwrap() }
/// ```
#[cfg(all(feature = "parsing", feature = "full"))]
pub fn parse_file(mut content: &str) -> Result<File, ParseError> {
    // Strip the BOM if it is present
    const BOM: &'static str = "\u{feff}";
    if content.starts_with(BOM) {
        content = &content[BOM.len()..];
    }

    let mut shebang = None;
    if content.starts_with("#!") && !content.starts_with("#![") {
        if let Some(idx) = content.find('\n') {
            shebang = Some(content[..idx].to_string());
            content = &content[idx..];
        } else {
            shebang = Some(content.to_string());
            content = "";
        }
    }

    let mut file: File = parse_str(content)?;
    file.shebang = shebang;
    Ok(file)
}

#[cfg(feature = "printing")]
struct TokensOrDefault<'a, T: 'a>(&'a Option<T>);

#[cfg(feature = "printing")]
impl<'a, T> quote::ToTokens for TokensOrDefault<'a, T>
    where T: quote::ToTokens + Default,
{
    fn to_tokens(&self, tokens: &mut quote::Tokens) {
        match *self.0 {
            Some(ref t) => t.to_tokens(tokens),
            None => T::default().to_tokens(tokens),
        }
    }
}
<commit_msg>Fix method in parse_tokens doc comment<commit_after>#![doc(html_root_url = "https://dtolnay.github.io/syn")]

#![cfg_attr(feature = "cargo-clippy", allow(
    const_static_lifetime,
    doc_markdown,
    large_enum_variant,
    redundant_closure,
))]

extern crate proc_macro;
extern crate proc_macro2;
extern crate unicode_xid;

#[cfg(any(feature = "printing", feature = "parsing"))]
extern crate quote;

#[cfg(feature = "parsing")]
#[macro_use]
#[doc(hidden)]
pub mod parsers;

#[macro_use]
mod macros;

#[cfg(feature = "parsing")]
#[doc(hidden)]
#[macro_use]
pub mod helper;

#[macro_use]
pub mod token;

mod attr;
pub use attr::{Attribute, AttrStyle, MetaItem, NestedMetaItem, MetaItemList,
               MetaNameValue};

mod data;
pub use data::{Field, Variant, VariantData, Visibility, VisRestricted, VisCrate,
               VisPublic, VisInherited};

mod expr;
pub use expr::{Expr, ExprKind, ExprBox, ExprInPlace, ExprArray, ExprCall,
               ExprMethodCall, ExprTuple, ExprBinary, ExprUnary, ExprCast,
               ExprType, ExprIf, ExprIfLet, ExprWhile, ExprWhileLet,
               ExprForLoop, ExprLoop, ExprMatch, ExprClosure, ExprBlock,
               ExprAssign, ExprAssignOp, ExprField, ExprTupField, ExprIndex,
               ExprRange, ExprPath, ExprAddrOf, ExprBreak, ExprContinue,
               ExprRet, ExprStruct, ExprRepeat, ExprParen, ExprTry, ExprCatch,
               ExprGroup, ExprYield, ExprUnsafe};

#[cfg(feature = "full")]
pub use expr::{Arm, BindingMode, Block, CaptureBy, FieldPat, FieldValue, Local,
               MacStmtStyle, Pat, RangeLimits, Stmt, PatIdent, PatWild,
               PatStruct, PatTuple, PatTupleStruct, PatPath, PatBox, PatRef,
               PatLit, PatRange, PatSlice, InPlaceKind};

mod generics;
pub use generics::{Generics, GenericParam, LifetimeDef, TraitBoundModifier, TypeParam, TypeParamBound,
                   WhereBoundPredicate, WhereClause, WhereEqPredicate, WherePredicate,
                   WhereRegionPredicate, BoundLifetimes, ConstParam};
#[cfg(feature = "printing")]
pub use generics::{ImplGenerics, Turbofish, TypeGenerics};

mod ident;
pub use ident::Ident;

#[cfg(feature = "full")]
mod item;
#[cfg(feature = "full")]
pub use item::{Constness, Defaultness, FnArg, FnDecl, ForeignItem, ItemForeignMod,
               ImplItem, ImplPolarity, Item, MethodSig,
               TraitItem, ItemExternCrate, ItemUse,
               ItemStatic, ItemConst, ItemFn, ItemMacro, ItemMacro2, ItemMod, ItemType, ItemEnum,
               ItemStruct, ItemUnion, ItemTrait, ItemDefaultImpl, ItemImpl,
               UsePath, UseGlob, UseList, ForeignItemFn, ForeignItemStatic, ForeignItemType,
               TraitItemConst, TraitItemMacro, TraitItemMethod, TraitItemType,
               ImplItemConst, ImplItemMacro, ImplItemMethod, ImplItemType, ArgSelfRef,
               ArgSelf, ArgCaptured, UseTree};

#[cfg(feature = "full")]
mod file;
#[cfg(feature = "full")]
pub use file::File;

mod lifetime;
pub use lifetime::Lifetime;

mod lit;
pub use lit::{Lit, LitKind};

mod mac;
pub use mac::{Macro, TokenTree};

mod derive;
pub use derive::{Body, DeriveInput, BodyEnum, BodyStruct};

mod op;
pub use op::{BinOp, UnOp};

mod ty;
pub use ty::{Abi, AbiKind, AngleBracketedGenericArguments, BareFnArg,
             BareFnArgName, BareFnType, ReturnType, MutType, Mutability,
             ParenthesizedGenericArguments, Path, PathArguments, PathSegment,
             PolyTraitRef, QSelf, Type, TypeBinding, Unsafety, TypeSlice,
             TypeArray, TypePtr, TypeReference, TypeBareFn, TypeNever, TypeTuple,
             TypePath, TypeTraitObject, TypeImplTrait, TypeParen, TypeInfer,
             TypeGroup, GenericArgument};
#[cfg(feature = "printing")]
pub use ty::PathTokens;

#[cfg(feature = "parsing")]
mod cursor;
#[cfg(feature = "parsing")]
pub mod synom;
pub mod delimited;

mod gen {
    #[cfg(feature = "visit")]
    pub mod visit;

    #[cfg(feature = "visit_mut")]
    pub mod visit_mut;

    #[cfg(feature = "fold")]
    pub mod fold;
}
pub use gen::*;

////////////////////////////////////////////////////////////////////////////////

#[cfg(feature = "parsing")]
use synom::Synom;
#[cfg(feature = "parsing")]
use cursor::SynomBuffer;

#[cfg(feature = "parsing")]
mod error;
#[cfg(feature = "parsing")]
pub use error::{PResult, ParseError};

// Not public API.
#[cfg(feature = "parsing")]
#[doc(hidden)]
pub use error::parse_error;

/// Parse tokens of source code into the chosen syn data type.
///
/// This is preferred over parsing a string because tokens are able to preserve
/// information about where in the user's code they were originally written (the
/// "span" of the token), possibly allowing the compiler to produce better error
/// messages.
///
/// # Examples
///
/// ```rust
/// extern crate proc_macro;
/// use proc_macro::TokenStream;
///
/// extern crate syn;
///
/// #[macro_use]
/// extern crate quote;
///
/// use syn::DeriveInput;
///
/// # const IGNORE_TOKENS: &str = stringify! {
/// #[proc_macro_derive(MyMacro)]
/// # };
/// pub fn my_macro(input: TokenStream) -> TokenStream {
///     // Parse the tokens into a syntax tree
///     let ast: DeriveInput = syn::parse(input).unwrap();
///
///     // Build the output, possibly using quasi-quotation
///     let expanded = quote! {
///         /* ... */
///     };
///
///     // Convert into a token stream and return it
///     expanded.into()
/// }
/// #
/// # fn main() {}
/// ```
#[cfg(feature = "parsing")]
pub fn parse<T>(tokens: proc_macro::TokenStream) -> Result<T, ParseError>
    where T: Synom,
{
    _parse(tokens.into())
}

#[cfg(feature = "parsing")]
fn _parse<T>(tokens: proc_macro2::TokenStream) -> Result<T, ParseError>
    where T: Synom,
{
    let buf = SynomBuffer::new(tokens);
    let result = T::parse(buf.begin());
    let err = match result {
        Ok((rest, t)) => {
            if rest.eof() {
                return Ok(t);
            } else if rest == buf.begin() {
                // parsed nothing
                ParseError::new("failed to parse anything")
            } else {
                ParseError::new("failed to parse all tokens")
            }
        }
        Err(err) => err,
    };
    match T::description() {
        Some(s) => Err(ParseError::new(format!("failed to parse {}: {}", s, err))),
        None => Err(err),
    }
}

/// Parse a `quote::Tokens` of Rust code into the chosen syn data type.
///
/// # Examples
///
/// ```rust
/// extern crate syn;
/// #
/// # #[macro_use]
/// # extern crate quote;
/// #
/// # type Result<T> = std::result::Result<T, Box<std::error::Error>>;
///
/// use syn::Expr;
///
/// fn run() -> Result<()> {
///     let code = quote!(assert_eq!(u8::max_value(), 255));
///     let expr = syn::parse_tokens::<Expr>(code)?;
///     println!("{:#?}", expr);
///     Ok(())
/// }
/// #
/// # fn main() { run().unwrap() }
/// ```
#[cfg(feature = "parsing")]
pub fn parse_tokens<T: Synom>(tokens: quote::Tokens) -> Result<T, ParseError> {
    _parse(tokens.into())
}

/// Parse a string of Rust code into the chosen syn data type.
///
/// # Examples
///
/// ```rust
/// extern crate syn;
/// #
/// #
/// # type Result<T> = std::result::Result<T, Box<std::error::Error>>;
///
/// use syn::Expr;
///
/// fn run() -> Result<()> {
///     let code = "assert_eq!(u8::max_value(), 255)";
///     let expr = syn::parse_str::<Expr>(code)?;
///     println!("{:#?}", expr);
///     Ok(())
/// }
/// #
/// # fn main() { run().unwrap() }
/// ```
#[cfg(feature = "parsing")]
pub fn parse_str<T: Synom>(s: &str) -> Result<T, ParseError> {
    _parse(s.parse()?)
}

// FIXME the name parse_file makes it sound like you might pass in a path to a
// file, rather than the content.
/// Parse the content of a file of Rust code.
///
/// This is different from `syn::parse_str::<File>(content)` in two ways:
///
/// - It discards a leading byte order mark `\u{FEFF}` if the file has one.
/// - It preserves the shebang line of the file, such as `#!/usr/bin/env rustx`.
///
/// If present, either of these would be an error using `from_str`.
///
/// # Examples
///
/// ```rust,no_run
/// extern crate syn;
/// #
/// #
/// # type Result<T> = std::result::Result<T, Box<std::error::Error>>;
///
/// use std::fs::File;
/// use std::io::Read;
///
/// fn run() -> Result<()> {
///     let mut file = File::open("path/to/code.rs")?;
///     let mut content = String::new();
///     file.read_to_string(&mut content)?;
///
///     let ast = syn::parse_file(&content)?;
///     if let Some(shebang) = ast.shebang {
///         println!("{}", shebang);
///     }
///     println!("{} items", ast.items.len());
///
///     Ok(())
/// }
/// #
/// # fn main() { run().unwrap() }
/// ```
#[cfg(all(feature = "parsing", feature = "full"))]
pub fn parse_file(mut content: &str) -> Result<File, ParseError> {
    // Strip the BOM if it is present
    const BOM: &'static str = "\u{feff}";
    if content.starts_with(BOM) {
        content = &content[BOM.len()..];
    }

    let mut shebang = None;
    if content.starts_with("#!") && !content.starts_with("#![") {
        if let Some(idx) = content.find('\n') {
            shebang = Some(content[..idx].to_string());
            content = &content[idx..];
        } else {
            shebang = Some(content.to_string());
            content = "";
        }
    }

    let mut file: File = parse_str(content)?;
    file.shebang = shebang;
    Ok(file)
}

#[cfg(feature = "printing")]
struct TokensOrDefault<'a, T: 'a>(&'a Option<T>);

#[cfg(feature = "printing")]
impl<'a, T> quote::ToTokens for TokensOrDefault<'a, T>
    where T: quote::ToTokens + Default,
{
    fn to_tokens(&self, tokens: &mut quote::Tokens) {
        match *self.0 {
            Some(ref t) => t.to_tokens(tokens),
            None => T::default().to_tokens(tokens),
        }
    }
}
<|endoftext|>