<commit_before>use std::sync::{Arc, RWLock};
use std::collections::HashMap;
use std::collections::hashmap::{Occupied, Vacant};
use std::io::{IoResult, File};
use std::io::util::copy;
use std::path::BytesContainer;
use serialize::Encodable;
use http;
use http::server::ResponseWriter;
use time;
use mimes::get_media_type;
use mustache;
use mustache::{Template, Encoder, Error};

///A container for the response
pub struct Response<'a, 'b: 'a> {
    ///the original `http::server::ResponseWriter`
    pub origin: &'a mut ResponseWriter<'b>,
    templates: Arc<RWLock<HashMap<&'static str, Template>>>
}

impl<'a, 'b> Response<'a, 'b> {
    pub fn from_internal<'c, 'd>(response: &'c mut ResponseWriter<'d>,
                                 templates: Arc<RWLock<HashMap<&'static str, Template>>>)
                                -> Response<'c, 'd> {
        Response {
            origin: response,
            templates: templates
        }
    }

    /// Sets the content type by it's short form.
    /// Returns the response for chaining.
    ///
    /// # Example
    /// ```{rust,ignore}
    /// response.content_type("html");
    /// ```
    pub fn content_type(&mut self, text: &str) -> &mut Response<'a,'b> {
        self.origin.headers.content_type = get_media_type(text);
        self
    }

    /// Sets the status code and returns the response for chaining
    ///
    /// # Example
    /// ```{rust,ignore}
    /// response.status_code(http::status::NotFound);
    /// ```
    pub fn status_code(&mut self, status: http::status::Status) -> &mut Response<'a,'b> {
        self.origin.status = status;
        self
    }

    /// Writes a response
    ///
    /// # Example
    /// ```{rust,ignore}
    /// response.send("hello world");
    /// ```
    pub fn send<T: BytesContainer> (&mut self, text: T) {
        // TODO: This needs to be more sophisticated to return the correct headers
        // not just "some headers" :)
        Response::set_headers(self.origin);
        let _ = self.origin.write(text.container_as_bytes());
    }

    fn set_headers(response_writer: &mut http::server::ResponseWriter) {
        let ref mut headers = response_writer.headers;
        headers.date = Some(time::now_utc());

        // we don't need to set this https://github.com/Ogeon/rustful/issues/3#issuecomment-44787613
        headers.content_length = None;
        if headers.content_type.is_none() {
            headers.content_type = get_media_type("txt");
        }

        headers.server = Some(String::from_str("Nickel"));
    }

    /// Writes a file to the output.
    ///
    /// # Example
    /// ```{rust,ignore}
    /// response.send_file(some_path);
    /// ```
    pub fn send_file(&mut self, path: &Path) -> IoResult<()> {
        let mut file = try!(File::open(path));
        self.origin.headers.content_length = None;

        self.origin.headers.content_type = path.extension_str().and_then(get_media_type);
        self.origin.headers.server = Some(String::from_str("Nickel"));
        copy(&mut file, self.origin)
    }

    /// Renders the given template bound with the given data.
    ///
    /// # Example
    /// ```{rust,ignore}
    /// let mut data = HashMap::<&'static str, &'static str>::new();
    /// data.insert("name", "user");
    /// response.render("examples/assets/template.tpl", &data);
    /// ```
    pub fn render<'a, T: Encodable<Encoder<'a>, Error>>
        (&mut self, path: &'static str, data: &T) {
            // Fast path doesn't need writer lock
            match self.templates.read().find(&path) {
                Some(t) => {
                    let _ = t.render(self.origin, data);
                    return
                },
                None => {}
            }

            // We didn't find the template, get writers lock
            let mut templates = self.templates.write();
            // Search again incase there was a race to compile the template
            let template = match templates.entry(path) {
                Vacant(entry) => {
                    let mut file = File::open(&Path::new(path));
                    let raw_template =
                        file.read_to_string()
                            .ok()
                            .expect(format!("Couldn't open the template file: {}",
                                            path).as_slice());

                    entry.set(mustache::compile_str(raw_template.as_slice()))
                },
                Occupied(entry) => entry.into_mut()
            };

            let _ = template.render(self.origin, data);
    }
}

#[test]
fn matches_content_type () {
    let path = &Path::new("test.txt");
    let content_type = path.extension_str().and_then(get_media_type).unwrap();

    assert_eq!(content_type.type_.as_slice(), "text");
    assert_eq!(content_type.subtype.as_slice(), "plain");
}
<commit_msg>docs(response): fix docs<commit_after>use std::sync::{Arc, RWLock};
use std::collections::HashMap;
use std::collections::hashmap::{Occupied, Vacant};
use std::io::{IoResult, File};
use std::io::util::copy;
use std::path::BytesContainer;
use serialize::Encodable;
use http;
use http::server::ResponseWriter;
use time;
use mimes::get_media_type;
use mustache;
use mustache::{Template, Encoder, Error};

///A container for the response
pub struct Response<'a, 'b: 'a> {
    ///the original `http::server::ResponseWriter`
    pub origin: &'a mut ResponseWriter<'b>,
    templates: Arc<RWLock<HashMap<&'static str, Template>>>
}

impl<'a, 'b> Response<'a, 'b> {
    pub fn from_internal<'c, 'd>(response: &'c mut ResponseWriter<'d>,
                                 templates: Arc<RWLock<HashMap<&'static str, Template>>>)
                                -> Response<'c, 'd> {
        Response {
            origin: response,
            templates: templates
        }
    }

    /// Sets the content type by it's short form.
    /// Returns the response for chaining.
    ///
    /// # Example
    /// ```{rust}
    /// # use nickel::{Request, Response};
    /// fn handler(request: &Request, response: &mut Response) {
    ///     response.content_type("html");
    /// }
    /// ```
    pub fn content_type(&mut self, text: &str) -> &mut Response<'a,'b> {
        self.origin.headers.content_type = get_media_type(text);
        self
    }

    /// Sets the status code and returns the response for chaining
    ///
    /// # Example
    /// ```{rust}
    /// # extern crate http;
    /// # extern crate nickel;
    /// # use nickel::{Request, Response};
    /// # fn main() {
    /// fn handler(request: &Request, response: &mut Response) {
    ///     response.status_code(http::status::NotFound);
    /// }
    /// # }
    /// ```
    pub fn status_code(&mut self, status: http::status::Status) -> &mut Response<'a,'b> {
        self.origin.status = status;
        self
    }

    /// Writes a response
    ///
    /// # Example
    /// ```{rust}
    /// # use nickel::{Request, Response};
    /// fn handler(request: &Request, response: &mut Response) {
    ///     response.send("hello world");
    /// }
    /// ```
    pub fn send<T: BytesContainer> (&mut self, text: T) {
        // TODO: This needs to be more sophisticated to return the correct headers
        // not just "some headers" :)
        Response::set_headers(self.origin);
        let _ = self.origin.write(text.container_as_bytes());
    }

    fn set_headers(response_writer: &mut http::server::ResponseWriter) {
        let ref mut headers = response_writer.headers;
        headers.date = Some(time::now_utc());

        // we don't need to set this https://github.com/Ogeon/rustful/issues/3#issuecomment-44787613
        headers.content_length = None;
        if headers.content_type.is_none() {
            headers.content_type = get_media_type("txt");
        }

        headers.server = Some(String::from_str("Nickel"));
    }

    /// Writes a file to the output.
    ///
    /// # Example
    /// ```{rust}
    /// # use nickel::{Request, Response};
    /// fn handler(request: &Request, response: &mut Response) {
    ///     let favicon = Path::new("/assets/favicon.ico");
    ///     response.send_file(&favicon).ok().expect("Failed to send favicon");
    /// }
    /// ```
    pub fn send_file(&mut self, path: &Path) -> IoResult<()> {
        let mut file = try!(File::open(path));
        self.origin.headers.content_length = None;

        self.origin.headers.content_type = path.extension_str().and_then(get_media_type);
        self.origin.headers.server = Some(String::from_str("Nickel"));
        copy(&mut file, self.origin)
    }

    /// Renders the given template bound with the given data.
    ///
    /// # Example
    /// ```{rust}
    /// # use nickel::{Request, Response};
    /// # use std::collections::hashmap::HashMap;
    /// fn handler(request: &Request, response: &mut Response) {
    ///     let mut data = HashMap::new();
    ///     data.insert("name", "user");
    ///     response.render("examples/assets/template.tpl", &data);
    /// }
    /// ```
    pub fn render<'a, T: Encodable<Encoder<'a>, Error>>
        (&mut self, path: &'static str, data: &T) {
            // Fast path doesn't need writer lock
            match self.templates.read().find(&path) {
                Some(t) => {
                    let _ = t.render(self.origin, data);
                    return
                },
                None => {}
            }

            // We didn't find the template, get writers lock
            let mut templates = self.templates.write();
            // Search again incase there was a race to compile the template
            let template = match templates.entry(path) {
                Vacant(entry) => {
                    let mut file = File::open(&Path::new(path));
                    let raw_template =
                        file.read_to_string()
                            .ok()
                            .expect(format!("Couldn't open the template file: {}",
                                            path).as_slice());

                    entry.set(mustache::compile_str(raw_template.as_slice()))
                },
                Occupied(entry) => entry.into_mut()
            };

            let _ = template.render(self.origin, data);
    }
}

#[test]
fn matches_content_type () {
    let path = &Path::new("test.txt");
    let content_type = path.extension_str().and_then(get_media_type).unwrap();

    assert_eq!(content_type.type_.as_slice(), "text");
    assert_eq!(content_type.subtype.as_slice(), "plain");
}
<|endoftext|>


<commit_before>// run-rustfix
// edition:2018

#![warn(clippy::use_self)]
#![allow(dead_code)]
#![allow(clippy::should_implement_trait)]

fn main() {}

mod use_self {
    struct Foo {}

    impl Foo {
        fn new() -> Foo {
            Foo {}
        }
        fn test() -> Foo {
            Foo::new()
        }
    }

    impl Default for Foo {
        fn default() -> Foo {
            Foo::new()
        }
    }
}

mod better {
    struct Foo {}

    impl Foo {
        fn new() -> Self {
            Self {}
        }
        fn test() -> Self {
            Self::new()
        }
    }

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

mod lifetimes {
    struct Foo<'a> {
        foo_str: &'a str,
    }

    impl<'a> Foo<'a> {
        // Cannot use `Self` as return type, because the function is actually `fn foo<'b>(s: &'b str) ->
        // Foo<'b>`
        fn foo(s: &str) -> Foo {
            Foo { foo_str: s }
        }
        // cannot replace with `Self`, because that's `Foo<'a>`
        fn bar() -> Foo<'static> {
            Foo { foo_str: "foo" }
        }

        // FIXME: the lint does not handle lifetimed struct
        // `Self` should be applicable here
        fn clone(&self) -> Foo<'a> {
            Foo { foo_str: self.foo_str }
        }
    }
}

mod issue2894 {
    trait IntoBytes {
        #[allow(clippy::clippy::wrong_self_convention)]
        fn into_bytes(&self) -> Vec<u8>;
    }

    // This should not be linted
    impl IntoBytes for u8 {
        fn into_bytes(&self) -> Vec<u8> {
            vec![*self]
        }
    }
}

mod existential {
    struct Foo;

    impl Foo {
        fn bad(foos: &[Self]) -> impl Iterator<Item = &Foo> {
            foos.iter()
        }

        fn good(foos: &[Self]) -> impl Iterator<Item = &Self> {
            foos.iter()
        }
    }
}

mod tuple_structs {
    pub struct TS(i32);

    impl TS {
        pub fn ts() -> Self {
            TS(0)
        }
    }
}

mod macros {
    macro_rules! use_self_expand {
        () => {
            fn new() -> Foo {
                Foo {}
            }
        };
    }

    struct Foo {}

    impl Foo {
        use_self_expand!(); // Should lint in local macros
    }
}

mod nesting {
    struct Foo {}
    impl Foo {
        fn foo() {
            #[allow(unused_imports)]
            use self::Foo; // Can't use Self here
            struct Bar {
                foo: Foo, // Foo != Self
            }

            impl Bar {
                fn bar() -> Bar {
                    Bar { foo: Foo {} }
                }
            }

            // Can't use Self here
            fn baz() -> Foo {
                Foo {}
            }
        }

        // Should lint here
        fn baz() -> Foo {
            Foo {}
        }
    }

    enum Enum {
        A,
        B(u64),
        C { field: bool },
    }
    impl Enum {
        fn method() {
            #[allow(unused_imports)]
            use self::Enum::*; // Issue 3425
            static STATIC: Enum = Enum::A; // Can't use Self as type
        }

        fn method2() {
            let _ = Enum::B(42);
            let _ = Enum::C { field: true };
            let _ = Enum::A;
        }
    }
}

mod issue3410 {

    struct A;
    struct B;

    trait Trait<T> {
        fn a(v: T);
    }

    impl Trait<Vec<A>> for Vec<B> {
        fn a(_: Vec<A>) {}
    }
}

#[allow(clippy::no_effect, path_statements)]
mod rustfix {
    mod nested {
        pub struct A {}
    }

    impl nested::A {
        const A: bool = true;

        fn fun_1() {}

        fn fun_2() {
            nested::A::fun_1();
            nested::A::A;

            nested::A {};
        }
    }
}

mod issue3567 {
    struct TestStruct {}
    impl TestStruct {
        fn from_something() -> Self {
            Self {}
        }
    }

    trait Test {
        fn test() -> TestStruct;
    }

    impl Test for TestStruct {
        fn test() -> TestStruct {
            TestStruct::from_something()
        }
    }
}

mod paths_created_by_lowering {
    use std::ops::Range;

    struct S {}

    impl S {
        const A: usize = 0;
        const B: usize = 1;

        async fn g() -> S {
            S {}
        }

        fn f<'a>(&self, p: &'a [u8]) -> &'a [u8] {
            &p[S::A..S::B]
        }
    }

    trait T {
        fn f<'a>(&self, p: &'a [u8]) -> &'a [u8];
    }

    impl T for Range<u8> {
        fn f<'a>(&self, p: &'a [u8]) -> &'a [u8] {
            &p[0..1]
        }
    }
}
<commit_msg>Update tests/ui/use_self.rs<commit_after>// run-rustfix
// edition:2018

#![warn(clippy::use_self)]
#![allow(dead_code)]
#![allow(clippy::should_implement_trait)]

fn main() {}

mod use_self {
    struct Foo {}

    impl Foo {
        fn new() -> Foo {
            Foo {}
        }
        fn test() -> Foo {
            Foo::new()
        }
    }

    impl Default for Foo {
        fn default() -> Foo {
            Foo::new()
        }
    }
}

mod better {
    struct Foo {}

    impl Foo {
        fn new() -> Self {
            Self {}
        }
        fn test() -> Self {
            Self::new()
        }
    }

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

mod lifetimes {
    struct Foo<'a> {
        foo_str: &'a str,
    }

    impl<'a> Foo<'a> {
        // Cannot use `Self` as return type, because the function is actually `fn foo<'b>(s: &'b str) ->
        // Foo<'b>`
        fn foo(s: &str) -> Foo {
            Foo { foo_str: s }
        }
        // cannot replace with `Self`, because that's `Foo<'a>`
        fn bar() -> Foo<'static> {
            Foo { foo_str: "foo" }
        }

        // FIXME: the lint does not handle lifetimed struct
        // `Self` should be applicable here
        fn clone(&self) -> Foo<'a> {
            Foo { foo_str: self.foo_str }
        }
    }
}

mod issue2894 {
    trait IntoBytes {
        #[allow(clippy::wrong_self_convention)]
        fn into_bytes(&self) -> Vec<u8>;
    }

    // This should not be linted
    impl IntoBytes for u8 {
        fn into_bytes(&self) -> Vec<u8> {
            vec![*self]
        }
    }
}

mod existential {
    struct Foo;

    impl Foo {
        fn bad(foos: &[Self]) -> impl Iterator<Item = &Foo> {
            foos.iter()
        }

        fn good(foos: &[Self]) -> impl Iterator<Item = &Self> {
            foos.iter()
        }
    }
}

mod tuple_structs {
    pub struct TS(i32);

    impl TS {
        pub fn ts() -> Self {
            TS(0)
        }
    }
}

mod macros {
    macro_rules! use_self_expand {
        () => {
            fn new() -> Foo {
                Foo {}
            }
        };
    }

    struct Foo {}

    impl Foo {
        use_self_expand!(); // Should lint in local macros
    }
}

mod nesting {
    struct Foo {}
    impl Foo {
        fn foo() {
            #[allow(unused_imports)]
            use self::Foo; // Can't use Self here
            struct Bar {
                foo: Foo, // Foo != Self
            }

            impl Bar {
                fn bar() -> Bar {
                    Bar { foo: Foo {} }
                }
            }

            // Can't use Self here
            fn baz() -> Foo {
                Foo {}
            }
        }

        // Should lint here
        fn baz() -> Foo {
            Foo {}
        }
    }

    enum Enum {
        A,
        B(u64),
        C { field: bool },
    }
    impl Enum {
        fn method() {
            #[allow(unused_imports)]
            use self::Enum::*; // Issue 3425
            static STATIC: Enum = Enum::A; // Can't use Self as type
        }

        fn method2() {
            let _ = Enum::B(42);
            let _ = Enum::C { field: true };
            let _ = Enum::A;
        }
    }
}

mod issue3410 {

    struct A;
    struct B;

    trait Trait<T> {
        fn a(v: T);
    }

    impl Trait<Vec<A>> for Vec<B> {
        fn a(_: Vec<A>) {}
    }
}

#[allow(clippy::no_effect, path_statements)]
mod rustfix {
    mod nested {
        pub struct A {}
    }

    impl nested::A {
        const A: bool = true;

        fn fun_1() {}

        fn fun_2() {
            nested::A::fun_1();
            nested::A::A;

            nested::A {};
        }
    }
}

mod issue3567 {
    struct TestStruct {}
    impl TestStruct {
        fn from_something() -> Self {
            Self {}
        }
    }

    trait Test {
        fn test() -> TestStruct;
    }

    impl Test for TestStruct {
        fn test() -> TestStruct {
            TestStruct::from_something()
        }
    }
}

mod paths_created_by_lowering {
    use std::ops::Range;

    struct S {}

    impl S {
        const A: usize = 0;
        const B: usize = 1;

        async fn g() -> S {
            S {}
        }

        fn f<'a>(&self, p: &'a [u8]) -> &'a [u8] {
            &p[S::A..S::B]
        }
    }

    trait T {
        fn f<'a>(&self, p: &'a [u8]) -> &'a [u8];
    }

    impl T for Range<u8> {
        fn f<'a>(&self, p: &'a [u8]) -> &'a [u8] {
            &p[0..1]
        }
    }
}
<|endoftext|>


<commit_before>
//! Template handling.

use std::rc;
use std::str;
use std::path;
use std::io;
use std::fs;
use std::fmt;
use std::error;

use event;
use parse;
use transform;
use text;

/// Invalid input.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum InputError {
    /// The input exceeded the configured length limit.
    LengthLimitExceeded {
        /// The exceeded limit.
        limit: usize,
    },
    /// The input could not be parsed.
    Parse {
        /// Actual parse error.
        error: parse::Error,
    },
}

impl error::Error for InputError {

    fn description(&self) -> &str { "Input error" }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            InputError::Parse { ref error } => Some(error),
            _ => None,
        }
    }
}

impl fmt::Display for InputError {

    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            InputError::Parse { .. } =>
                write!(fmt, "Unable to parse input into HTML5 stream"),
            InputError::LengthLimitExceeded { limit } =>
                write!(fmt, "Input length limit ({}) was exceeded", limit),
        }
    }
}

/// An error occured while reading a HTML5 file.
#[derive(Debug)]
pub enum FileError {
    /// The file could not be opened.
    Open {
        /// Filename we tried to open.
        path: path::PathBuf,
        /// Actual open error.
        error: io::Error,
    },
    /// The file could not be read.
    Read {
        /// Filename we tried to read.
        path: path::PathBuf,
        /// Actual read error.
        error: io::Error,
    },
    /// There was an error with the input.
    Input {
        /// Filename producing the invalid input.
        path: path::PathBuf,
        /// Actual input error.
        error: InputError,
    },
    /// The file content could not be decoded as UTF-8.
    Decode {
        /// Filename we tried to decode.
        path: path::PathBuf,
        /// Actual decoding error.
        error: str::Utf8Error,
    },
}

impl error::Error for FileError {

    fn description(&self) -> &str { "File error" }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            FileError::Input { ref error, .. } => Some(error),
            FileError::Open { ref error, .. } => Some(error),
            FileError::Read { ref error, .. } => Some(error),
            FileError::Decode { ref error, .. } => Some(error),
        }
    }
}

impl fmt::Display for FileError {

    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let (action, path) = match *self {
            FileError::Input { ref path, .. } => ("process", path),
            FileError::Open { ref path, .. } => ("open", path),
            FileError::Read { ref path, .. } => ("read", path),
            FileError::Decode { ref path, .. } => ("decode", path),
        };
        write!(fmt, "Unable to {} file '{}'", action, path.display())
    }
}

/// Event stream produced by a template.
#[derive(Debug)]
pub struct TemplateStream {
    events: rc::Rc<Vec<event::Event>>,
    index: usize,
}

impl event::Stream for TemplateStream {

    fn next_event(&mut self) -> event::StreamResult {
        match self.events.get(self.index) {
            Some(event) => {
                self.index += 1;
                Ok(Some(event.clone()))
            },
            None => Ok(None),
        }
    }
}

/// A complete HTML5 fragment.
///
/// Templates are collected sequences of events that are used as source for transformations.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Template {
    events: rc::Rc<Vec<event::Event>>,
}

impl Template {

    /// Load a template from a file.
    pub fn from_file
(path: P, options: parse::Options) -> Result<Template, FileError>
    where P: AsRef<path::Path> {
        use std::io::{ BufRead };

        let path = path.as_ref();

        let mut buffer = fs::File::open(path)
            .map(io::BufReader::new)
            .map_err(|error| FileError::Open {
                path: path.into(),
                error,
            })?;

        let mut input = String::new();
        let limit = options
            .max_input_len
            .unwrap_or_else(usize::max_value);

        'read: loop {

            let consumed_len = {
                let data = buffer.fill_buf()
                    .map_err(|error| FileError::Read {
                        path: path.into(),
                        error,
                    })?;

                if data.is_empty() {
                    break 'read;
                }

                let valid_data = match str::from_utf8(data) {
                    Ok(valid_data) => valid_data,
                    Err(error) =>
                        if error.valid_up_to() == 0 {
                            return Err(FileError::Decode {
                                path: path.into(),
                                error,
                            });
                        } else {
                            str::from_utf8(&data[..error.valid_up_to()])
                                .expect("verified utf8")
                        },
                };

                input.push_str(valid_data);
                valid_data.len()
            };

            if input.len() > limit {
                return Err(FileError::Input {
                    path: path.into(),
                    error: InputError::LengthLimitExceeded { limit },
                });
            }

            buffer.consume(consumed_len);
        }

        Template::from_str(&input, options)
            .map_err(|error| FileError::Input {
                path: path.into(),
                error,
            })
    }

    /// Load a template from a `&str`.
    pub fn from_str(input: &str, options: parse::Options) -> Result<Template, InputError> {

        if let Some(limit) = options.max_input_len {
            if input.len() > limit {
                return Err(InputError::LengthLimitExceeded {
                    limit,
                });
            }
        }

        Ok(Template {
            events: parse::Iter::new(input, options)
                .collect::<Result<_, _>>()
                .map(rc::Rc::new)
                .map_err(|error| InputError::Parse { error })?,
        })
    }

    /// Create a template with a single empty element.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::error;
    /// # fn run() -> Result<(), Box<error::Error>> {
    /// use html5_fuser::{ Template, ParseOptions };
    ///
    /// let template = Template::from_str(r#"
    ///     <body></body>
    /// "#, ParseOptions::default())?;
    ///
    /// let output = format!("{}", template.transform(|html| html
    ///     .select_once("body", |html| html
    ///         .replace_contents(
    ///             Template::with_element("a")
    ///             .map_err(Into::into)
    ///             .and_then(|template| template
    ///                 .transform(|html| html
    ///                     .select_once("a", |html| html
    ///                         .set_attribute_with_value("href", "index.html")
    ///                         .replace_contents("Home")
    ///                     )
    ///                 )
    ///             )
    ///         )
    ///     )
    /// )?);
    ///
    /// assert!(output.contains(
    ///     r#"<body><a href="index.html">Home</a></body>"#,
    /// ));
    /// # Ok(()) }
    /// # fn main() { run().unwrap() }
    /// ```
    pub fn with_element<T>(tag: T) -> Result<Template, text::IdentifierError>
    where T: text::IntoIdentifier {
        let tag = tag.into_identifier()?;
        let event = {
            let attributes = event::Attributes::new(Vec::new());
            if parse::is_void_tag(&tag) {
                event::Event(event::EventKind::VoidTag { tag, attributes })
            } else {
                event::Event(event::EventKind::SelfClosedTag { tag, attributes })
            }
        };
        let mut events = Vec::new();
        events.push(event);
        let events = rc::Rc::new(events);
        Ok(Template { events })
    }

    pub(crate) fn to_stream(&self) -> TemplateStream {
        TemplateStream {
            events: self.events.clone(),
            index: 0,
        }
    }

    pub(crate) fn from_stream<S>(mut stream: S) -> Result<Template, event::StreamError>
    where S: event::Stream {
        let mut events = Vec::new();

        while let Some(event) = stream.next_event_skip_noop()? {
            events.push(event);
        }

        Ok(Template {
            events: rc::Rc::new(events),
        })
    }

    /// Apply a transform to the template. If successful, this produces a new template.
    pub fn transform(&self, builder: B) -> Result<Template, event::StreamError>
    where
        B: for<'t> FnOnce(transform::Api<'t, TemplateStream>) -> transform::Api<'t, R>,
        R: event::Stream,
    {
        let stream = transform::build_once(self.to_stream(), builder);
        Template::from_stream(stream)
    }
}

impl fmt::Display for Template {

    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        for event in self.events.iter() {
            fmt::Display::fmt(event, fmt)?;
        }
        Ok(())
    }
}

impl event::IntoStream for rc::Rc<Template> {

    type Stream = TemplateStream;

    fn into_stream(self) -> TemplateStream {
        self.to_stream()
    }
}

impl<'t> event::IntoStream for &'t Template {

    type Stream = TemplateStream;

    fn into_stream(self) -> TemplateStream {
        self.to_stream()
    }
}

impl event::IntoStream for Template {

    type Stream = TemplateStream;

    fn into_stream(self) -> TemplateStream {
        self.to_stream()
    }
}

#[cfg(test)]
mod tests {
    use std::str::{ FromStr };
    use std::rc;

    #[test]
    fn into_stream_ref() {
        let new = ::Template::from_str("", Default::default()).unwrap();
        test_transform!(
            Default::default(),
            "",
            "",
            |html| html
                .select(::select::Tag::from_str("a").unwrap(), |html| html
                    .replace_contents(&new)
                )
        );
    }

    #[test]
    fn into_stream_rc() {
        let new = rc::Rc::new(::Template::from_str("", Default::default()).unwrap());
        test_transform!(
            Default::default(),
            "",
            "",
            |html| html
                .select(::select::Tag::from_str("a").unwrap(), |html| html
                    .replace_contents(new.clone())
                )
        );
    }

    #[test]
    fn into_stream() {
        test_transform!(
            Default::default(),
            "",
            "",
            |html| html
                .select(::select::Tag::from_str("a").unwrap(), |html| html
                    .replace_contents(
                        ::Template::from_str("", Default::default()).unwrap(),
                    )
                )
        );
    }

    #[test]
    fn roundtrip() {
        let original = "foo";
        test_transform!(Default::default(), original, original, |html| html);
        test_transform!(Default::default(), "", "", |html| html);
        test_transform!(Default::default(), "foo", "foo", |html| html);
    }
}
<commit_msg>moved template tests to new test structure<commit_after>
//! Template handling.

use std::rc;
use std::str;
use std::path;
use std::io;
use std::fs;
use std::fmt;
use std::error;

use event;
use parse;
use transform;
use text;

/// Invalid input.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum InputError {
    /// The input exceeded the configured length limit.
    LengthLimitExceeded {
        /// The exceeded limit.
        limit: usize,
    },
    /// The input could not be parsed.
    Parse {
        /// Actual parse error.
        error: parse::Error,
    },
}

impl error::Error for InputError {

    fn description(&self) -> &str { "Input error" }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            InputError::Parse { ref error } => Some(error),
            _ => None,
        }
    }
}

impl fmt::Display for InputError {

    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            InputError::Parse { .. } =>
                write!(fmt, "Unable to parse input into HTML5 stream"),
            InputError::LengthLimitExceeded { limit } =>
                write!(fmt, "Input length limit ({}) was exceeded", limit),
        }
    }
}

/// An error occured while reading a HTML5 file.
#[derive(Debug)]
pub enum FileError {
    /// The file could not be opened.
    Open {
        /// Filename we tried to open.
        path: path::PathBuf,
        /// Actual open error.
        error: io::Error,
    },
    /// The file could not be read.
    Read {
        /// Filename we tried to read.
        path: path::PathBuf,
        /// Actual read error.
        error: io::Error,
    },
    /// There was an error with the input.
    Input {
        /// Filename producing the invalid input.
        path: path::PathBuf,
        /// Actual input error.
        error: InputError,
    },
    /// The file content could not be decoded as UTF-8.
    Decode {
        /// Filename we tried to decode.
        path: path::PathBuf,
        /// Actual decoding error.
        error: str::Utf8Error,
    },
}

impl error::Error for FileError {

    fn description(&self) -> &str { "File error" }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            FileError::Input { ref error, .. } => Some(error),
            FileError::Open { ref error, .. } => Some(error),
            FileError::Read { ref error, .. } => Some(error),
            FileError::Decode { ref error, .. } => Some(error),
        }
    }
}

impl fmt::Display for FileError {

    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let (action, path) = match *self {
            FileError::Input { ref path, .. } => ("process", path),
            FileError::Open { ref path, .. } => ("open", path),
            FileError::Read { ref path, .. } => ("read", path),
            FileError::Decode { ref path, .. } => ("decode", path),
        };
        write!(fmt, "Unable to {} file '{}'", action, path.display())
    }
}

/// Event stream produced by a template.
#[derive(Debug)]
pub struct TemplateStream {
    events: rc::Rc<Vec<event::Event>>,
    index: usize,
}

impl event::Stream for TemplateStream {

    fn next_event(&mut self) -> event::StreamResult {
        match self.events.get(self.index) {
            Some(event) => {
                self.index += 1;
                Ok(Some(event.clone()))
            },
            None => Ok(None),
        }
    }
}

/// A complete HTML5 fragment.
///
/// Templates are collected sequences of events that are used as source for transformations.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Template {
    events: rc::Rc<Vec<event::Event>>,
}

impl Template {

    /// Load a template from a file.
    pub fn from_file
(path: P, options: parse::Options) -> Result<Template, FileError>
    where P: AsRef<path::Path> {
        use std::io::{ BufRead };

        let path = path.as_ref();

        let mut buffer = fs::File::open(path)
            .map(io::BufReader::new)
            .map_err(|error| FileError::Open {
                path: path.into(),
                error,
            })?;

        let mut input = String::new();
        let limit = options
            .max_input_len
            .unwrap_or_else(usize::max_value);

        'read: loop {

            let consumed_len = {
                let data = buffer.fill_buf()
                    .map_err(|error| FileError::Read {
                        path: path.into(),
                        error,
                    })?;

                if data.is_empty() {
                    break 'read;
                }

                let valid_data = match str::from_utf8(data) {
                    Ok(valid_data) => valid_data,
                    Err(error) =>
                        if error.valid_up_to() == 0 {
                            return Err(FileError::Decode {
                                path: path.into(),
                                error,
                            });
                        } else {
                            str::from_utf8(&data[..error.valid_up_to()])
                                .expect("verified utf8")
                        },
                };

                input.push_str(valid_data);
                valid_data.len()
            };

            if input.len() > limit {
                return Err(FileError::Input {
                    path: path.into(),
                    error: InputError::LengthLimitExceeded { limit },
                });
            }

            buffer.consume(consumed_len);
        }

        Template::from_str(&input, options)
            .map_err(|error| FileError::Input {
                path: path.into(),
                error,
            })
    }

    /// Load a template from a `&str`.
    pub fn from_str(input: &str, options: parse::Options) -> Result<Template, InputError> {

        if let Some(limit) = options.max_input_len {
            if input.len() > limit {
                return Err(InputError::LengthLimitExceeded {
                    limit,
                });
            }
        }

        Ok(Template {
            events: parse::Iter::new(input, options)
                .collect::<Result<_, _>>()
                .map(rc::Rc::new)
                .map_err(|error| InputError::Parse { error })?,
        })
    }

    /// Create a template with a single empty element.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::error;
    /// # fn run() -> Result<(), Box<error::Error>> {
    /// use html5_fuser::{ Template, ParseOptions };
    ///
    /// let template = Template::from_str(r#"
    ///     <body></body>
    /// "#, ParseOptions::default())?;
    ///
    /// let output = format!("{}", template.transform(|html| html
    ///     .select_once("body", |html| html
    ///         .replace_contents(
    ///             Template::with_element("a")
    ///             .map_err(Into::into)
    ///             .and_then(|template| template
    ///                 .transform(|html| html
    ///                     .select_once("a", |html| html
    ///                         .set_attribute_with_value("href", "index.html")
    ///                         .replace_contents("Home")
    ///                     )
    ///                 )
    ///             )
    ///         )
    ///     )
    /// )?);
    ///
    /// assert!(output.contains(
    ///     r#"<body><a href="index.html">Home</a></body>"#,
    /// ));
    /// # Ok(()) }
    /// # fn main() { run().unwrap() }
    /// ```
    pub fn with_element<T>(tag: T) -> Result<Template, text::IdentifierError>
    where T: text::IntoIdentifier {
        let tag = tag.into_identifier()?;
        let event = {
            let attributes = event::Attributes::new(Vec::new());
            if parse::is_void_tag(&tag) {
                event::Event(event::EventKind::VoidTag { tag, attributes })
            } else {
                event::Event(event::EventKind::SelfClosedTag { tag, attributes })
            }
        };
        let mut events = Vec::new();
        events.push(event);
        let events = rc::Rc::new(events);
        Ok(Template { events })
    }

    pub(crate) fn to_stream(&self) -> TemplateStream {
        TemplateStream {
            events: self.events.clone(),
            index: 0,
        }
    }

    pub(crate) fn from_stream<S>(mut stream: S) -> Result<Template, event::StreamError>
    where S: event::Stream {
        let mut events = Vec::new();

        while let Some(event) = stream.next_event_skip_noop()? {
            events.push(event);
        }

        Ok(Template {
            events: rc::Rc::new(events),
        })
    }

    /// Apply a transform to the template. If successful, this produces a new template.
    pub fn transform(&self, builder: B) -> Result<Template, event::StreamError>
    where
        B: for<'t> FnOnce(transform::Api<'t, TemplateStream>) -> transform::Api<'t, R>,
        R: event::Stream,
    {
        let stream = transform::build_once(self.to_stream(), builder);
        Template::from_stream(stream)
    }
}

impl fmt::Display for Template {

    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        for event in self.events.iter() {
            fmt::Display::fmt(event, fmt)?;
        }
        Ok(())
    }
}

impl event::IntoStream for rc::Rc<Template> {

    type Stream = TemplateStream;

    fn into_stream(self) -> TemplateStream {
        self.to_stream()
    }
}

impl<'t> event::IntoStream for &'t Template {

    type Stream = TemplateStream;

    fn into_stream(self) -> TemplateStream {
        self.to_stream()
    }
}

impl event::IntoStream for Template {

    type Stream = TemplateStream;

    fn into_stream(self) -> TemplateStream {
        self.to_stream()
    }
}

#[cfg(test)]
mod tests {

    test_group!(into_stream:
        "template reference" => {
            let new = ::Template::from_str("", Default::default()).unwrap();
            transform_test!(
                "",
                "",
                |html| html.select("a", |html| html.replace_contents(&new)),
            );
        },
        "template rc" => {
            use std::rc;
            let new = rc::Rc::new(::Template::from_str("", Default::default()).unwrap());
            transform_test!(
                "",
                "",
                |html| html.select("a", |html| html.replace_contents(new.clone())),
            );
        },
        "template plain" => transform_test!(
            "",
            "",
            |html| html.select("a", |html| html.replace_contents(
                ::Template::from_str("", Default::default()).unwrap(),
            )),
        ),
    );

    test_group!(round_trip:
        "nested" => transform_test!("foo", "foo", |html| html),
        "empty" => transform_test!("", "", |html| html),
        "data only" => transform_test!("foo", "foo", |html| html),
    );
}
<|endoftext|>


<commit_before>/* Copyright (C)  2016 nokaa <nokaa@cock.li>
 * This software is licensed under the terms of the
 * GNU Affero General Public License. You should have
 * received a copy of this license with this software.
 * The license may also be found at https://gnu.org/licenses/agpl.txt
 */

mod command;
mod cursor;
mod insert;
mod normal;

use rustty::{self, Event, Color};
use editor;

/// `Term` represents our client application. This allows
/// us to work with the filesystem and the UI.
pub struct Term<'a> {
    /// Represents the location of the cursor in our UI
    cursor: cursor::Cursor,
    /// Contains file information; allows us to work with
    /// the filesystem
    editor: &'a mut editor::Editor<'a>,
    /// This is the UI itself
    term: rustty::Terminal,
    /// Represents the running status
    quit: bool,
    /// Represents the topmost line of the file we are editing in our UI
    line: usize,
    /// Represents the total number of lines in the currently
    /// open file
    total_lines: usize,
    partial_lines: Vec<usize>,
}

impl<'a> Term<'a> {
    /// Creates a new `Term` using the given `editor`.
    pub fn new(editor: &'a mut editor::Editor<'a>) -> Term<'a> {
        Term {
            cursor: cursor::Cursor::new(Color::Red),
            editor: editor,
            term: rustty::Terminal::new().unwrap(),
            quit: false,
            line: 0,
            total_lines: 0,
            partial_lines: vec![],
        }
    }

    /// Launches the terminal.
    pub fn run(&mut self) {
        self.editor.read_file();
        let lines = self.editor.contents.len() as isize;
        self.set_total_lines(lines);

        self.term[self.cursor.current_pos()].set_bg(self.cursor.color);
        let current_line = self.current_line();
        self.print_file(current_line);
        self.prompt();
        self.term.swap_buffers().unwrap();

        while !self.quit {
            let evt = self.term.get_event(100).unwrap();
            if let Some(Event::Key(ch)) = evt {
                if self.editor.normal_mode() {
                    normal::handle(self, ch);
                } else if self.editor.command_mode() {
                    command::handle(self, ch);
                } else {
                    insert::handle(self, ch);
                }

                if self.cursor.pos.x > self.term.cols() - 1 {
                    self.term[self.cursor.last_pos()].set_bg(Color::Default);
                    self.cursor.save_pos();
                    self.cursor.pos.x = 0;
                    self.cursor.pos.y += 1;
                }
                if self.cursor.pos.y >= self.term.rows() - 1 {
                    self.term[self.cursor.last_pos()].set_bg(Color::Default);
                    self.cursor.save_pos();
                    self.cursor.pos.x = 0;
                    self.cursor.pos.y = 0;
                }

                self.term[self.cursor.last_pos()].set_bg(Color::Default);
                self.term[self.cursor.current_pos()].set_bg(self.cursor.color);
                self.term.swap_buffers().unwrap();
            }
        }
    }

    /// Prints our prompt to the UI.
    pub fn prompt(&mut self) {
        let w = self.term.cols();
        let h = self.term.rows();

        for i in 0..w {
            self.term[(i, h - 2)].set_bg(Color::Red);
        }

        for (i, c) in self.editor.filename().chars().enumerate() {
            self.term[(i, h - 2)].set_ch(c);
        }
    }

    /// Prints our editor's contents to the UI.
    fn print_file(&mut self, start: usize) {
        self.partial_lines = vec![];
        let w = self.term.cols();
        let mut i = 0;
        let mut j = 0;
        for line in &self.editor.contents {
            if i < start {
                i += 1;
                continue;
            }

            for &b in line {
                if b == b'\n' {
                    continue;
                } else if j == w {
                    i += 1;
                    j = 0;
                    self.partial_lines.push(i - start);
                }

                self.term[(j, i - start)].set_ch(b as char);
                j += 1;
            }
            while j < w {
                self.term[(j, i - start)].set_ch(' ');
                j += 1;
            }

            i += 1;
            j = 0;
            if i - start == self.term.rows() - 2 {
                break;
            }
        }
    }

    /// Handles moving the cursor
    pub fn move_cursor(&mut self, direction: cursor::Direction) {
        match direction {
            cursor::Direction::Up => {
                if self.cursor.pos.y > 0 {
                    self.cursor.save_pos();
                    let mut i = self.cursor.pos.y - 1;
                    while self.partial_lines.contains(&i) {
                        self.cursor.pos.y -= 1;
                        i -= 1;
                    }
                    self.cursor.pos.y -= 1;
                    let curr = self.current_line() - 1;
                    self.set_current_line(curr);

                    let len = self.editor.contents[curr].len() - 1;
                    if len == 0 && self.cursor.pos.x > len {
                        self.cursor.pos.x = len;
                        self.cursor.in_line = len;
                    } else if len > 0 && self.cursor.pos.x > len - 1 {
                        self.cursor.pos.x = len - 1;
                        self.cursor.in_line = len - 1;
                    }
                }
            }
            cursor::Direction::Down => {
                if self.cursor.pos.y < self.term.rows() - 3 {
                    let curr = self.current_line();
                    let len = self.editor.contents[curr].len() - 1;

                    self.cursor.save_pos();
                    self.set_current_line(curr + 1);

                    if len > self.term.cols() {
                        let mut adv = len / self.term.cols();
                        if len % self.term.cols() > 0 {
                            adv += 1;
                        }
                        if self.partial_lines.contains(&self.cursor.pos.y) {
                            adv -= 1;
                        }
                        self.cursor.pos.y += adv;
                    } else {
                        self.cursor.pos.y += 1;
                    }

                    let curr = self.current_line();
                    let len = self.editor.contents[curr].len() - 1;
                    if len == 0 && self.cursor.pos.x > len {
                        self.cursor.pos.x = len;
                        self.cursor.in_line = len;
                    } else if len > 0 && self.cursor.pos.x > len - 1 {
                        self.cursor.pos.x = len - 1;
                        self.cursor.in_line = len - 1;
                    }
                }
            }
            cursor::Direction::Left => {
                let y = self.cursor.pos.y;

                if self.cursor.pos.x != 0 {
                    self.cursor.save_pos();
                    self.cursor.pos.x -= 1;
                    self.cursor.in_line -= 1;
                } else if self.partial_lines.contains(&y) {
                    self.cursor.save_pos();
                    self.cursor.pos.y -= 1;
                    self.cursor.pos.x = self.term.cols() - 1;
                    self.cursor.in_line -= 1;
                }
            }
            cursor::Direction::Right => {
                let (x, y) = self.cursor.current_pos();
                let curr = self.current_line();
                let len = self.editor.contents[curr].len() - 1;

                if len > 0 && self.cursor.in_line < len - 1 {
                    if x < self.term.cols() - 1 {
                        self.cursor.save_pos();
                        self.cursor.pos.x += 1;
                        self.cursor.in_line += 1;
                    } else {
                        self.cursor.save_pos();
                        self.cursor.pos.x = 1;
                        self.cursor.pos.y += 1;
                        self.cursor.in_line += 1;
                    }
                }
            }
        }
    }

    /// Changes the value of the `quit` attribute to `true`.
    pub fn quit(&mut self) {
        self.quit = true;
    }

    /// Returns the total lines in our file
    pub fn total_lines(&self) -> usize {
        self.total_lines
    }

    /// Allows us to modify the total number of lines
    /// in our file, e.g. if a new line is added.
    pub fn set_total_lines(&mut self, change: isize) {
        let new = self.total_lines as isize + change;
        self.total_lines = new as usize;
    }

    /// Gives the current line at the top of our UI
    pub fn current_line(&self) -> usize {
        self.line
    }

    /// Allows us to change what the topmost line in the UI is
    pub fn set_current_line(&mut self, line: usize) {
        self.line = line;
    }

    /// This function redraws the portion of our UI displaying
    /// file contents. E.g. this is called when the current line
    /// changes.
    pub fn redraw_file(&mut self) {
        let current_line = self.current_line();
        self.print_file(current_line);
    }

    /// This function redraws the given line of the UI on the screen.
    pub fn redraw_line(&mut self, ui_line: usize) {
        let file_line = ui_line + self.current_line();
        self.print_line(ui_line, file_line);
    }

    pub fn print_line(&mut self, ui_line: usize, file_line: usize) {
        let contents = &self.editor.contents[file_line];
        let w = self.term.cols();
        let mut i = 0;
        let mut j = 0;

        for &b in contents {
            if b == b'\n' {
                continue;
            } else if i == w {
                i = 0;
                j += 1;
            }
            self.term[(i, ui_line + j)].set_ch(b as char);
            i += 1;
        }

        while i < self.term.cols() {
            self.term[(i, ui_line + j)].set_ch(' ');
            i += 1;
        }
    }
}
<commit_msg>Fix bug with right movement on long lines<commit_after>/* Copyright (C)  2016 nokaa <nokaa@cock.li>
 * This software is licensed under the terms of the
 * GNU Affero General Public License. You should have
 * received a copy of this license with this software.
 * The license may also be found at https://gnu.org/licenses/agpl.txt
 */

mod command;
mod cursor;
mod insert;
mod normal;

use rustty::{self, Event, Color};
use editor;

/// `Term` represents our client application. This allows
/// us to work with the filesystem and the UI.
pub struct Term<'a> {
    /// Represents the location of the cursor in our UI
    cursor: cursor::Cursor,
    /// Contains file information; allows us to work with
    /// the filesystem
    editor: &'a mut editor::Editor<'a>,
    /// This is the UI itself
    term: rustty::Terminal,
    /// Represents the running status
    quit: bool,
    /// Represents the topmost line of the file we are editing in our UI
    line: usize,
    /// Represents the total number of lines in the currently
    /// open file
    total_lines: usize,
    partial_lines: Vec<usize>,
}

impl<'a> Term<'a> {
    /// Creates a new `Term` using the given `editor`.
    pub fn new(editor: &'a mut editor::Editor<'a>) -> Term<'a> {
        Term {
            cursor: cursor::Cursor::new(Color::Red),
            editor: editor,
            term: rustty::Terminal::new().unwrap(),
            quit: false,
            line: 0,
            total_lines: 0,
            partial_lines: vec![],
        }
    }

    /// Launches the terminal.
    pub fn run(&mut self) {
        self.editor.read_file();
        let lines = self.editor.contents.len() as isize;
        self.set_total_lines(lines);

        self.term[self.cursor.current_pos()].set_bg(self.cursor.color);
        let current_line = self.current_line();
        self.print_file(current_line);
        self.prompt();
        self.term.swap_buffers().unwrap();

        while !self.quit {
            let evt = self.term.get_event(100).unwrap();
            if let Some(Event::Key(ch)) = evt {
                if self.editor.normal_mode() {
                    normal::handle(self, ch);
                } else if self.editor.command_mode() {
                    command::handle(self, ch);
                } else {
                    insert::handle(self, ch);
                }

                if self.cursor.pos.x > self.term.cols() - 1 {
                    self.term[self.cursor.last_pos()].set_bg(Color::Default);
                    self.cursor.save_pos();
                    self.cursor.pos.x = 0;
                    self.cursor.pos.y += 1;
                }
                if self.cursor.pos.y >= self.term.rows() - 1 {
                    self.term[self.cursor.last_pos()].set_bg(Color::Default);
                    self.cursor.save_pos();
                    self.cursor.pos.x = 0;
                    self.cursor.pos.y = 0;
                }

                self.term[self.cursor.last_pos()].set_bg(Color::Default);
                self.term[self.cursor.current_pos()].set_bg(self.cursor.color);
                self.term.swap_buffers().unwrap();
            }
        }
    }

    /// Prints our prompt to the UI.
    pub fn prompt(&mut self) {
        let w = self.term.cols();
        let h = self.term.rows();

        for i in 0..w {
            self.term[(i, h - 2)].set_bg(Color::Red);
        }

        for (i, c) in self.editor.filename().chars().enumerate() {
            self.term[(i, h - 2)].set_ch(c);
        }
    }

    /// Prints our editor's contents to the UI.
    fn print_file(&mut self, start: usize) {
        self.partial_lines = vec![];
        let w = self.term.cols();
        let mut i = 0;
        let mut j = 0;
        for line in &self.editor.contents {
            if i < start {
                i += 1;
                continue;
            }

            for &b in line {
                if b == b'\n' {
                    continue;
                } else if j == w {
                    i += 1;
                    j = 0;
                    self.partial_lines.push(i - start);
                }

                self.term[(j, i - start)].set_ch(b as char);
                j += 1;
            }
            while j < w {
                self.term[(j, i - start)].set_ch(' ');
                j += 1;
            }

            i += 1;
            j = 0;
            if i - start == self.term.rows() - 2 {
                break;
            }
        }
    }

    /// Handles moving the cursor
    pub fn move_cursor(&mut self, direction: cursor::Direction) {
        match direction {
            cursor::Direction::Up => {
                if self.cursor.pos.y > 0 {
                    self.cursor.save_pos();
                    let mut i = self.cursor.pos.y - 1;
                    while self.partial_lines.contains(&i) {
                        self.cursor.pos.y -= 1;
                        i -= 1;
                    }
                    self.cursor.pos.y -= 1;
                    let curr = self.current_line() - 1;
                    self.set_current_line(curr);

                    let len = self.editor.contents[curr].len() - 1;
                    if len == 0 && self.cursor.pos.x > len {
                        self.cursor.pos.x = len;
                        self.cursor.in_line = len;
                    } else if len > 0 && self.cursor.pos.x > len - 1 {
                        self.cursor.pos.x = len - 1;
                        self.cursor.in_line = len - 1;
                    }
                }
            }
            cursor::Direction::Down => {
                if self.cursor.pos.y < self.term.rows() - 3 &&
                   self.cursor.pos.y < self.editor.contents.len() - 1
                {
                    let curr = self.current_line();
                    let len = self.editor.contents[curr].len() - 1;

                    self.cursor.save_pos();
                    self.set_current_line(curr + 1);

                    if len > self.term.cols() {
                        let mut adv = len / self.term.cols();
                        if len % self.term.cols() > 0 {
                            adv += 1;
                        }
                        if self.partial_lines.contains(&self.cursor.pos.y) {
                            adv -= 1;
                        }
                        self.cursor.pos.y += adv;
                    } else {
                        self.cursor.pos.y += 1;
                    }

                    let curr = self.current_line();
                    let len = self.editor.contents[curr].len() - 1;
                    if len == 0 && self.cursor.pos.x > len {
                        self.cursor.pos.x = len;
                        self.cursor.in_line = len;
                    } else if len > 0 && self.cursor.pos.x > len - 1 {
                        self.cursor.pos.x = len - 1;
                        self.cursor.in_line = len - 1;
                    }
                }
            }
            cursor::Direction::Left => {
                let y = self.cursor.pos.y;

                if self.cursor.pos.x != 0 {
                    self.cursor.save_pos();
                    self.cursor.pos.x -= 1;
                    self.cursor.in_line -= 1;
                } else if self.partial_lines.contains(&y) {
                    self.cursor.save_pos();
                    self.cursor.pos.y -= 1;
                    self.cursor.pos.x = self.term.cols() - 1;
                    self.cursor.in_line -= 1;
                }
            }
            cursor::Direction::Right => {
                let x = self.cursor.pos.x;
                let curr = self.current_line();
                let len = self.editor.contents[curr].len() - 1;

                if len > 0 && self.cursor.in_line < len - 1 {
                    if x < self.term.cols() - 1 {
                        self.cursor.save_pos();
                        self.cursor.pos.x += 1;
                        self.cursor.in_line += 1;
                    } else {
                        self.cursor.save_pos();
                        self.cursor.pos.x = 0;
                        self.cursor.pos.y += 1;
                        self.cursor.in_line += 1;
                    }
                }
            }
        }
    }

    /// Changes the value of the `quit` attribute to `true`.
    pub fn quit(&mut self) {
        self.quit = true;
    }

    /// Returns the total lines in our file
    pub fn total_lines(&self) -> usize {
        self.total_lines
    }

    /// Allows us to modify the total number of lines
    /// in our file, e.g. if a new line is added.
    pub fn set_total_lines(&mut self, change: isize) {
        let new = self.total_lines as isize + change;
        self.total_lines = new as usize;
    }

    /// Gives the current line at the top of our UI
    pub fn current_line(&self) -> usize {
        self.line
    }

    /// Allows us to change what the topmost line in the UI is
    pub fn set_current_line(&mut self, line: usize) {
        self.line = line;
    }

    /// This function redraws the portion of our UI displaying
    /// file contents. E.g. this is called when the current line
    /// changes.
    pub fn redraw_file(&mut self) {
        let current_line = self.current_line();
        self.print_file(current_line);
    }

    /// This function redraws the given line of the UI on the screen.
    pub fn redraw_line(&mut self, ui_line: usize) {
        let file_line = ui_line + self.current_line();
        self.print_line(ui_line, file_line);
    }

    pub fn print_line(&mut self, ui_line: usize, file_line: usize) {
        let contents = &self.editor.contents[file_line];
        let w = self.term.cols();
        let mut i = 0;
        let mut j = 0;

        for &b in contents {
            if b == b'\n' {
                continue;
            } else if i == w {
                i = 0;
                j += 1;
            }
            self.term[(i, ui_line + j)].set_ch(b as char);
            i += 1;
        }

        while i < self.term.cols() {
            self.term[(i, ui_line + j)].set_ch(' ');
            i += 1;
        }
    }
}
<|endoftext|>


<commit_before>use std::thread;
use std::sync::mpsc::{self, sync_channel, SendError};
use std::io::{Write, Read, ErrorKind};

use mio::*;
use mio::tcp::{TcpStream, Shutdown};

use ladspa::{PluginDescriptor, Plugin, PortConnection, Data};

use super::{BUFFER_SIZE, BYTE_BUFFER_SIZE, BASE_PORT};
use super::Packet;

const CLIENT: Token = Token(1);

pub struct Transmitter {
    sample_rate: u64,
    channel: u16,
    data_tx: Option<mpsc::SyncSender<Packet>>,
    notify_tx: Option<Sender<<PacketTransmitter as Handler>::Message>>,
    lbuffer: Vec<Data>,
    rbuffer: Vec<Data>,
}

impl Transmitter {
    pub fn new(desc: &PluginDescriptor, sample_rate: u64) -> Box<Plugin + Send> {
        Box::new(Transmitter {
            sample_rate: sample_rate,
            channel: 0,
            data_tx: None,
            notify_tx: None,
            lbuffer: Vec::new(),
            rbuffer: Vec::new(),
        })
    }

    fn init_client(&mut self) {
        let (data_tx, data_rx) = sync_channel(16);
        self.data_tx = Some(data_tx);

        let channel = self.channel;
        let mut event_loop = EventLoop::new().unwrap();
        self.notify_tx = Some(event_loop.channel());
        thread::spawn(move || {
            let addr = format!("127.0.0.1:{}", BASE_PORT + channel).parse().unwrap();
            let client = TcpStream::connect(&addr).unwrap();
            client.set_nodelay(true);
            event_loop.register(&client, CLIENT).unwrap();
            event_loop.run(&mut PacketTransmitter {
                socket: client,
                data_rx: data_rx,
            }).unwrap();
        });
    }

    fn kill_client(&mut self) {
        self.notify_tx.as_ref().unwrap().send(());
    }
}

impl Plugin for Transmitter {
    fn run<'a>(&mut self, sample_count: usize, ports: &[&'a PortConnection<'a>]) {
        let inputl = ports[0].unwrap_audio();
        let inputr = ports[1].unwrap_audio();
        let mut outputl = ports[2].unwrap_audio_mut();
        let mut outputr = ports[3].unwrap_audio_mut();

        let channel = *ports[4].unwrap_control() as u16;

        if channel != self.channel {
            self.channel = channel;
            println!("set channel {}", self.channel);
            self.kill_client();
            self.init_client();
        }

        let mut i = 0;
        while i < sample_count {
            while self.lbuffer.len() < BUFFER_SIZE && i < sample_count {
                self.lbuffer.push(inputl[i]);
                self.rbuffer.push(inputr[i]);

                outputl[i] = inputl[i];
                outputr[i] = inputr[i];

                i += 1;
            }

            if self.lbuffer.len() == BUFFER_SIZE {
                let mut packet = Packet::new(&self.lbuffer, &self.rbuffer);
                //TODO this should really push them to a queue, don't want to wait here forever.
                while let Err(SendError(p)) = self.data_tx.as_ref().unwrap().send(packet) {
                    self.kill_client();
                    self.init_client();
                    packet = p;
                }

                self.lbuffer.clear();
                self.rbuffer.clear();
            }
        }
    }

    fn activate(&mut self) {
        println!("activate {}", self.channel);
        self.init_client();
    }

    fn deactivate(&mut self) {
        println!("deactivate {}", self.channel);
        self.kill_client();
    }
}

struct PacketTransmitter {
    socket: TcpStream,
    data_rx: mpsc::Receiver<Packet>,
}

impl Handler for PacketTransmitter {
    type Timeout = ();
    type Message = ();

    fn ready(&mut self, event_loop: &mut EventLoop<Self>, token: Token, events: EventSet) {
        match token {
            CLIENT => {
                loop {
                    assert!(events.is_writable());
                    let packet = match self.data_rx.recv() {
                        Ok(p) => p,
                        Err(_) => {
                            println!("err recieving packet from ladspa, channel is dead!");
                            break;
                        }
                    };
                    match self.socket.write(&packet.as_bytes()[..]) {
                        Ok(num_written) => assert!(num_written == BYTE_BUFFER_SIZE),
                        Err(_) => {
                            println!("err writing packet to network!");
                            event_loop.shutdown();
                            break;
                        }
                    }
                }
            },
            _ => panic!("Received unknown token"),
        }
    }

    fn notify(&mut self, event_loop: &mut EventLoop<Self>, msg: Self::Message) {
        self.socket.shutdown(Shutdown::Both);
        event_loop.shutdown();
    }
}

<commit_msg>make note.<commit_after>use std::thread;
use std::sync::mpsc::{self, sync_channel, SendError};
use std::io::{Write, Read, ErrorKind};

use mio::*;
use mio::tcp::{TcpStream, Shutdown};

use ladspa::{PluginDescriptor, Plugin, PortConnection, Data};

use super::{BUFFER_SIZE, BYTE_BUFFER_SIZE, BASE_PORT};
use super::Packet;

const CLIENT: Token = Token(1);

pub struct Transmitter {
    sample_rate: u64,
    channel: u16,
    data_tx: Option<mpsc::SyncSender<Packet>>,
    notify_tx: Option<Sender<<PacketTransmitter as Handler>::Message>>,
    lbuffer: Vec<Data>,
    rbuffer: Vec<Data>,
}

impl Transmitter {
    pub fn new(desc: &PluginDescriptor, sample_rate: u64) -> Box<Plugin + Send> {
        Box::new(Transmitter {
            sample_rate: sample_rate,
            channel: 0,
            data_tx: None,
            notify_tx: None,
            lbuffer: Vec::new(),
            rbuffer: Vec::new(),
        })
    }

    fn init_client(&mut self) {
        let (data_tx, data_rx) = sync_channel(16);
        self.data_tx = Some(data_tx);

        let channel = self.channel;
        let mut event_loop = EventLoop::new().unwrap();
        self.notify_tx = Some(event_loop.channel());
        thread::spawn(move || {
            let addr = format!("127.0.0.1:{}", BASE_PORT + channel).parse().unwrap();
            let client = TcpStream::connect(&addr).unwrap();
            client.set_nodelay(true);
            event_loop.register(&client, CLIENT).unwrap();
            event_loop.run(&mut PacketTransmitter {
                socket: client,
                data_rx: data_rx,
            }).unwrap();
        });
    }

    fn kill_client(&mut self) {
        self.notify_tx.as_ref().unwrap().send(());
    }
}

impl Plugin for Transmitter {
    fn run<'a>(&mut self, sample_count: usize, ports: &[&'a PortConnection<'a>]) {
        let inputl = ports[0].unwrap_audio();
        let inputr = ports[1].unwrap_audio();
        let mut outputl = ports[2].unwrap_audio_mut();
        let mut outputr = ports[3].unwrap_audio_mut();

        let channel = *ports[4].unwrap_control() as u16;

        if channel != self.channel {
            self.channel = channel;
            println!("set channel {}", self.channel);
            self.kill_client();
            self.init_client();
        }

        let mut i = 0;
        while i < sample_count {
            while self.lbuffer.len() < BUFFER_SIZE && i < sample_count {
                self.lbuffer.push(inputl[i]);
                self.rbuffer.push(inputr[i]);

                outputl[i] = inputl[i];
                outputr[i] = inputr[i];

                i += 1;
            }

            if self.lbuffer.len() == BUFFER_SIZE {
                let mut packet = Packet::new(&self.lbuffer, &self.rbuffer);
                //TODO this should really push them to a queue, don't want to wait here forever.
                while let Err(SendError(p)) = self.data_tx.as_ref().unwrap().send(packet) {
                    self.kill_client();
                    self.init_client();
                    packet = p;
                }

                self.lbuffer.clear();
                self.rbuffer.clear();
            }
        }
    }

    fn activate(&mut self) {
        println!("activate {}", self.channel);
        self.init_client();
    }

    fn deactivate(&mut self) {
        println!("deactivate {}", self.channel);
        self.kill_client();
    }
}

struct PacketTransmitter {
    socket: TcpStream,
    data_rx: mpsc::Receiver<Packet>,
}

impl Handler for PacketTransmitter {
    type Timeout = ();
    type Message = ();

    fn ready(&mut self, event_loop: &mut EventLoop<Self>, token: Token, events: EventSet) {
        match token {
            CLIENT => {
                loop {
                    assert!(events.is_writable());
                    let packet = match self.data_rx.recv() {
                        Ok(p) => p,
                        Err(_) => {
                            println!("err recieving packet from ladspa, channel is dead!");
                            break;
                        }
                    };
                    match self.socket.write(&packet.as_bytes()[..]) {
                        Ok(num_written) =>
                            assert!(num_written == BYTE_BUFFER_SIZE), //TODO this fails sometimes.
                        Err(_) => {
                            println!("err writing packet to network!");
                            event_loop.shutdown();
                            break;
                        }
                    }
                }
            },
            _ => panic!("Received unknown token"),
        }
    }

    fn notify(&mut self, event_loop: &mut EventLoop<Self>, msg: Self::Message) {
        self.socket.shutdown(Shutdown::Both);
        event_loop.shutdown();
    }
}

<|endoftext|>


<commit_before>extern crate libc;
extern crate std;

use super::liblua;
use super::Lua;
use super::Pushable;
use super::Readable;

pub struct UserData<T> {
    value: T
}

impl<T:Clone> UserData<T> {
    pub fn new(val: T) -> UserData<T> {
        UserData{value: val}
    }
}

// TODO: handle destructors

impl<T:Clone> Pushable for UserData<T> {
    fn push_to_lua(&self, lua: &mut Lua) {
        let dataRaw = unsafe { liblua::lua_newuserdata(lua.lua, std::mem::size_of_val(&self.value) as libc::size_t) };
        let data: &mut T = unsafe { std::mem::transmute(dataRaw) };
        (*data) = self.value.clone();
    }
}

impl<T:Clone> Readable for UserData<T> {
    fn read_from_lua(lua: &mut Lua, index: i32) -> Option<UserData<T>> {
        // TODO: check type
        let dataPtr = unsafe { liblua::lua_touserdata(lua.lua, index) };
        let data: &T = unsafe { std::mem::transmute(dataPtr) };
        Some(UserData{value: data.clone()})
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn readwrite() {
        let mut lua = super::super::Lua::new();
        let d = super::UserData::new(2);

        lua.set("a", d);
        let x: super::UserData<int> = lua.get("a").unwrap();
        assert_eq!(x.value, 2)
    }
}
<commit_msg>Fix warning in userdata<commit_after>extern crate libc;
extern crate std;

use super::liblua;
use super::Lua;
use super::Pushable;
use super::Readable;

pub struct UserData<T> {
    value: T
}

impl<T:Clone> UserData<T> {
    pub fn new(val: T) -> UserData<T> {
        UserData{value: val}
    }
}

// TODO: handle destructors

impl<T:Clone> Pushable for UserData<T> {
    fn push_to_lua(&self, lua: &mut Lua) {
        let dataRaw = unsafe { liblua::lua_newuserdata(lua.lua, std::mem::size_of_val(&self.value) as libc::size_t) };
        let data: &mut T = unsafe { std::mem::transmute(dataRaw) };
        (*data) = self.value.clone();
    }
}

impl<T:Clone> Readable for UserData<T> {
    fn read_from_lua(lua: &mut Lua, index: i32) -> Option<UserData<T>> {
        // TODO: check type
        let dataPtr = unsafe { liblua::lua_touserdata(lua.lua, index) };
        let data: &T = unsafe { std::mem::transmute(dataPtr) };
        Some(UserData{value: data.clone()})
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn readwrite() {
        let mut lua = super::super::Lua::new();
        let d = super::UserData::new(2);

        lua.set("a", d).unwrap();
        let x: super::UserData<int> = lua.get("a").unwrap();
        assert_eq!(x.value, 2)
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017-2018 Ryan Huang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

mod board;
mod board_parts;
mod sys;
mod vec2;

use imgui::{ImGuiCond, ImStr, ImVec2, Ui};
use imgui_sys;

use self::board::board;
pub use self::sys::run;
use self::vec2::Vec2;
use model::{Color, ColorMap, Model, Player};
use update::Event;

pub fn draw(ui: &Ui, size: (f32, f32), model: &Model) -> Option<Event> {
    unsafe {
        imgui_sys::igPushStyleVar(imgui_sys::ImGuiStyleVar::WindowRounding, 0.0);
    }

    let mut event = None;

    ui.main_menu_bar(|| {
        ui.menu(im_str!("Game")).build(|| {
            ui.menu_item(im_str!("New game")).enabled(false).build();
            if ui.menu_item(im_str!("Human vs. Human")).build() {
                insert_if_empty(
                    &mut event,
                    Event::NewGame(ColorMap::new(Player::Human, Player::Human)),
                );
            }
            if ui.menu_item(im_str!("Human vs. Computer")).build() {
                insert_if_empty(
                    &mut event,
                    Event::NewGame(ColorMap::new(Player::Human, Player::Computer)),
                );
            }
            if ui.menu_item(im_str!("Computer vs. Human")).build() {
                insert_if_empty(
                    &mut event,
                    Event::NewGame(ColorMap::new(Player::Computer, Player::Human)),
                );
            }
            ui.separator();
            if ui.menu_item(im_str!("Quit")).build() {
                insert_if_empty(&mut event, Event::Quit);
            }
        });
    });

    ui.window(im_str!("Coerceo"))
        .size(size, ImGuiCond::Always)
        .position((0.0, 19.0), ImGuiCond::Once)
        .title_bar(false)
        .resizable(false)
        .movable(false)
        .build(|| {
            ui.text("Welcome to Coerceo!");
            ui.text(format!(
                "{:?} vs. {:?}",
                model.players.white, model.players.black
            ));

            if let Some(click) = board(model, Vec2::new(size.0 - 16.0, size.1 - 170.0)) {
                insert_if_empty(&mut event, click);
            }

            let display_vitals = || {
                ui.text(format!(
                    "{:?} has {} piece(s) left and {} captured hex(es).",
                    Color::White,
                    model.board.pieces(Color::White),
                    model.board.hexes(Color::White),
                ));
                ui.text(format!(
                    "{:?} has {} piece(s) left and {} captured hex(es).",
                    Color::Black,
                    model.board.pieces(Color::Black),
                    model.board.hexes(Color::Black),
                ));
            };

            let button_size = Vec2::new(120.0, 20.0);
            use model::Outcome::*;
            match model.outcome {
                Win(color) => {
                    ui.text(format!("{:?} wins!", color));
                    display_vitals();
                    if model.can_undo() && ui.button(im_str!("Undo"), button_size) {
                        insert_if_empty(&mut event, Event::Undo);
                    }
                }
                InProgress => {
                    ui.text(format!("It's {:?}'s turn.", model.board.turn));
                    display_vitals();

                    horz_button_layout(
                        ui,
                        vec![
                            (model.can_undo(), im_str!("Undo"), Event::Undo),
                            (model.can_redo(), im_str!("Redo"), Event::Redo),
                        ],
                        &button_size,
                        &mut event,
                    );
                    horz_button_layout(
                        ui,
                        vec![
                            (true, im_str!("Resign"), Event::Resign),
                            (
                                model.board.can_exchange()
                                    && model.current_player() == Player::Human,
                                if model.exchanging {
                                    im_str!("Stop Exchanging")
                                } else {
                                    im_str!("Exchange")
                                },
                                Event::Exchange,
                            ),
                        ],
                        &button_size,
                        &mut event,
                    );
                }
                // Draw cases
                _ => {
                    let message = match model.outcome {
                        DrawStalemate => "It's a draw by stalemate!",
                        DrawThreefoldRepetition => "It's a draw by threefold repetition!",
                        DrawInsufficientMaterial => "It's a draw by insufficient material!",
                        _ => unreachable!(),
                    };
                    ui.text(message);
                    display_vitals();
                    if model.can_undo() && ui.button(im_str!("Undo"), button_size) {
                        insert_if_empty(&mut event, Event::Undo);
                    }
                }
            }
        });

    unsafe {
        imgui_sys::igPopStyleVar(1);
    }

    event
}

fn horz_button_layout(
    ui: &Ui,
    buttons: Vec<(bool, &ImStr, Event)>,
    size: &Vec2,
    event: &mut Option<Event>,
) {
    if !buttons.iter().any(|&(show, _, _)| show) {
        return;
    }

    let size: ImVec2 = (*size).into();

    for (show, label, action) in buttons {
        if show {
            if ui.button(label, size) {
                insert_if_empty(event, action);
            }
        } else {
            unsafe {
                imgui_sys::igDummy(&size);
            }
        }
        ui.same_line(0.0);
    }
    ui.new_line();
}

fn insert_if_empty<T>(a: &mut Option<T>, b: T) {
    if a.is_none() {
        *a = Some(b);
    }
}
<commit_msg>Add "Computer vs. Computer" option<commit_after>/*
 * Copyright (C) 2017-2018 Ryan Huang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

mod board;
mod board_parts;
mod sys;
mod vec2;

use imgui::{ImGuiCond, ImStr, ImVec2, Ui};
use imgui_sys;

use self::board::board;
pub use self::sys::run;
use self::vec2::Vec2;
use model::{Color, ColorMap, Model, Player};
use update::Event;

pub fn draw(ui: &Ui, size: (f32, f32), model: &Model) -> Option<Event> {
    unsafe {
        imgui_sys::igPushStyleVar(imgui_sys::ImGuiStyleVar::WindowRounding, 0.0);
    }

    let mut event = None;

    ui.main_menu_bar(|| {
        ui.menu(im_str!("Game")).build(|| {
            ui.menu_item(im_str!("New game")).enabled(false).build();

            use self::Player::*;
            if ui.menu_item(im_str!("Human vs. Human")).build() {
                insert_if_empty(&mut event, Event::NewGame(ColorMap::new(Human, Human)));
            }
            if ui.menu_item(im_str!("Human vs. Computer")).build() {
                insert_if_empty(&mut event, Event::NewGame(ColorMap::new(Human, Computer)));
            }
            if ui.menu_item(im_str!("Computer vs. Human")).build() {
                insert_if_empty(&mut event, Event::NewGame(ColorMap::new(Computer, Human)));
            }
            if ui.menu_item(im_str!("Computer vs. Computer")).build() {
                insert_if_empty(
                    &mut event,
                    Event::NewGame(ColorMap::new(Computer, Computer)),
                );
            }
            ui.separator();
            if ui.menu_item(im_str!("Quit")).build() {
                insert_if_empty(&mut event, Event::Quit);
            }
        });
    });

    ui.window(im_str!("Coerceo"))
        .size(size, ImGuiCond::Always)
        .position((0.0, 19.0), ImGuiCond::Once)
        .title_bar(false)
        .resizable(false)
        .movable(false)
        .build(|| {
            ui.text("Welcome to Coerceo!");
            ui.text(format!(
                "{:?} vs. {:?}",
                model.players.white, model.players.black
            ));

            if let Some(click) = board(model, Vec2::new(size.0 - 16.0, size.1 - 170.0)) {
                insert_if_empty(&mut event, click);
            }

            let display_vitals = || {
                ui.text(format!(
                    "{:?} has {} piece(s) left and {} captured hex(es).",
                    Color::White,
                    model.board.pieces(Color::White),
                    model.board.hexes(Color::White),
                ));
                ui.text(format!(
                    "{:?} has {} piece(s) left and {} captured hex(es).",
                    Color::Black,
                    model.board.pieces(Color::Black),
                    model.board.hexes(Color::Black),
                ));
            };

            let button_size = Vec2::new(120.0, 20.0);
            use model::Outcome::*;
            match model.outcome {
                Win(color) => {
                    ui.text(format!("{:?} wins!", color));
                    display_vitals();
                    if model.can_undo() && ui.button(im_str!("Undo"), button_size) {
                        insert_if_empty(&mut event, Event::Undo);
                    }
                }
                InProgress => {
                    ui.text(format!("It's {:?}'s turn.", model.board.turn));
                    display_vitals();

                    horz_button_layout(
                        ui,
                        vec![
                            (model.can_undo(), im_str!("Undo"), Event::Undo),
                            (model.can_redo(), im_str!("Redo"), Event::Redo),
                        ],
                        &button_size,
                        &mut event,
                    );
                    horz_button_layout(
                        ui,
                        vec![
                            (true, im_str!("Resign"), Event::Resign),
                            (
                                model.board.can_exchange()
                                    && model.current_player() == Player::Human,
                                if model.exchanging {
                                    im_str!("Stop Exchanging")
                                } else {
                                    im_str!("Exchange")
                                },
                                Event::Exchange,
                            ),
                        ],
                        &button_size,
                        &mut event,
                    );
                }
                // Draw cases
                _ => {
                    let message = match model.outcome {
                        DrawStalemate => "It's a draw by stalemate!",
                        DrawThreefoldRepetition => "It's a draw by threefold repetition!",
                        DrawInsufficientMaterial => "It's a draw by insufficient material!",
                        _ => unreachable!(),
                    };
                    ui.text(message);
                    display_vitals();
                    if model.can_undo() && ui.button(im_str!("Undo"), button_size) {
                        insert_if_empty(&mut event, Event::Undo);
                    }
                }
            }
        });

    unsafe {
        imgui_sys::igPopStyleVar(1);
    }

    event
}

fn horz_button_layout(
    ui: &Ui,
    buttons: Vec<(bool, &ImStr, Event)>,
    size: &Vec2,
    event: &mut Option<Event>,
) {
    if !buttons.iter().any(|&(show, _, _)| show) {
        return;
    }

    let size: ImVec2 = (*size).into();

    for (show, label, action) in buttons {
        if show {
            if ui.button(label, size) {
                insert_if_empty(event, action);
            }
        } else {
            unsafe {
                imgui_sys::igDummy(&size);
            }
        }
        ui.same_line(0.0);
    }
    ui.new_line();
}

fn insert_if_empty<T>(a: &mut Option<T>, b: T) {
    if a.is_none() {
        *a = Some(b);
    }
}
<|endoftext|>


<commit_before>#![allow(non_uppercase_statics)]
#![allow(non_camel_case_types)]

use libc::*;
use xlib::Display;
use xlib::Window;
use xlib::Drawable;
use xlib::XID;

#[repr(C)]
pub struct XineramaScreenInfo {
   pub screen_number: c_int,
   pub x_org : c_short,
   pub y_org : c_short,
   pub width : c_short,
   pub height : c_short
}

#[repr(C)]
pub struct XPanoramiXInfo {
    pub window: Window,
    pub screen: c_int,
    pub State: c_int,
    pub width: c_int,
    pub height: c_int,
    pub ScreenCount: c_int,
    pub eventMask: XID
}

#[link(name="Xinerama")]
extern {
    pub fn XPanoramiXGetState(dpy: *mut Display, drawable: Drawable, panoramix_info: *mut XPanoramiXInfo) -> c_int;
    pub fn XPanoramiXGetScreenCount(dpy: *mut Display, drawable: Drawable, panoramix_info: *mut XPanoramiXInfo) -> c_int;
    pub fn XPanoramiXGetScreenSize(dpy: *mut Display, drawable: Drawable, screen_num: c_int, panoramix_info: *mut XPanoramiXInfo) -> c_int;
    pub fn XineramaQueryExtension(dpy: *mut Display, event: *mut c_int, error: *mut c_int) -> c_int;
    pub fn XineramaQueryVersion(dpy: *mut Display, major: *mut c_int, minor: *mut c_int) -> c_int;
	pub fn XineramaIsActive(dpy: *mut Display) -> c_int;
	pub fn XineramaQueryScreens(dpy: *mut Display, number: *mut c_int) -> *const XineramaScreenInfo;
}
<commit_msg>added clone and copy to structs<commit_after>#![allow(non_uppercase_statics)]
#![allow(non_camel_case_types)]

use libc::*;
use xlib::Display;
use xlib::Window;
use xlib::Drawable;
use xlib::XID;

#[repr(C)]
#[derive(Copy, Clone)]
pub struct XineramaScreenInfo {
   pub screen_number: c_int,
   pub x_org : c_short,
   pub y_org : c_short,
   pub width : c_short,
   pub height : c_short
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct XPanoramiXInfo {
    pub window: Window,
    pub screen: c_int,
    pub State: c_int,
    pub width: c_int,
    pub height: c_int,
    pub ScreenCount: c_int,
    pub eventMask: XID
}

#[link(name="Xinerama")]
extern {
    pub fn XPanoramiXGetState(dpy: *mut Display, drawable: Drawable, panoramix_info: *mut XPanoramiXInfo) -> c_int;
    pub fn XPanoramiXGetScreenCount(dpy: *mut Display, drawable: Drawable, panoramix_info: *mut XPanoramiXInfo) -> c_int;
    pub fn XPanoramiXGetScreenSize(dpy: *mut Display, drawable: Drawable, screen_num: c_int, panoramix_info: *mut XPanoramiXInfo) -> c_int;
    pub fn XineramaQueryExtension(dpy: *mut Display, event: *mut c_int, error: *mut c_int) -> c_int;
    pub fn XineramaQueryVersion(dpy: *mut Display, major: *mut c_int, minor: *mut c_int) -> c_int;
	pub fn XineramaIsActive(dpy: *mut Display) -> c_int;
	pub fn XineramaQueryScreens(dpy: *mut Display, number: *mut c_int) -> *const XineramaScreenInfo;
}
<|endoftext|>


<commit_before>use super::{Custom, Error, ErrorKind, Repr};
use crate::error;
use crate::fmt;
use crate::mem::size_of;
use crate::sys::decode_error_kind;
use crate::sys::os::error_string;

#[test]
fn test_size() {
    assert!(size_of::<Error>() <= size_of::<[usize; 2]>());
}

#[test]
fn test_debug_error() {
    let code = 6;
    let msg = error_string(code);
    let kind = decode_error_kind(code);
    let err = Error {
        repr: Repr::Custom(box Custom {
            kind: ErrorKind::InvalidInput,
            error: box Error { repr: super::Repr::Os(code) },
        }),
    };
    let expected = format!(
        "Custom {{ \
         kind: InvalidInput, \
         error: Os {{ \
         code: {:?}, \
         kind: {:?}, \
         message: {:?} \
         }} \
         }}",
        code, kind, msg
    );
    assert_eq!(format!("{:?}", err), expected);
}

#[test]
fn test_downcasting() {
    #[derive(Debug)]
    struct TestError;

    impl fmt::Display for TestError {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            f.write_str("asdf")
        }
    }

    impl error::Error for TestError {}

    // we have to call all of these UFCS style right now since method
    // resolution won't implicitly drop the Send+Sync bounds
    let mut err = Error::new(ErrorKind::Other, TestError);
    assert!(err.get_ref().unwrap().is::<TestError>());
    assert_eq!("asdf", err.get_ref().unwrap().to_string());
    assert!(err.get_mut().unwrap().is::<TestError>());
    let extracted = err.into_inner().unwrap();
    extracted.downcast::<TestError>().unwrap();
}
<commit_msg>Add test for io::Error::new_const.<commit_after>use super::{Custom, Error, ErrorKind, Repr};
use crate::error;
use crate::fmt;
use crate::mem::size_of;
use crate::sys::decode_error_kind;
use crate::sys::os::error_string;

#[test]
fn test_size() {
    assert!(size_of::<Error>() <= size_of::<[usize; 2]>());
}

#[test]
fn test_debug_error() {
    let code = 6;
    let msg = error_string(code);
    let kind = decode_error_kind(code);
    let err = Error {
        repr: Repr::Custom(box Custom {
            kind: ErrorKind::InvalidInput,
            error: box Error { repr: super::Repr::Os(code) },
        }),
    };
    let expected = format!(
        "Custom {{ \
         kind: InvalidInput, \
         error: Os {{ \
         code: {:?}, \
         kind: {:?}, \
         message: {:?} \
         }} \
         }}",
        code, kind, msg
    );
    assert_eq!(format!("{:?}", err), expected);
}

#[test]
fn test_downcasting() {
    #[derive(Debug)]
    struct TestError;

    impl fmt::Display for TestError {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            f.write_str("asdf")
        }
    }

    impl error::Error for TestError {}

    // we have to call all of these UFCS style right now since method
    // resolution won't implicitly drop the Send+Sync bounds
    let mut err = Error::new(ErrorKind::Other, TestError);
    assert!(err.get_ref().unwrap().is::<TestError>());
    assert_eq!("asdf", err.get_ref().unwrap().to_string());
    assert!(err.get_mut().unwrap().is::<TestError>());
    let extracted = err.into_inner().unwrap();
    extracted.downcast::<TestError>().unwrap();
}

#[test]
fn test_const() {
    const E: Error = Error::new_const(ErrorKind::NotFound, &"hello");

    assert_eq!(E.kind(), ErrorKind::NotFound);
    assert_eq!(E.to_string(), "hello");
    assert!(format!("{:?}", E).contains("\"hello\""));
    assert!(format!("{:?}", E).contains("NotFound"));
}
<|endoftext|>