<commit_before>use super::*;
use crate::punctuated::Punctuated;

ast_struct! {
    /// Data structure sent to a `proc_macro_derive` macro.
    ///
    /// *This type is available if Syn is built with the `"derive"` feature.*
    pub struct DeriveInput {
        /// Attributes tagged on the whole struct or enum.
        pub attrs: Vec<Attribute>,

        /// Visibility of the struct or enum.
        pub vis: Visibility,

        /// Name of the struct or enum.
        pub ident: Ident,

        /// Generics required to complete the definition.
        pub generics: Generics,

        /// Data within the struct or enum.
        pub data: Data,
    }
}

ast_enum_of_structs! {
    /// The storage of a struct, enum or union data structure.
    ///
    /// *This type is available if Syn is built with the `"derive"` feature.*
    ///
    /// # Syntax tree enum
    ///
    /// This type is a [syntax tree enum].
    ///
    /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
    //
    // TODO: change syntax-tree-enum link to an intra rustdoc link, currently
    // blocked on https://github.com/rust-lang/rust/issues/62833
    pub enum Data {
        /// A struct input to a `proc_macro_derive` macro.
        Struct(DataStruct),

        /// An enum input to a `proc_macro_derive` macro.
        Enum(DataEnum),

        /// A tagged union input to a `proc_macro_derive` macro.
        Union(DataUnion),
    }

    do_not_generate_to_tokens
}

ast_struct! {
    /// A struct input to a `proc_macro_derive` macro.
    ///
    /// *This type is available if Syn is built with the `"derive"`
    /// feature.*
    pub struct DataStruct {
        pub struct_token: Token![struct],
        pub fields: Fields,
        pub semi_token: Option<Token![;]>,
    }
}

ast_struct! {
    /// An enum input to a `proc_macro_derive` macro.
    ///
    /// *This type is available if Syn is built with the `"derive"`
    /// feature.*
    pub struct DataEnum {
        pub enum_token: Token![enum],
        pub brace_token: token::Brace,
        pub variants: Punctuated<Variant, Token![,]>,
    }
}

ast_struct! {
    /// A tagged union input to a `proc_macro_derive` macro.
    ///
    /// *This type is available if Syn is built with the `"derive"`
    /// feature.*
    pub struct DataUnion {
        pub union_token: Token![union],
        pub fields: FieldsNamed,
    }
}

#[cfg(feature = "parsing")]
pub mod parsing {
    use super::*;

    use crate::parse::{Parse, ParseStream, Result};

    impl Parse for DeriveInput {
        fn parse(input: ParseStream) -> Result<Self> {
            let attrs = input.call(Attribute::parse_outer)?;
            let vis = input.parse::<Visibility>()?;

            let lookahead = input.lookahead1();
            if lookahead.peek(Token![struct]) {
                let struct_token = input.parse::<Token![struct]>()?;
                let ident = input.parse::<Ident>()?;
                let generics = input.parse::<Generics>()?;
                let (where_clause, fields, semi) = data_struct(input)?;
                Ok(DeriveInput {
                    attrs,
                    vis,
                    ident,
                    generics: Generics {
                        where_clause,
                        ..generics
                    },
                    data: Data::Struct(DataStruct {
                        struct_token,
                        fields,
                        semi_token: semi,
                    }),
                })
            } else if lookahead.peek(Token![enum]) {
                let enum_token = input.parse::<Token![enum]>()?;
                let ident = input.parse::<Ident>()?;
                let generics = input.parse::<Generics>()?;
                let (where_clause, brace, variants) = data_enum(input)?;
                Ok(DeriveInput {
                    attrs,
                    vis,
                    ident,
                    generics: Generics {
                        where_clause,
                        ..generics
                    },
                    data: Data::Enum(DataEnum {
                        enum_token,
                        brace_token: brace,
                        variants,
                    }),
                })
            } else if lookahead.peek(Token![union]) {
                let union_token = input.parse::<Token![union]>()?;
                let ident = input.parse::<Ident>()?;
                let generics = input.parse::<Generics>()?;
                let (where_clause, fields) = data_union(input)?;
                Ok(DeriveInput {
                    attrs,
                    vis,
                    ident,
                    generics: Generics {
                        where_clause,
                        ..generics
                    },
                    data: Data::Union(DataUnion {
                        union_token,
                        fields,
                    }),
                })
            } else {
                Err(lookahead.error())
            }
        }
    }

    pub fn data_struct(
        input: ParseStream,
    ) -> Result<(Option<WhereClause>, Fields, Option<Token![;]>)> {
        let mut lookahead = input.lookahead1();
        let mut where_clause = None;
        if lookahead.peek(Token![where]) {
            where_clause = Some(input.parse()?);
            lookahead = input.lookahead1();
        }

        if where_clause.is_none() && lookahead.peek(token::Paren) {
            let fields = input.parse()?;

            lookahead = input.lookahead1();
            if lookahead.peek(Token![where]) {
                where_clause = Some(input.parse()?);
                lookahead = input.lookahead1();
            }

            if lookahead.peek(Token![;]) {
                let semi = input.parse()?;
                Ok((where_clause, Fields::Unnamed(fields), Some(semi)))
            } else {
                Err(lookahead.error())
            }
        } else if lookahead.peek(token::Brace) {
            let fields = input.parse()?;
            Ok((where_clause, Fields::Named(fields), None))
        } else if lookahead.peek(Token![;]) {
            let semi = input.parse()?;
            Ok((where_clause, Fields::Unit, Some(semi)))
        } else {
            Err(lookahead.error())
        }
    }

    pub fn data_enum(
        input: ParseStream,
    ) -> Result<(
        Option<WhereClause>,
        token::Brace,
        Punctuated<Variant, Token![,]>,
    )> {
        let where_clause = input.parse()?;

        let content;
        let brace = braced!(content in input);
        let variants = content.parse_terminated(Variant::parse)?;

        Ok((where_clause, brace, variants))
    }

    pub fn data_union(input: ParseStream) -> Result<(Option<WhereClause>, FieldsNamed)> {
        let where_clause = input.parse()?;
        let fields = input.parse()?;
        Ok((where_clause, fields))
    }
}

#[cfg(feature = "printing")]
mod printing {
    use super::*;

    use proc_macro2::TokenStream;
    use quote::ToTokens;

    use crate::attr::FilterAttrs;
    use crate::print::TokensOrDefault;

    impl ToTokens for DeriveInput {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            for attr in self.attrs.outer() {
                attr.to_tokens(tokens);
            }
            self.vis.to_tokens(tokens);
            match &self.data {
                Data::Struct(d) => d.struct_token.to_tokens(tokens),
                Data::Enum(d) => d.enum_token.to_tokens(tokens),
                Data::Union(d) => d.union_token.to_tokens(tokens),
            }
            self.ident.to_tokens(tokens);
            self.generics.to_tokens(tokens);
            match &self.data {
                Data::Struct(data) => match &data.fields {
                    Fields::Named(fields) => {
                        self.generics.where_clause.to_tokens(tokens);
                        fields.to_tokens(tokens);
                    }
                    Fields::Unnamed(fields) => {
                        fields.to_tokens(tokens);
                        self.generics.where_clause.to_tokens(tokens);
                        TokensOrDefault(&data.semi_token).to_tokens(tokens);
                    }
                    Fields::Unit => {
                        self.generics.where_clause.to_tokens(tokens);
                        TokensOrDefault(&data.semi_token).to_tokens(tokens);
                    }
                },
                Data::Enum(data) => {
                    self.generics.where_clause.to_tokens(tokens);
                    data.brace_token.surround(tokens, |tokens| {
                        data.variants.to_tokens(tokens);
                    });
                }
                Data::Union(data) => {
                    self.generics.where_clause.to_tokens(tokens);
                    data.fields.to_tokens(tokens);
                }
            }
        }
    }
}
<commit_msg>Fix untagged union typo<commit_after>use super::*;
use crate::punctuated::Punctuated;

ast_struct! {
    /// Data structure sent to a `proc_macro_derive` macro.
    ///
    /// *This type is available if Syn is built with the `"derive"` feature.*
    pub struct DeriveInput {
        /// Attributes tagged on the whole struct or enum.
        pub attrs: Vec<Attribute>,

        /// Visibility of the struct or enum.
        pub vis: Visibility,

        /// Name of the struct or enum.
        pub ident: Ident,

        /// Generics required to complete the definition.
        pub generics: Generics,

        /// Data within the struct or enum.
        pub data: Data,
    }
}

ast_enum_of_structs! {
    /// The storage of a struct, enum or union data structure.
    ///
    /// *This type is available if Syn is built with the `"derive"` feature.*
    ///
    /// # Syntax tree enum
    ///
    /// This type is a [syntax tree enum].
    ///
    /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
    //
    // TODO: change syntax-tree-enum link to an intra rustdoc link, currently
    // blocked on https://github.com/rust-lang/rust/issues/62833
    pub enum Data {
        /// A struct input to a `proc_macro_derive` macro.
        Struct(DataStruct),

        /// An enum input to a `proc_macro_derive` macro.
        Enum(DataEnum),

        /// An untagged union input to a `proc_macro_derive` macro.
        Union(DataUnion),
    }

    do_not_generate_to_tokens
}

ast_struct! {
    /// A struct input to a `proc_macro_derive` macro.
    ///
    /// *This type is available if Syn is built with the `"derive"`
    /// feature.*
    pub struct DataStruct {
        pub struct_token: Token![struct],
        pub fields: Fields,
        pub semi_token: Option<Token![;]>,
    }
}

ast_struct! {
    /// An enum input to a `proc_macro_derive` macro.
    ///
    /// *This type is available if Syn is built with the `"derive"`
    /// feature.*
    pub struct DataEnum {
        pub enum_token: Token![enum],
        pub brace_token: token::Brace,
        pub variants: Punctuated<Variant, Token![,]>,
    }
}

ast_struct! {
    /// An untagged union input to a `proc_macro_derive` macro.
    ///
    /// *This type is available if Syn is built with the `"derive"`
    /// feature.*
    pub struct DataUnion {
        pub union_token: Token![union],
        pub fields: FieldsNamed,
    }
}

#[cfg(feature = "parsing")]
pub mod parsing {
    use super::*;

    use crate::parse::{Parse, ParseStream, Result};

    impl Parse for DeriveInput {
        fn parse(input: ParseStream) -> Result<Self> {
            let attrs = input.call(Attribute::parse_outer)?;
            let vis = input.parse::<Visibility>()?;

            let lookahead = input.lookahead1();
            if lookahead.peek(Token![struct]) {
                let struct_token = input.parse::<Token![struct]>()?;
                let ident = input.parse::<Ident>()?;
                let generics = input.parse::<Generics>()?;
                let (where_clause, fields, semi) = data_struct(input)?;
                Ok(DeriveInput {
                    attrs,
                    vis,
                    ident,
                    generics: Generics {
                        where_clause,
                        ..generics
                    },
                    data: Data::Struct(DataStruct {
                        struct_token,
                        fields,
                        semi_token: semi,
                    }),
                })
            } else if lookahead.peek(Token![enum]) {
                let enum_token = input.parse::<Token![enum]>()?;
                let ident = input.parse::<Ident>()?;
                let generics = input.parse::<Generics>()?;
                let (where_clause, brace, variants) = data_enum(input)?;
                Ok(DeriveInput {
                    attrs,
                    vis,
                    ident,
                    generics: Generics {
                        where_clause,
                        ..generics
                    },
                    data: Data::Enum(DataEnum {
                        enum_token,
                        brace_token: brace,
                        variants,
                    }),
                })
            } else if lookahead.peek(Token![union]) {
                let union_token = input.parse::<Token![union]>()?;
                let ident = input.parse::<Ident>()?;
                let generics = input.parse::<Generics>()?;
                let (where_clause, fields) = data_union(input)?;
                Ok(DeriveInput {
                    attrs,
                    vis,
                    ident,
                    generics: Generics {
                        where_clause,
                        ..generics
                    },
                    data: Data::Union(DataUnion {
                        union_token,
                        fields,
                    }),
                })
            } else {
                Err(lookahead.error())
            }
        }
    }

    pub fn data_struct(
        input: ParseStream,
    ) -> Result<(Option<WhereClause>, Fields, Option<Token![;]>)> {
        let mut lookahead = input.lookahead1();
        let mut where_clause = None;
        if lookahead.peek(Token![where]) {
            where_clause = Some(input.parse()?);
            lookahead = input.lookahead1();
        }

        if where_clause.is_none() && lookahead.peek(token::Paren) {
            let fields = input.parse()?;

            lookahead = input.lookahead1();
            if lookahead.peek(Token![where]) {
                where_clause = Some(input.parse()?);
                lookahead = input.lookahead1();
            }

            if lookahead.peek(Token![;]) {
                let semi = input.parse()?;
                Ok((where_clause, Fields::Unnamed(fields), Some(semi)))
            } else {
                Err(lookahead.error())
            }
        } else if lookahead.peek(token::Brace) {
            let fields = input.parse()?;
            Ok((where_clause, Fields::Named(fields), None))
        } else if lookahead.peek(Token![;]) {
            let semi = input.parse()?;
            Ok((where_clause, Fields::Unit, Some(semi)))
        } else {
            Err(lookahead.error())
        }
    }

    pub fn data_enum(
        input: ParseStream,
    ) -> Result<(
        Option<WhereClause>,
        token::Brace,
        Punctuated<Variant, Token![,]>,
    )> {
        let where_clause = input.parse()?;

        let content;
        let brace = braced!(content in input);
        let variants = content.parse_terminated(Variant::parse)?;

        Ok((where_clause, brace, variants))
    }

    pub fn data_union(input: ParseStream) -> Result<(Option<WhereClause>, FieldsNamed)> {
        let where_clause = input.parse()?;
        let fields = input.parse()?;
        Ok((where_clause, fields))
    }
}

#[cfg(feature = "printing")]
mod printing {
    use super::*;

    use proc_macro2::TokenStream;
    use quote::ToTokens;

    use crate::attr::FilterAttrs;
    use crate::print::TokensOrDefault;

    impl ToTokens for DeriveInput {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            for attr in self.attrs.outer() {
                attr.to_tokens(tokens);
            }
            self.vis.to_tokens(tokens);
            match &self.data {
                Data::Struct(d) => d.struct_token.to_tokens(tokens),
                Data::Enum(d) => d.enum_token.to_tokens(tokens),
                Data::Union(d) => d.union_token.to_tokens(tokens),
            }
            self.ident.to_tokens(tokens);
            self.generics.to_tokens(tokens);
            match &self.data {
                Data::Struct(data) => match &data.fields {
                    Fields::Named(fields) => {
                        self.generics.where_clause.to_tokens(tokens);
                        fields.to_tokens(tokens);
                    }
                    Fields::Unnamed(fields) => {
                        fields.to_tokens(tokens);
                        self.generics.where_clause.to_tokens(tokens);
                        TokensOrDefault(&data.semi_token).to_tokens(tokens);
                    }
                    Fields::Unit => {
                        self.generics.where_clause.to_tokens(tokens);
                        TokensOrDefault(&data.semi_token).to_tokens(tokens);
                    }
                },
                Data::Enum(data) => {
                    self.generics.where_clause.to_tokens(tokens);
                    data.brace_token.surround(tokens, |tokens| {
                        data.variants.to_tokens(tokens);
                    });
                }
                Data::Union(data) => {
                    self.generics.where_clause.to_tokens(tokens);
                    data.fields.to_tokens(tokens);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Test against the `sx` program, and itself
extern crate tempfile;
extern crate rand;
extern crate xmodem;

use std::process::{Command, Stdio, ChildStdin, ChildStdout};
use std::io::{self, Read, Write, Seek, ErrorKind};
use tempfile::NamedTempFile;
use rand::{Rng, thread_rng};
use xmodem::{Xmodem,Checksum};
use std::sync::mpsc::{channel,Sender,Receiver};

struct ChildStdInOut {
    stdin: ChildStdin,
    stdout: ChildStdout,
}

impl Read for ChildStdInOut {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.stdout.read(buf)
    }
}

impl Write for ChildStdInOut {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.stdin.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.stdin.flush()
    }
}

struct BidirectionalPipe {
    pin : Receiver<u8>,
    pout : Sender<u8>,
}

impl Read for BidirectionalPipe {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        for idx in 0..buf.len() {
            buf[idx] = match self.pin.recv() {
                Ok(v) => v,
                Err(e) => return Err(std::io::Error::new(ErrorKind::BrokenPipe,e)),
            }
        }
        Ok(buf.len())
    }
}

impl Write for BidirectionalPipe {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        for v in buf { self.pout.send(*v).unwrap(); }
        Ok(buf.len())
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

fn loopback() -> (BidirectionalPipe, BidirectionalPipe) {
    let (s1,r1) = channel();
    let (s2,r2) = channel();
    (BidirectionalPipe{ pin : r1, pout : s2 }, BidirectionalPipe{ pin : r2, pout : s1 })
}

#[cfg(test)]
fn xmodem_recv(checksum_mode:Checksum) {
    let data_len = 2000;
    let mut data = vec![0; data_len];
    thread_rng().fill_bytes(&mut data);

    let mut send_file = NamedTempFile::new().unwrap();
    send_file.write_all(&data).unwrap();

    let send = Command::new("sb")
        .arg("--xmodem")
        .arg(send_file.path())
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .stderr(Stdio::null())
        .spawn().unwrap();

    let tx_stream = send.stdin.unwrap();
    let rx_stream = send.stdout.unwrap();
    let mut serial_dev = ChildStdInOut { stdin: tx_stream, stdout: rx_stream };

    let mut xmodem = Xmodem::new();
    let mut recv_data = Vec::new();
    xmodem.recv(&mut serial_dev,&mut recv_data, checksum_mode).unwrap();

    let mut sent_data = Vec::new();
    send_file.seek(std::io::SeekFrom::Start(0)).unwrap();
    send_file.read_to_end(&mut sent_data).unwrap();
    let mut padded_data = sent_data.clone();
    for _ in 0..(128 - sent_data.len() % 128) {
         padded_data.push(0x1a);
    }
    assert_eq!(padded_data, recv_data);
}

#[cfg(test)]
fn xmodem_loopback(checksum_mode:Checksum) {
    let data_len=51200;
    let mut data_out = vec![0; data_len];
    thread_rng().fill_bytes(&mut data_out);
    let mut data_in = vec![0; data_len];
    let (mut p1, mut p2) = loopback();
    let handle = std::thread::spawn(move || {
        let mut xmodem = Xmodem::new();
        xmodem.send(&mut p1, &mut &data_out[..]).unwrap();
    });
    let handle2 = std::thread::spawn(move || {
        let mut xmodem = Xmodem::new();
        xmodem.recv(&mut p2, &mut data_in, checksum_mode).unwrap();
    });

    match handle.join() {
        Ok(()) => (),
        Err(e) => println!("{:?}",e),
    }
    handle2.join().unwrap();
}

#[test]
fn xmodem_loopback_standard() {
    xmodem_loopback(Checksum::Standard);
}

#[test]
fn xmodem_recv_standard() {
    xmodem_recv(Checksum::Standard);
}

#[test]
fn xmodem_recv_crc() {
    xmodem_recv(Checksum::CRC16);
}

#[test]
fn xmodem_send_standard() {
    let data_len = 2000;
    let mut data = vec![0; data_len];
    thread_rng().fill_bytes(&mut data);

    let mut recv_file = NamedTempFile::new().unwrap();
    let recv = Command::new("rb")
                       .arg("--xmodem")
                       .arg(recv_file.path())
                       .stdin(Stdio::piped())
                       .stdout(Stdio::piped())
                       .stderr(Stdio::null())
                       .spawn().unwrap();

    let tx_stream = recv.stdin.unwrap();
    let rx_stream = recv.stdout.unwrap();
    let mut serial_dev = ChildStdInOut { stdin: tx_stream, stdout: rx_stream };

    let mut xmodem = Xmodem::new();
    xmodem.send(&mut serial_dev, &mut &data[..]).unwrap();

    let mut received_data = Vec::new();
    recv_file.read_to_end(&mut received_data).unwrap();
    let mut padded_data = data.clone();
    for _ in 0..(128 - data.len() % 128) {
        padded_data.push(0x1a);
    }
    assert_eq!(received_data, padded_data);
}

#[test]
fn xmodem_send_crc() {
    let data_len = 2000;
    let mut data = vec![0; data_len];
    thread_rng().fill_bytes(&mut data);

    let mut recv_file = NamedTempFile::new().unwrap();
    let recv = Command::new("rb")
                       .arg("--xmodem")
                       .arg("--with-crc")
                       .arg(recv_file.path())
                       .stdin(Stdio::piped())
                       .stdout(Stdio::piped())
                       .stderr(Stdio::null())
                       .spawn().unwrap();

    let tx_stream = recv.stdin.unwrap();
    let rx_stream = recv.stdout.unwrap();
    let mut serial_dev = ChildStdInOut { stdin: tx_stream, stdout: rx_stream };

    let mut xmodem = Xmodem::new();
    xmodem.send(&mut serial_dev, &mut &data[..]).unwrap();

    let mut received_data = Vec::new();
    recv_file.read_to_end(&mut received_data).unwrap();
    let mut padded_data = data.clone();
    for _ in 0..(128 - data.len() % 128) {
        padded_data.push(0x1a);
    }
    assert_eq!(received_data, padded_data);
}
<commit_msg>check for excessive errors in recv<commit_after>//! Test against the `sx` program, and itself
extern crate tempfile;
extern crate rand;
extern crate xmodem;

use std::process::{Command, Stdio, ChildStdin, ChildStdout};
use std::io::{self, Read, Write, Seek, ErrorKind};
use tempfile::NamedTempFile;
use rand::{Rng, thread_rng};
use xmodem::{Xmodem,Checksum};
use std::sync::mpsc::{channel,Sender,Receiver};

struct ChildStdInOut {
    stdin: ChildStdin,
    stdout: ChildStdout,
}

impl Read for ChildStdInOut {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.stdout.read(buf)
    }
}

impl Write for ChildStdInOut {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.stdin.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.stdin.flush()
    }
}

struct BidirectionalPipe {
    pin : Receiver<u8>,
    pout : Sender<u8>,
}

impl Read for BidirectionalPipe {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        for idx in 0..buf.len() {
            buf[idx] = match self.pin.recv() {
                Ok(v) => v,
                Err(e) => return Err(std::io::Error::new(ErrorKind::BrokenPipe,e)),
            }
        }
        Ok(buf.len())
    }
}

impl Write for BidirectionalPipe {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        for v in buf { self.pout.send(*v).unwrap(); }
        Ok(buf.len())
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

fn loopback() -> (BidirectionalPipe, BidirectionalPipe) {
    let (s1,r1) = channel();
    let (s2,r2) = channel();
    (BidirectionalPipe{ pin : r1, pout : s2 }, BidirectionalPipe{ pin : r2, pout : s1 })
}

#[cfg(test)]
fn xmodem_recv(checksum_mode:Checksum) {
    let data_len = 2000;
    let mut data = vec![0; data_len];
    thread_rng().fill_bytes(&mut data);

    let mut send_file = NamedTempFile::new().unwrap();
    send_file.write_all(&data).unwrap();

    let send = Command::new("sb")
        .arg("--xmodem")
        .arg(send_file.path())
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .stderr(Stdio::null())
        .spawn().unwrap();

    let tx_stream = send.stdin.unwrap();
    let rx_stream = send.stdout.unwrap();
    let mut serial_dev = ChildStdInOut { stdin: tx_stream, stdout: rx_stream };

    let mut xmodem = Xmodem::new();
    let mut recv_data = Vec::new();
    xmodem.recv(&mut serial_dev,&mut recv_data, checksum_mode).unwrap();

    let mut sent_data = Vec::new();
    send_file.seek(std::io::SeekFrom::Start(0)).unwrap();
    send_file.read_to_end(&mut sent_data).unwrap();
    let mut padded_data = sent_data.clone();
    for _ in 0..(128 - sent_data.len() % 128) {
         padded_data.push(0x1a);
    }
    assert_eq!(padded_data, recv_data);
}

#[cfg(test)]
fn xmodem_loopback(checksum_mode:Checksum) {
    let data_len=51200;
    let mut data_out = vec![0; data_len];
    thread_rng().fill_bytes(&mut data_out);
    let mut data_in = vec![0; data_len];
    let (mut p1, mut p2) = loopback();
    let handle = std::thread::spawn(move || {
        let mut xmodem = Xmodem::new();
        xmodem.send(&mut p1, &mut &data_out[..]).unwrap();
    });
    let handle2 = std::thread::spawn(move || {
        let mut xmodem = Xmodem::new();
        xmodem.recv(&mut p2, &mut data_in, checksum_mode).unwrap();
    });

    handle.join().unwrap();
    handle2.join().unwrap();
}

#[test]
fn xmodem_loopback_standard() {
    xmodem_loopback(Checksum::Standard);
}

#[test]
fn xmodem_recv_standard() {
    xmodem_recv(Checksum::Standard);
}

#[test]
fn xmodem_recv_crc() {
    xmodem_recv(Checksum::CRC16);
}

#[test]
fn xmodem_send_standard() {
    let data_len = 2000;
    let mut data = vec![0; data_len];
    thread_rng().fill_bytes(&mut data);

    let mut recv_file = NamedTempFile::new().unwrap();
    let recv = Command::new("rb")
                       .arg("--xmodem")
                       .arg(recv_file.path())
                       .stdin(Stdio::piped())
                       .stdout(Stdio::piped())
                       .stderr(Stdio::null())
                       .spawn().unwrap();

    let tx_stream = recv.stdin.unwrap();
    let rx_stream = recv.stdout.unwrap();
    let mut serial_dev = ChildStdInOut { stdin: tx_stream, stdout: rx_stream };

    let mut xmodem = Xmodem::new();
    xmodem.send(&mut serial_dev, &mut &data[..]).unwrap();

    let mut received_data = Vec::new();
    recv_file.read_to_end(&mut received_data).unwrap();
    let mut padded_data = data.clone();
    for _ in 0..(128 - data.len() % 128) {
        padded_data.push(0x1a);
    }
    assert_eq!(received_data, padded_data);
}

#[test]
fn xmodem_send_crc() {
    let data_len = 2000;
    let mut data = vec![0; data_len];
    thread_rng().fill_bytes(&mut data);

    let mut recv_file = NamedTempFile::new().unwrap();
    let recv = Command::new("rb")
                       .arg("--xmodem")
                       .arg("--with-crc")
                       .arg(recv_file.path())
                       .stdin(Stdio::piped())
                       .stdout(Stdio::piped())
                       .stderr(Stdio::null())
                       .spawn().unwrap();

    let tx_stream = recv.stdin.unwrap();
    let rx_stream = recv.stdout.unwrap();
    let mut serial_dev = ChildStdInOut { stdin: tx_stream, stdout: rx_stream };

    let mut xmodem = Xmodem::new();
    xmodem.send(&mut serial_dev, &mut &data[..]).unwrap();

    let mut received_data = Vec::new();
    recv_file.read_to_end(&mut received_data).unwrap();
    let mut padded_data = data.clone();
    for _ in 0..(128 - data.len() % 128) {
        padded_data.push(0x1a);
    }
    assert_eq!(received_data, padded_data);
}
<|endoftext|>


<commit_before>#![allow(dead_code, non_camel_case_types)]
#[macro_use]
extern crate derive_more;

#[derive(
    From,
    FromStr,
    Display,
    Index,
    Not,
    Add,
    Mul,
    Sum,
    IndexMut,
    AddAssign,
    Deref,
    DerefMut,
    IntoIterator,
    IntoIteratorRef,
    IntoIteratorRefMut,
    Constructor
)]
#[deref(forward)]
#[deref_mut(forward)]
struct Wrapped<T: Clone>(T);

#[derive(Iterator, Deref, DerefMut)]
struct Wrapped2<T: Clone>(T);

#[derive(From, Not, Add, Mul, AddAssign, Constructor, Sum)]
struct WrappedDouble<T: Clone, U: Clone>(T, U);

#[derive(
    From,
    FromStr,
    Display,
    Index,
    Not,
    Add,
    Mul,
    IndexMut,
    AddAssign,
    Deref,
    DerefMut,
    IntoIterator,
    IntoIteratorRef,
    IntoIteratorRefMut,
    Constructor,
    Sum
)]
struct Struct<T: Clone> {
    t: T,
}

#[derive(Iterator, Deref, DerefMut)]
struct Struct2<T: Clone> {
    t: T,
}

#[derive(From, Not, Add, Mul, AddAssign, Constructor, Sum)]
struct DoubleStruct<T: Clone, U: Clone> {
    t: T,
    u: U,
}

#[derive(From, Not, Add)]
enum TupleEnum<T: Clone, U: Clone> {
    Tuple(T),
    DoubleTuple(T, U),
}

#[derive(From, Not, Add)]
enum StructEnum<T: Clone, U: Clone> {
    Struct { t: T },
    DoubleStruct { t: T, u: U },
}
<commit_msg>Add generic test<commit_after>#![allow(dead_code, non_camel_case_types)]
#[macro_use]
extern crate derive_more;

#[derive(
    From,
    FromStr,
    Display,
    Index,
    Not,
    Add,
    Mul,
    Sum,
    IndexMut,
    AddAssign,
    Deref,
    DerefMut,
    IntoIterator,
    IntoIteratorRef,
    IntoIteratorRefMut,
    Constructor
)]
#[deref(forward)]
#[deref_mut(forward)]
struct Wrapped<T: Clone>(T);

#[derive(Iterator, Deref, DerefMut)]
struct Wrapped2<T: Clone>(T);

#[derive(From, Not, Add, Mul, AddAssign, Constructor, Sum)]
struct WrappedDouble<T: Clone, U: Clone>(T, U);

#[derive(
    From,
    FromStr,
    Display,
    Index,
    Not,
    Add,
    Mul,
    IndexMut,
    AddAssign,
    Deref,
    DerefMut,
    IntoIterator,
    IntoIteratorRef,
    IntoIteratorRefMut,
    Constructor,
    Sum
)]
#[deref(forward)]
#[deref_mut(forward)]
struct Struct<T: Clone> {
    t: T,
}

#[derive(Iterator, Deref, DerefMut)]
struct Struct2<T: Clone> {
    t: T,
}

#[derive(From, Not, Add, Mul, AddAssign, Constructor, Sum)]
struct DoubleStruct<T: Clone, U: Clone> {
    t: T,
    u: U,
}

#[derive(From, Not, Add)]
enum TupleEnum<T: Clone, U: Clone> {
    Tuple(T),
    DoubleTuple(T, U),
}

#[derive(From, Not, Add)]
enum StructEnum<T: Clone, U: Clone> {
    Struct { t: T },
    DoubleStruct { t: T, u: U },
}
<|endoftext|>


<commit_before>mod progress;

use self::progress::Progress;
use anyhow::Result;
use flate2::read::GzDecoder;
use rustc_span::edition::Edition;
use std::fs;
use std::path::Path;
use tar::Archive;
use walkdir::DirEntry;

const REVISION: &str = "46e85b4328fe18492894093c1092dfe509df4370";

#[rustfmt::skip]
static EXCLUDE: &[&str] = &[
    // TODO: Deprecated anonymous parameter syntax in traits
    "test/ui/error-codes/e0119/auxiliary/issue-23563-a.rs",
    "test/ui/issues/issue-13105.rs",
    "test/ui/issues/issue-13775.rs",
    "test/ui/issues/issue-34074.rs",
    "test/ui/proc-macro/trait-fn-args-2015.rs",

    // not actually test cases
    "test/rustdoc-ui/test-compile-fail2.rs",
    "test/rustdoc-ui/test-compile-fail3.rs",
    "test/ui/include-single-expr-helper.rs",
    "test/ui/include-single-expr-helper-1.rs",
    "test/ui/issues/auxiliary/issue-21146-inc.rs",
    "test/ui/json-bom-plus-crlf-multifile-aux.rs",
    "test/ui/macros/auxiliary/macro-comma-support.rs",
    "test/ui/macros/auxiliary/macro-include-items-expr.rs",
];

pub fn base_dir_filter(entry: &DirEntry) -> bool {
    let path = entry.path();
    if path.is_dir() {
        return true; // otherwise walkdir does not visit the files
    }
    if path.extension().map(|e| e != "rs").unwrap_or(true) {
        return false;
    }

    let mut path_string = path.to_string_lossy();
    if cfg!(windows) {
        path_string = path_string.replace('\\', "/").into();
    }
    assert!(path_string.starts_with("tests/rust/src/"));
    let path = &path_string["tests/rust/src/".len()..];

    // TODO assert that parsing fails on the parse-fail cases
    if path.starts_with("test/parse-fail")
        || path.starts_with("test/compile-fail")
        || path.starts_with("test/rustfix")
    {
        return false;
    }

    if path.starts_with("test/ui") {
        let stderr_path = entry.path().with_extension("stderr");
        if stderr_path.exists() {
            // Expected to fail in some way
            return false;
        }
    }

    !EXCLUDE.contains(&path)
}

pub fn edition(path: &Path) -> Edition {
    if path.ends_with("dyn-2015-no-warnings-without-lints.rs") {
        Edition::Edition2015
    } else {
        Edition::Edition2018
    }
}

pub fn clone_rust() {
    let needs_clone = match fs::read_to_string("tests/rust/COMMIT") {
        Err(_) => true,
        Ok(contents) => contents.trim() != REVISION,
    };
    if needs_clone {
        download_and_unpack().unwrap();
    }
    let mut missing = String::new();
    let test_src = Path::new("tests/rust/src");
    for exclude in EXCLUDE {
        if !test_src.join(exclude).exists() {
            missing += "\ntests/rust/src/";
            missing += exclude;
        }
    }
    if !missing.is_empty() {
        panic!("excluded test file does not exist:{}\n", missing);
    }
}

fn download_and_unpack() -> Result<()> {
    let url = format!(
        "https://github.com/rust-lang/rust/archive/{}.tar.gz",
        REVISION
    );
    let response = reqwest::blocking::get(&url)?.error_for_status()?;
    let progress = Progress::new(response);
    let decoder = GzDecoder::new(progress);
    let mut archive = Archive::new(decoder);
    let prefix = format!("rust-{}", REVISION);

    let tests_rust = Path::new("tests/rust");
    if tests_rust.exists() {
        fs::remove_dir_all(tests_rust)?;
    }

    for entry in archive.entries()? {
        let mut entry = entry?;
        let path = entry.path()?;
        if path == Path::new("pax_global_header") {
            continue;
        }
        let relative = path.strip_prefix(&prefix)?;
        let out = tests_rust.join(relative);
        entry.unpack(&out)?;
    }

    fs::write("tests/rust/COMMIT", REVISION)?;
    Ok(())
}
<commit_msg>Unignore one of the anonymous parameter syntax tests<commit_after>mod progress;

use self::progress::Progress;
use anyhow::Result;
use flate2::read::GzDecoder;
use rustc_span::edition::Edition;
use std::fs;
use std::path::Path;
use tar::Archive;
use walkdir::DirEntry;

const REVISION: &str = "46e85b4328fe18492894093c1092dfe509df4370";

#[rustfmt::skip]
static EXCLUDE: &[&str] = &[
    // Deprecated anonymous parameter syntax in traits
    "test/ui/issues/issue-13105.rs",
    "test/ui/issues/issue-13775.rs",
    "test/ui/issues/issue-34074.rs",
    "test/ui/proc-macro/trait-fn-args-2015.rs",

    // not actually test cases
    "test/rustdoc-ui/test-compile-fail2.rs",
    "test/rustdoc-ui/test-compile-fail3.rs",
    "test/ui/include-single-expr-helper.rs",
    "test/ui/include-single-expr-helper-1.rs",
    "test/ui/issues/auxiliary/issue-21146-inc.rs",
    "test/ui/json-bom-plus-crlf-multifile-aux.rs",
    "test/ui/macros/auxiliary/macro-comma-support.rs",
    "test/ui/macros/auxiliary/macro-include-items-expr.rs",
];

pub fn base_dir_filter(entry: &DirEntry) -> bool {
    let path = entry.path();
    if path.is_dir() {
        return true; // otherwise walkdir does not visit the files
    }
    if path.extension().map(|e| e != "rs").unwrap_or(true) {
        return false;
    }

    let mut path_string = path.to_string_lossy();
    if cfg!(windows) {
        path_string = path_string.replace('\\', "/").into();
    }
    assert!(path_string.starts_with("tests/rust/src/"));
    let path = &path_string["tests/rust/src/".len()..];

    // TODO assert that parsing fails on the parse-fail cases
    if path.starts_with("test/parse-fail")
        || path.starts_with("test/compile-fail")
        || path.starts_with("test/rustfix")
    {
        return false;
    }

    if path.starts_with("test/ui") {
        let stderr_path = entry.path().with_extension("stderr");
        if stderr_path.exists() {
            // Expected to fail in some way
            return false;
        }
    }

    !EXCLUDE.contains(&path)
}

pub fn edition(path: &Path) -> Edition {
    if path.ends_with("dyn-2015-no-warnings-without-lints.rs") {
        Edition::Edition2015
    } else {
        Edition::Edition2018
    }
}

pub fn clone_rust() {
    let needs_clone = match fs::read_to_string("tests/rust/COMMIT") {
        Err(_) => true,
        Ok(contents) => contents.trim() != REVISION,
    };
    if needs_clone {
        download_and_unpack().unwrap();
    }
    let mut missing = String::new();
    let test_src = Path::new("tests/rust/src");
    for exclude in EXCLUDE {
        if !test_src.join(exclude).exists() {
            missing += "\ntests/rust/src/";
            missing += exclude;
        }
    }
    if !missing.is_empty() {
        panic!("excluded test file does not exist:{}\n", missing);
    }
}

fn download_and_unpack() -> Result<()> {
    let url = format!(
        "https://github.com/rust-lang/rust/archive/{}.tar.gz",
        REVISION
    );
    let response = reqwest::blocking::get(&url)?.error_for_status()?;
    let progress = Progress::new(response);
    let decoder = GzDecoder::new(progress);
    let mut archive = Archive::new(decoder);
    let prefix = format!("rust-{}", REVISION);

    let tests_rust = Path::new("tests/rust");
    if tests_rust.exists() {
        fs::remove_dir_all(tests_rust)?;
    }

    for entry in archive.entries()? {
        let mut entry = entry?;
        let path = entry.path()?;
        if path == Path::new("pax_global_header") {
            continue;
        }
        let relative = path.strip_prefix(&prefix)?;
        let out = tests_rust.join(relative);
        entry.unpack(&out)?;
    }

    fs::write("tests/rust/COMMIT", REVISION)?;
    Ok(())
}
<|endoftext|>


<commit_before>//! Module for built-in filter functions
//!
//! Contains all the built-in filter functions for use in templates.
//! You can define your own filters; for more information,
//! see the top-level crate documentation.

#[cfg(feature = "serde-json")]
mod json;

#[cfg(feature = "serde-json")]
pub use self::json::json;

use num_traits::Signed;
use std::fmt;

use super::Result;
use escaping::{self, MarkupDisplay};

// This is used by the code generator to decide whether a named filter is part of
// Askama or should refer to a local `filters` module. It should contain all the
// filters shipped with Askama, even the optional ones (since optional inclusion
// in the const vector based on features seems impossible right now).
pub const BUILT_IN_FILTERS: [&str; 17] = [
    "abs",
    "capitalize",
    "e",
    "escape",
    "format",
    "join",
    "linebreaks",
    "linebreaksbr",
    "lower",
    "lowercase",
    "safe",
    "trim",
    "truncate",
    "upper",
    "uppercase",
    "wordcount",
    "json", // Optional feature; reserve the name anyway
];

/// Marks a string (or other `Display` type) as safe
///
/// Use this is you want to allow markup in an expression, or if you know
/// that the expression's contents don't need to be escaped.
pub fn safe<D, I>(v: I) -> Result<MarkupDisplay<D>>
where
    D: fmt::Display,
    MarkupDisplay<D>: From,
{
    let res: MarkupDisplay<D> = v.into();
    Ok(res.mark_safe())
}

/// Escapes `&`, `<` and `>` in strings
pub fn escape<D, I>(i: I) -> Result<MarkupDisplay<String>>
where
    D: fmt::Display,
    MarkupDisplay<D>: From,
{
    let md: MarkupDisplay<D> = i.into();
    Ok(MarkupDisplay::Safe(escaping::escape(md.unsafe_string())))
}

/// Alias for the `escape()` filter
pub fn e<D, I>(i: I) -> Result<MarkupDisplay<String>>
where
    D: fmt::Display,
    MarkupDisplay<D>: From,
{
    escape(i)
}

/// Formats arguments according to the specified format
///
/// The first argument to this filter must be a string literal (as in normal
/// Rust). All arguments are passed through to the `format!()`
/// [macro](https://doc.rust-lang.org/stable/std/macro.format.html) by
/// the Askama code generator.
pub fn format() {}

/// Replaces line breaks in plain text with appropriate HTML
///
/// A single newline becomes an HTML line break `<br>` and a new line
/// followed by a blank line becomes a paragraph break `<p>`.
pub fn linebreaks(s: &fmt::Display) -> Result<String> {
    let s = format!("{}", s);
    let linebroken = s.replace("\n\n", "

").replace("\n", "
");

    Ok(format!("
{}
", linebroken))
}

/// Converts all newlines in a piece of plain text to HTML line breaks
pub fn linebreaksbr(s: &fmt::Display) -> Result<String> {
    let s = format!("{}", s);
    Ok(s.replace("\n", "
"))
}

/// Converts to lowercase
pub fn lower(s: &fmt::Display) -> Result<String> {
    let s = format!("{}", s);
    Ok(s.to_lowercase())
}

/// Alias for the `lower()` filter
pub fn lowercase(s: &fmt::Display) -> Result<String> {
    lower(s)
}

/// Converts to uppercase
pub fn upper(s: &fmt::Display) -> Result<String> {
    let s = format!("{}", s);
    Ok(s.to_uppercase())
}

/// Alias for the `upper()` filter
pub fn uppercase(s: &fmt::Display) -> Result<String> {
    upper(s)
}

/// Strip leading and trailing whitespace
pub fn trim(s: &fmt::Display) -> Result<String> {
    let s = format!("{}", s);
    Ok(s.trim().to_owned())
}

/// Limit string length, appends '...' if truncated
pub fn truncate(s: &fmt::Display, len: &usize) -> Result<String> {
    let mut s = format!("{}", s);
    if s.len() < *len {
        Ok(s)
    } else {
        s.truncate(*len);
        s.push_str("...");
        Ok(s)
    }
}

/// Joins iterable into a string separated by provided argument
pub fn join<T, I, S>(input: I, separator: S) -> Result<String>
where
    T: fmt::Display,
    I: Iterator<Item = T>,
    S: AsRef<str>,
{
    let separator: &str = separator.as_ref();

    let mut rv = String::new();

    for (num, item) in input.enumerate() {
        if num > 0 {
            rv.push_str(separator);
        }

        rv.push_str(&format!("{}", item));
    }

    Ok(rv)
}

/// Absolute value
pub fn abs<T>(number: T) -> Result<T>
where
    T: Signed,
{
    Ok(number.abs())
}

/// Capitalize a value. The first character will be uppercase, all others lowercase.
pub fn capitalize(s: &fmt::Display) -> Result<String> {
    let mut s = format!("{}", s);

    match s.get_mut(0..1).map(|s| {
        s.make_ascii_uppercase();
        &*s
    }) {
        None => Ok(s),
        _ => {
            let l = s.len();
            match s.get_mut(1..l).map(|s| {
                s.make_ascii_lowercase();
                &*s
            }) {
                _ => Ok(s),
            }
        }
    }
}

/// Count the words in that string.
pub fn wordcount(s: &fmt::Display) -> Result<usize> {
    let s = format!("{}", s);

    Ok(s.split_whitespace().count())
}

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

    #[test]
    fn test_linebreaks() {
        assert_eq!(
            linebreaks(&"Foo\nBar Baz").unwrap(),
            "
Foo
Bar Baz
"
        );
        assert_eq!(
            linebreaks(&"Foo\nBar\n\nBaz").unwrap(),
            "
Foo
Bar

Baz
"
        );
    }

    #[test]
    fn test_linebreaksbr() {
        assert_eq!(linebreaksbr(&"Foo\nBar").unwrap(), "Foo
Bar");
        assert_eq!(
            linebreaksbr(&"Foo\nBar\n\nBaz").unwrap(),
            "Foo
Bar

Baz"
        );
    }

    #[test]
    fn test_lower() {
        assert_eq!(lower(&"Foo").unwrap(), "foo");
        assert_eq!(lower(&"FOO").unwrap(), "foo");
        assert_eq!(lower(&"FooBar").unwrap(), "foobar");
        assert_eq!(lower(&"foo").unwrap(), "foo");
    }

    #[test]
    fn test_upper() {
        assert_eq!(upper(&"Foo").unwrap(), "FOO");
        assert_eq!(upper(&"FOO").unwrap(), "FOO");
        assert_eq!(upper(&"FooBar").unwrap(), "FOOBAR");
        assert_eq!(upper(&"foo").unwrap(), "FOO");
    }

    #[test]
    fn test_trim() {
        assert_eq!(trim(&" Hello\tworld\t").unwrap(), "Hello\tworld");
    }

    #[test]
    fn test_join() {
        assert_eq!(
            join((&["hello", "world"]).into_iter(), ", ").unwrap(),
            "hello, world"
        );
        assert_eq!(join((&["hello"]).into_iter(), ", ").unwrap(), "hello");

        let empty: &[&str] = &[];
        assert_eq!(join(empty.into_iter(), ", ").unwrap(), "");

        let input: Vec<String> = vec!["foo".into(), "bar".into(), "bazz".into()];
        assert_eq!(
            join((&input).into_iter(), ":".to_string()).unwrap(),
            "foo:bar:bazz"
        );
        assert_eq!(
            join(input.clone().into_iter(), ":").unwrap(),
            "foo:bar:bazz"
        );
        assert_eq!(
            join(input.clone().into_iter(), ":".to_string()).unwrap(),
            "foo:bar:bazz"
        );

        let input: &[String] = &["foo".into(), "bar".into()];
        assert_eq!(join(input.into_iter(), ":").unwrap(), "foo:bar");
        assert_eq!(join(input.into_iter(), ":".to_string()).unwrap(), "foo:bar");

        let real: String = "blah".into();
        let input: Vec<&str> = vec![&real];
        assert_eq!(join(input.into_iter(), ";").unwrap(), "blah");

        assert_eq!(
            join((&&&&&["foo", "bar"]).into_iter(), ", ").unwrap(),
            "foo, bar"
        );
    }

    #[test]
    fn test_abs() {
        assert_eq!(abs(1).unwrap(), 1);
        assert_eq!(abs(-1).unwrap(), 1);
        assert_eq!(abs(1.0).unwrap(), 1.0);
        assert_eq!(abs(-1.0).unwrap(), 1.0);
        assert_eq!(abs(1.0 as f64).unwrap(), 1.0 as f64);
        assert_eq!(abs(-1.0 as f64).unwrap(), 1.0 as f64);
    }

    #[test]
    fn test_capitalize() {
        assert_eq!(capitalize(&"foo").unwrap(), "Foo".to_string());
        assert_eq!(capitalize(&"f").unwrap(), "F".to_string());
        assert_eq!(capitalize(&"fO").unwrap(), "Fo".to_string());
        assert_eq!(capitalize(&"").unwrap(), "".to_string());
        assert_eq!(capitalize(&"FoO").unwrap(), "Foo".to_string());
        assert_eq!(capitalize(&"foO BAR").unwrap(), "Foo bar".to_string());
    }

    #[test]
    fn test_wordcount() {
        assert_eq!(wordcount(&"").unwrap(), 0);
        assert_eq!(wordcount(&" \n\t").unwrap(), 0);
        assert_eq!(wordcount(&"foo").unwrap(), 1);
        assert_eq!(wordcount(&"foo bar").unwrap(), 2);
    }
}
<commit_msg>Add center filter<commit_after>//! Module for built-in filter functions
//!
//! Contains all the built-in filter functions for use in templates.
//! You can define your own filters; for more information,
//! see the top-level crate documentation.

#[cfg(feature = "serde-json")]
mod json;

#[cfg(feature = "serde-json")]
pub use self::json::json;

use num_traits::Signed;
use std::fmt;

use super::Result;
use escaping::{self, MarkupDisplay};

// This is used by the code generator to decide whether a named filter is part of
// Askama or should refer to a local `filters` module. It should contain all the
// filters shipped with Askama, even the optional ones (since optional inclusion
// in the const vector based on features seems impossible right now).
pub const BUILT_IN_FILTERS: [&str; 18] = [
    "abs",
    "capitalize",
    "center",
    "e",
    "escape",
    "format",
    "join",
    "linebreaks",
    "linebreaksbr",
    "lower",
    "lowercase",
    "safe",
    "trim",
    "truncate",
    "upper",
    "uppercase",
    "wordcount",
    "json", // Optional feature; reserve the name anyway
];

/// Marks a string (or other `Display` type) as safe
///
/// Use this is you want to allow markup in an expression, or if you know
/// that the expression's contents don't need to be escaped.
pub fn safe<D, I>(v: I) -> Result<MarkupDisplay<D>>
where
    D: fmt::Display,
    MarkupDisplay<D>: From,
{
    let res: MarkupDisplay<D> = v.into();
    Ok(res.mark_safe())
}

/// Escapes `&`, `<` and `>` in strings
pub fn escape<D, I>(i: I) -> Result<MarkupDisplay<String>>
where
    D: fmt::Display,
    MarkupDisplay<D>: From,
{
    let md: MarkupDisplay<D> = i.into();
    Ok(MarkupDisplay::Safe(escaping::escape(md.unsafe_string())))
}

/// Alias for the `escape()` filter
pub fn e<D, I>(i: I) -> Result<MarkupDisplay<String>>
where
    D: fmt::Display,
    MarkupDisplay<D>: From,
{
    escape(i)
}

/// Formats arguments according to the specified format
///
/// The first argument to this filter must be a string literal (as in normal
/// Rust). All arguments are passed through to the `format!()`
/// [macro](https://doc.rust-lang.org/stable/std/macro.format.html) by
/// the Askama code generator.
pub fn format() {}

/// Replaces line breaks in plain text with appropriate HTML
///
/// A single newline becomes an HTML line break `<br>` and a new line
/// followed by a blank line becomes a paragraph break `<p>`.
pub fn linebreaks(s: &fmt::Display) -> Result<String> {
    let s = format!("{}", s);
    let linebroken = s.replace("\n\n", "

").replace("\n", "
");

    Ok(format!("
{}
", linebroken))
}

/// Converts all newlines in a piece of plain text to HTML line breaks
pub fn linebreaksbr(s: &fmt::Display) -> Result<String> {
    let s = format!("{}", s);
    Ok(s.replace("\n", "
"))
}

/// Converts to lowercase
pub fn lower(s: &fmt::Display) -> Result<String> {
    let s = format!("{}", s);
    Ok(s.to_lowercase())
}

/// Alias for the `lower()` filter
pub fn lowercase(s: &fmt::Display) -> Result<String> {
    lower(s)
}

/// Converts to uppercase
pub fn upper(s: &fmt::Display) -> Result<String> {
    let s = format!("{}", s);
    Ok(s.to_uppercase())
}

/// Alias for the `upper()` filter
pub fn uppercase(s: &fmt::Display) -> Result<String> {
    upper(s)
}

/// Strip leading and trailing whitespace
pub fn trim(s: &fmt::Display) -> Result<String> {
    let s = format!("{}", s);
    Ok(s.trim().to_owned())
}

/// Limit string length, appends '...' if truncated
pub fn truncate(s: &fmt::Display, len: &usize) -> Result<String> {
    let mut s = format!("{}", s);
    if s.len() < *len {
        Ok(s)
    } else {
        s.truncate(*len);
        s.push_str("...");
        Ok(s)
    }
}

/// Joins iterable into a string separated by provided argument
pub fn join<T, I, S>(input: I, separator: S) -> Result<String>
where
    T: fmt::Display,
    I: Iterator<Item = T>,
    S: AsRef<str>,
{
    let separator: &str = separator.as_ref();

    let mut rv = String::new();

    for (num, item) in input.enumerate() {
        if num > 0 {
            rv.push_str(separator);
        }

        rv.push_str(&format!("{}", item));
    }

    Ok(rv)
}

/// Absolute value
pub fn abs<T>(number: T) -> Result<T>
where
    T: Signed,
{
    Ok(number.abs())
}

/// Capitalize a value. The first character will be uppercase, all others lowercase.
pub fn capitalize(s: &fmt::Display) -> Result<String> {
    let mut s = format!("{}", s);

    match s.get_mut(0..1).map(|s| {
        s.make_ascii_uppercase();
        &*s
    }) {
        None => Ok(s),
        _ => {
            let l = s.len();
            match s.get_mut(1..l).map(|s| {
                s.make_ascii_lowercase();
                &*s
            }) {
                _ => Ok(s),
            }
        }
    }
}

/// Centers the value in a field of a given width.
pub fn center(s: &fmt::Display, l: usize) -> Result<String> {
    let s = format!("{}", s);
    let len = s.len();

    if l <= len {
        Ok(s)
    } else {
        let p = l - len;
        let q = p / 2;
        let r = p % 2;
        let mut buf = String::with_capacity(l);

        for _ in 0..q {
            buf.push(' ');
        }

        buf.push_str(&s);

        for _ in 0..q + r {
            buf.push(' ');
        }

        Ok(buf)
    }
}

/// Count the words in that string.
pub fn wordcount(s: &fmt::Display) -> Result<usize> {
    let s = format!("{}", s);

    Ok(s.split_whitespace().count())
}

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

    #[test]
    fn test_linebreaks() {
        assert_eq!(
            linebreaks(&"Foo\nBar Baz").unwrap(),
            "
Foo
Bar Baz
"
        );
        assert_eq!(
            linebreaks(&"Foo\nBar\n\nBaz").unwrap(),
            "
Foo
Bar

Baz
"
        );
    }

    #[test]
    fn test_linebreaksbr() {
        assert_eq!(linebreaksbr(&"Foo\nBar").unwrap(), "Foo
Bar");
        assert_eq!(
            linebreaksbr(&"Foo\nBar\n\nBaz").unwrap(),
            "Foo
Bar

Baz"
        );
    }

    #[test]
    fn test_lower() {
        assert_eq!(lower(&"Foo").unwrap(), "foo");
        assert_eq!(lower(&"FOO").unwrap(), "foo");
        assert_eq!(lower(&"FooBar").unwrap(), "foobar");
        assert_eq!(lower(&"foo").unwrap(), "foo");
    }

    #[test]
    fn test_upper() {
        assert_eq!(upper(&"Foo").unwrap(), "FOO");
        assert_eq!(upper(&"FOO").unwrap(), "FOO");
        assert_eq!(upper(&"FooBar").unwrap(), "FOOBAR");
        assert_eq!(upper(&"foo").unwrap(), "FOO");
    }

    #[test]
    fn test_trim() {
        assert_eq!(trim(&" Hello\tworld\t").unwrap(), "Hello\tworld");
    }

    #[test]
    fn test_join() {
        assert_eq!(
            join((&["hello", "world"]).into_iter(), ", ").unwrap(),
            "hello, world"
        );
        assert_eq!(join((&["hello"]).into_iter(), ", ").unwrap(), "hello");

        let empty: &[&str] = &[];
        assert_eq!(join(empty.into_iter(), ", ").unwrap(), "");

        let input: Vec<String> = vec!["foo".into(), "bar".into(), "bazz".into()];
        assert_eq!(
            join((&input).into_iter(), ":".to_string()).unwrap(),
            "foo:bar:bazz"
        );
        assert_eq!(
            join(input.clone().into_iter(), ":").unwrap(),
            "foo:bar:bazz"
        );
        assert_eq!(
            join(input.clone().into_iter(), ":".to_string()).unwrap(),
            "foo:bar:bazz"
        );

        let input: &[String] = &["foo".into(), "bar".into()];
        assert_eq!(join(input.into_iter(), ":").unwrap(), "foo:bar");
        assert_eq!(join(input.into_iter(), ":".to_string()).unwrap(), "foo:bar");

        let real: String = "blah".into();
        let input: Vec<&str> = vec![&real];
        assert_eq!(join(input.into_iter(), ";").unwrap(), "blah");

        assert_eq!(
            join((&&&&&["foo", "bar"]).into_iter(), ", ").unwrap(),
            "foo, bar"
        );
    }

    #[test]
    fn test_abs() {
        assert_eq!(abs(1).unwrap(), 1);
        assert_eq!(abs(-1).unwrap(), 1);
        assert_eq!(abs(1.0).unwrap(), 1.0);
        assert_eq!(abs(-1.0).unwrap(), 1.0);
        assert_eq!(abs(1.0 as f64).unwrap(), 1.0 as f64);
        assert_eq!(abs(-1.0 as f64).unwrap(), 1.0 as f64);
    }

    #[test]
    fn test_capitalize() {
        assert_eq!(capitalize(&"foo").unwrap(), "Foo".to_string());
        assert_eq!(capitalize(&"f").unwrap(), "F".to_string());
        assert_eq!(capitalize(&"fO").unwrap(), "Fo".to_string());
        assert_eq!(capitalize(&"").unwrap(), "".to_string());
        assert_eq!(capitalize(&"FoO").unwrap(), "Foo".to_string());
        assert_eq!(capitalize(&"foO BAR").unwrap(), "Foo bar".to_string());
    }

    #[test]
    fn test_center() {
        assert_eq!(center(&"f", 3).unwrap(), " f ".to_string());
        assert_eq!(center(&"f", 4).unwrap(), " f  ".to_string());
        assert_eq!(center(&"foo", 1).unwrap(), "foo".to_string());
        assert_eq!(center(&"foo bar", 8).unwrap(), "foo bar ".to_string());
    }

    #[test]
    fn test_wordcount() {
        assert_eq!(wordcount(&"").unwrap(), 0);
        assert_eq!(wordcount(&" \n\t").unwrap(), 0);
        assert_eq!(wordcount(&"foo").unwrap(), 1);
        assert_eq!(wordcount(&"foo bar").unwrap(), 2);
    }
}
<|endoftext|>


<commit_before>extern crate cgmath;
extern crate png;

use std::default::Default;
use std::f64;
use time;

use cgmath::{Matrix4, Point, Point3, Vector3};
use noise;
use noise::{Brownian3, Seed};

#[cfg(target_os = "android")]
use egl_context::EglContext;
use gl;
use gl::Texture;
use mesh;
use program::Program;
use vertices::Vertices;
use world::{Block, World};
#[cfg(target_os = "linux")]
use x11::{PollEventsIterator, XWindow};

#[cfg(target_os = "android")]
pub struct EngineImpl {
  pub egl_context: Option<Box<EglContext>>,
  pub program: Option<Program>,
}

#[cfg(target_os = "android")]
impl Default for EngineImpl {
  fn default() -> EngineImpl {
    EngineImpl {
      egl_context: None,
      program: None,
    }
  }
}

#[cfg(target_os = "linux")]
pub struct EngineImpl {
  pub window: XWindow,
  pub program: Program,
}

pub struct Engine {
  engine_impl: EngineImpl,
  animating: bool,
  angle: f32,  // in degrees.
  /// GL projection matrix
  projection_matrix: Matrix4<f32>,
  /// Texture atlas.
  texture: Texture,
  world: World,
  position_indices: Vec<u16>,
  // Important: need to save position and texture coordinates since OpenGL tries to reload them
  // from memory!
  vertices: Vertices,
}

impl Engine {
  #[cfg(target_os = "android")]
  pub fn new() -> Engine {
    Engine {
      engine_impl: Default::default(),
      animating: false,
      angle: 0.0,
      projection_matrix: Matrix4::identity(),
      texture: Default::default(),
      world: generate_chunk_of_perlin(),
      position_indices: Vec::new(),
      vertices: Vertices::new(0),
    }
  }

  #[cfg(target_os = "linux")]
  pub fn new(window: XWindow, program: Program) -> Engine {
    Engine {
      engine_impl: EngineImpl {
        window: window,
        program: program,
      },
      animating: false,
      angle: 0.0,
      projection_matrix: Matrix4::identity(),
      texture: Default::default(),
      world: generate_chunk_of_perlin(),
      position_indices: Vec::new(),
      vertices: Vertices::new(0),
    }
  }

  /// Initialize the engine.
  #[cfg(target_os = "android")]
  pub fn init(&mut self, egl_context: Box<EglContext>, texture_atlas_bytes: &[u8]) {
    self.engine_impl.egl_context = Some(egl_context);

    self.engine_impl.program = match Program::new() {
      Ok(p) => Some(p),
      Err(e) => panic!("Program failed: {:?}", e),
    };

    self.common_init(texture_atlas_bytes);

    if let Some(ref p) = self.engine_impl.program {
      p.set_texture_unit(0);
    }

    // Silly gymnastics to satisfy the borrow checker.
    let wh = if let Some(ref ec) = self.engine_impl.egl_context {
      Some((ec.width, ec.height))
    } else {
      None
    };
    if let Some((w, h)) = wh {
      self.set_viewport(w, h);
    }
  }

  /// Initialize the engine.
  #[cfg(target_os = "linux")]
  pub fn init(&mut self, texture_atlas_bytes: &[u8]) {
    self.common_init(texture_atlas_bytes);
    self.engine_impl.program.set_texture_unit(0);
  }

  fn common_init(&mut self, texture_atlas_bytes: &[u8]) {
    // Set the background clear color to sky blue.
    gl::clear_color(0.5, 0.69, 1.0, 1.0);

    // Enable reverse face culling.
    gl::enable(gl::CULL_FACE);
    // Enable depth test.
    gl::enable(gl::DEPTH_TEST);
    gl::depth_func(gl::LEQUAL);

    // Set up textures.
    self.texture = Engine::load_texture_atlas(texture_atlas_bytes);
    gl::active_texture(gl::TEXTURE0);
    gl::bind_texture_2d(self.texture);

    self.load_mesh();
  }

  #[cfg(target_os = "android")]
  fn load_mesh(&mut self) {
    let vertices = create_mesh_vertices(&self.world);
    if let Some(ref mut p) = self.engine_impl.program {
      p.set_vertices(&vertices);
    }
    self.position_indices = vertices.position_indices();
    self.vertices = vertices;
  }

  #[cfg(target_os = "linux")]
  fn load_mesh(&mut self) {
    let vertices = create_mesh_vertices(&self.world);
    self.engine_impl.program.set_vertices(&vertices);
    self.position_indices = vertices.position_indices();
    self.vertices = vertices;
  }

  pub fn set_viewport(&mut self, w: i32, h: i32) {
    gl::viewport(0, 0, w, h);
    self.projection_matrix = projection_matrix(w, h);
  }

  /// Load texture atlas from assets folder.
  fn load_texture_atlas(texture_atlas_bytes: &[u8]) -> Texture {
    let image = png::load_png_from_memory(texture_atlas_bytes)
      .unwrap_or_else(|s| panic!("load_png_from_memory() failed: {}", s));

    let pixels = match image.pixels {
      png::PixelsByColorType::RGBA8(v) => v,
      _ => {
        let color_type = match image.pixels {
            png::PixelsByColorType::K8(_) => "K8",
            png::PixelsByColorType::KA8(_) => "KA8",
            png::PixelsByColorType::RGB8(_) => "RGB8",
            png::PixelsByColorType::RGBA8(_) => panic!("Should not happen"),
        };
        panic!("Only RGBA8 image format supported, was: {}", color_type);
      }
    };

    let texture = gl::gen_texture();
    gl::bind_texture_2d(texture);
    gl::texture_2d_param(gl::TEXTURE_MIN_FILTER, gl::LINEAR_MIPMAP_LINEAR);
    gl::texture_2d_param(gl::TEXTURE_MAG_FILTER, gl::LINEAR);
    gl::texture_2d_param(gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE);
    gl::texture_2d_param(gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE);
    gl::texture_2d_image_rgba(image.width as i32, image.height as i32, &pixels);
    gl::generate_mipmap_2d();
    gl::bind_texture_2d(0);

    texture
  }

  /// Draw a frame.
  #[cfg(target_os = "android")]
  pub fn draw(&mut self) {
    if !self.animating {
      return;
    }

    match self.engine_impl.egl_context {
      None => return,  // No display.
      Some(ref egl_context) => {
        gl::clear(gl::DEPTH_BUFFER_BIT | gl::COLOR_BUFFER_BIT);

        match self.engine_impl.program {
          Some(ref p) => {
            // Compute the composite mvp_matrix and send it to program.  Model matrix
            // is always identity so instead of MVP = P * V * M just do MVP = P * V.
            let mvp_matrix = self.projection_matrix * view_matrix(self.angle);
            p.set_mvp_matrix(mvp_matrix);
            // Finally, draw the cube mesh.
            if self.position_indices.len() > 0 {
              // TODO: Switch to VBOs once it works for better performance!!!
              gl::draw_elements_triangles_u16(self.position_indices.len() as i32, &self.position_indices[0..]);
            }
          },
          None => panic!("Missing program, should never happen"),
        }

        egl_context.swap_buffers();
      }
    }
  }

  /// Draw a frame.
  #[cfg(target_os = "linux")]
  pub fn draw(&mut self) {
    if !self.animating {
      return;
    }

    gl::clear(gl::DEPTH_BUFFER_BIT | gl::COLOR_BUFFER_BIT);

    let p = &self.engine_impl.program;

    // Compute the composite mvp_matrix and send it to program.  Model matrix
    // is always identity so instead of MVP = P * V * M just do MVP = P * V.
    let mvp_matrix = self.projection_matrix * view_matrix(self.angle);
    p.set_mvp_matrix(mvp_matrix);

    // Finally, draw the cube mesh.
    if self.position_indices.len() > 0 {
      // TODO: Switch to VBOs once it works for better performance!!!
      gl::draw_elements_triangles_u16(self.position_indices.len() as i32, &self.position_indices[0..]);
    }

    self.engine_impl.window.swap_buffers();
    self.engine_impl.window.flush();
  }

  /// Update for time passed and draw a frame.
  pub fn update_draw(&mut self) {
    if self.animating {
      // Done processing events; draw next animation frame.
      // Do a complete rotation every 10 seconds, assuming 60 FPS.
      self.angle += 360.0 / 600.0;
      if self.angle > 360.0 {
        self.angle = 0.0;
      }

      // Drawing is throttled to the screen update rate, so there is no need to do timing here.
      self.draw();
    }
  }

  /// Terminate the engine.
  #[cfg(target_os = "android")]
  pub fn term(&mut self) {
    self.animating = false;
    // Drop the program and the EGL context.
    self.engine_impl = Default::default();
    log!("*** Renderer terminated");
  }

  /// Called when window gains input focus.
  pub fn gained_focus(&mut self) {
    self.animating = true;
  }

  /// Called when window loses input focus.
  pub fn lost_focus(&mut self) {
    self.animating = false;
  }

  #[cfg(target_os = "linux")]
  pub fn is_closed(&self) -> bool {
    self.engine_impl.window.is_closed()
  }

  #[cfg(target_os = "linux")]
  pub fn poll_events(&self) -> PollEventsIterator {
    self.engine_impl.window.poll_events()
  }
}

fn generate_chunk_of_perlin() -> World {
  let start_s = time::precise_time_s();

  let seed = Seed::new(1);
  let noise = Brownian3::new(noise::perlin3, 4).wavelength(16.0);

  let y_min = -8;
  let y_max = 7;
  let y_range = y_max - y_min;

  let mut min = f64::MAX;
  let mut max = f64::MIN;
  let mut world: World = Default::default();

  for y in y_min..(y_max + 1) {
    // Normalize into [0, 1].
    let normalized_y = (y as f64 - y_min as f64) / y_range as f64;
    for x in -8..8 {
      for z in -8..8 {
        let p = [x as f64, y as f64, z as f64];
        let val = noise.apply(&seed, &p);

        if val < min {
          min = val;
        }
        if val > max {
          max = val;
        }

        // Probablility to have a block added linearly increases from 0.0 at y_max to 1.0 at y_min.
        if 0.5 * (val + 1.0) >= normalized_y {
          world.add(Block::new(x, y, z));
        }
      }
    }
  }

  let spent_ms = (time::precise_time_s() - start_s) * 1000.0;
  log!("*** Generating a chunk of perlin: {:.3}ms, {} blocks", spent_ms, world.len());
  log!("***   min = {}, max = {}", min, max);
  log!("***   world = {:?}", world);

  world
}

fn create_mesh_vertices(world: &World) -> Vertices {
  let mut vertices = Vertices::new(world.len());
  for block in world.iter() {
    // Eliminate definitely invisible faces, i.e. those between two neighboring cubes.
    for face in mesh::CUBE_FACES.iter() {
      if !world.contains(&block.add_v(&face.direction)) {
        vertices.add(&translate(&face.position_coords, block), &face.position_indices, &face.texture_coords);
      }
    }
  }
  vertices
}

/// Accepts vertex coordinates as a flat list: x, y, z, x, y, z, ...
/// Translates them along the vector corresponding to the block.
fn translate(coords: &[f32; 12], block: &Block) -> [f32; 12] {
  let x = block.x as f32;
  let y = block.y as f32;
  let z = block.z as f32;

  [
    coords[0] + x, coords[1] + y, coords[2] + z,
    coords[3] + x, coords[4] + y, coords[5] + z,
    coords[6] + x, coords[7] + y, coords[8] + z,
    coords[9] + x, coords[10] + y, coords[11] + z,
  ]
}

/// A view matrix, eye is on a 10.0 radius circle starting at (0.0, 2.1, 10.0),
/// rotating around (0, 1, 0) counter-clockwise and looking at (0, 2.1, 0).
fn view_matrix(angle: f32) -> Matrix4<f32> {
  let r = 13.0;
  let y = 2.1;  // 0.5 for half block under feet + 1.6 up to eye height.
  let (s, c) = angle.to_radians().sin_cos();
  let eye = Point3::new(r * s, y, r * c);
  let center = Point3::new(0.0, y, 0.0);
  let up = Vector3::new(0.0, 1.0, 0.0);
  Matrix4::look_at(&eye, &center, &up)
}

/// Perspective projection matrix as frustum matrix.
fn projection_matrix(width: i32, height: i32) -> Matrix4<f32> {
  let ratio = width as f32 / height as f32;
  let left = -ratio;
  let right = ratio;
  let bottom = -1.0;
  let top = 1.0;
  let near = 1.0;
  let far = 50.0;
  cgmath::frustum(left, right, bottom, top, near, far)
}
<commit_msg>Stop dumping the world.<commit_after>extern crate cgmath;
extern crate png;

use std::default::Default;
use std::f64;
use time;

use cgmath::{Matrix4, Point, Point3, Vector3};
use noise;
use noise::{Brownian3, Seed};

#[cfg(target_os = "android")]
use egl_context::EglContext;
use gl;
use gl::Texture;
use mesh;
use program::Program;
use vertices::Vertices;
use world::{Block, World};
#[cfg(target_os = "linux")]
use x11::{PollEventsIterator, XWindow};

#[cfg(target_os = "android")]
pub struct EngineImpl {
  pub egl_context: Option<Box<EglContext>>,
  pub program: Option<Program>,
}

#[cfg(target_os = "android")]
impl Default for EngineImpl {
  fn default() -> EngineImpl {
    EngineImpl {
      egl_context: None,
      program: None,
    }
  }
}

#[cfg(target_os = "linux")]
pub struct EngineImpl {
  pub window: XWindow,
  pub program: Program,
}

pub struct Engine {
  engine_impl: EngineImpl,
  animating: bool,
  angle: f32,  // in degrees.
  /// GL projection matrix
  projection_matrix: Matrix4<f32>,
  /// Texture atlas.
  texture: Texture,
  world: World,
  position_indices: Vec<u16>,
  // Important: need to save position and texture coordinates since OpenGL tries to reload them
  // from memory!
  vertices: Vertices,
}

impl Engine {
  #[cfg(target_os = "android")]
  pub fn new() -> Engine {
    Engine {
      engine_impl: Default::default(),
      animating: false,
      angle: 0.0,
      projection_matrix: Matrix4::identity(),
      texture: Default::default(),
      world: generate_chunk_of_perlin(),
      position_indices: Vec::new(),
      vertices: Vertices::new(0),
    }
  }

  #[cfg(target_os = "linux")]
  pub fn new(window: XWindow, program: Program) -> Engine {
    Engine {
      engine_impl: EngineImpl {
        window: window,
        program: program,
      },
      animating: false,
      angle: 0.0,
      projection_matrix: Matrix4::identity(),
      texture: Default::default(),
      world: generate_chunk_of_perlin(),
      position_indices: Vec::new(),
      vertices: Vertices::new(0),
    }
  }

  /// Initialize the engine.
  #[cfg(target_os = "android")]
  pub fn init(&mut self, egl_context: Box<EglContext>, texture_atlas_bytes: &[u8]) {
    self.engine_impl.egl_context = Some(egl_context);

    self.engine_impl.program = match Program::new() {
      Ok(p) => Some(p),
      Err(e) => panic!("Program failed: {:?}", e),
    };

    self.common_init(texture_atlas_bytes);

    if let Some(ref p) = self.engine_impl.program {
      p.set_texture_unit(0);
    }

    // Silly gymnastics to satisfy the borrow checker.
    let wh = if let Some(ref ec) = self.engine_impl.egl_context {
      Some((ec.width, ec.height))
    } else {
      None
    };
    if let Some((w, h)) = wh {
      self.set_viewport(w, h);
    }
  }

  /// Initialize the engine.
  #[cfg(target_os = "linux")]
  pub fn init(&mut self, texture_atlas_bytes: &[u8]) {
    self.common_init(texture_atlas_bytes);
    self.engine_impl.program.set_texture_unit(0);
  }

  fn common_init(&mut self, texture_atlas_bytes: &[u8]) {
    // Set the background clear color to sky blue.
    gl::clear_color(0.5, 0.69, 1.0, 1.0);

    // Enable reverse face culling.
    gl::enable(gl::CULL_FACE);
    // Enable depth test.
    gl::enable(gl::DEPTH_TEST);
    gl::depth_func(gl::LEQUAL);

    // Set up textures.
    self.texture = Engine::load_texture_atlas(texture_atlas_bytes);
    gl::active_texture(gl::TEXTURE0);
    gl::bind_texture_2d(self.texture);

    self.load_mesh();
  }

  #[cfg(target_os = "android")]
  fn load_mesh(&mut self) {
    let vertices = create_mesh_vertices(&self.world);
    if let Some(ref mut p) = self.engine_impl.program {
      p.set_vertices(&vertices);
    }
    self.position_indices = vertices.position_indices();
    self.vertices = vertices;
  }

  #[cfg(target_os = "linux")]
  fn load_mesh(&mut self) {
    let vertices = create_mesh_vertices(&self.world);
    self.engine_impl.program.set_vertices(&vertices);
    self.position_indices = vertices.position_indices();
    self.vertices = vertices;
  }

  pub fn set_viewport(&mut self, w: i32, h: i32) {
    gl::viewport(0, 0, w, h);
    self.projection_matrix = projection_matrix(w, h);
  }

  /// Load texture atlas from assets folder.
  fn load_texture_atlas(texture_atlas_bytes: &[u8]) -> Texture {
    let image = png::load_png_from_memory(texture_atlas_bytes)
      .unwrap_or_else(|s| panic!("load_png_from_memory() failed: {}", s));

    let pixels = match image.pixels {
      png::PixelsByColorType::RGBA8(v) => v,
      _ => {
        let color_type = match image.pixels {
            png::PixelsByColorType::K8(_) => "K8",
            png::PixelsByColorType::KA8(_) => "KA8",
            png::PixelsByColorType::RGB8(_) => "RGB8",
            png::PixelsByColorType::RGBA8(_) => panic!("Should not happen"),
        };
        panic!("Only RGBA8 image format supported, was: {}", color_type);
      }
    };

    let texture = gl::gen_texture();
    gl::bind_texture_2d(texture);
    gl::texture_2d_param(gl::TEXTURE_MIN_FILTER, gl::LINEAR_MIPMAP_LINEAR);
    gl::texture_2d_param(gl::TEXTURE_MAG_FILTER, gl::LINEAR);
    gl::texture_2d_param(gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE);
    gl::texture_2d_param(gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE);
    gl::texture_2d_image_rgba(image.width as i32, image.height as i32, &pixels);
    gl::generate_mipmap_2d();
    gl::bind_texture_2d(0);

    texture
  }

  /// Draw a frame.
  #[cfg(target_os = "android")]
  pub fn draw(&mut self) {
    if !self.animating {
      return;
    }

    match self.engine_impl.egl_context {
      None => return,  // No display.
      Some(ref egl_context) => {
        gl::clear(gl::DEPTH_BUFFER_BIT | gl::COLOR_BUFFER_BIT);

        match self.engine_impl.program {
          Some(ref p) => {
            // Compute the composite mvp_matrix and send it to program.  Model matrix
            // is always identity so instead of MVP = P * V * M just do MVP = P * V.
            let mvp_matrix = self.projection_matrix * view_matrix(self.angle);
            p.set_mvp_matrix(mvp_matrix);
            // Finally, draw the cube mesh.
            if self.position_indices.len() > 0 {
              // TODO: Switch to VBOs once it works for better performance!!!
              gl::draw_elements_triangles_u16(self.position_indices.len() as i32, &self.position_indices[0..]);
            }
          },
          None => panic!("Missing program, should never happen"),
        }

        egl_context.swap_buffers();
      }
    }
  }

  /// Draw a frame.
  #[cfg(target_os = "linux")]
  pub fn draw(&mut self) {
    if !self.animating {
      return;
    }

    gl::clear(gl::DEPTH_BUFFER_BIT | gl::COLOR_BUFFER_BIT);

    let p = &self.engine_impl.program;

    // Compute the composite mvp_matrix and send it to program.  Model matrix
    // is always identity so instead of MVP = P * V * M just do MVP = P * V.
    let mvp_matrix = self.projection_matrix * view_matrix(self.angle);
    p.set_mvp_matrix(mvp_matrix);

    // Finally, draw the cube mesh.
    if self.position_indices.len() > 0 {
      // TODO: Switch to VBOs once it works for better performance!!!
      gl::draw_elements_triangles_u16(self.position_indices.len() as i32, &self.position_indices[0..]);
    }

    self.engine_impl.window.swap_buffers();
    self.engine_impl.window.flush();
  }

  /// Update for time passed and draw a frame.
  pub fn update_draw(&mut self) {
    if self.animating {
      // Done processing events; draw next animation frame.
      // Do a complete rotation every 10 seconds, assuming 60 FPS.
      self.angle += 360.0 / 600.0;
      if self.angle > 360.0 {
        self.angle = 0.0;
      }

      // Drawing is throttled to the screen update rate, so there is no need to do timing here.
      self.draw();
    }
  }

  /// Terminate the engine.
  #[cfg(target_os = "android")]
  pub fn term(&mut self) {
    self.animating = false;
    // Drop the program and the EGL context.
    self.engine_impl = Default::default();
    log!("*** Renderer terminated");
  }

  /// Called when window gains input focus.
  pub fn gained_focus(&mut self) {
    self.animating = true;
  }

  /// Called when window loses input focus.
  pub fn lost_focus(&mut self) {
    self.animating = false;
  }

  #[cfg(target_os = "linux")]
  pub fn is_closed(&self) -> bool {
    self.engine_impl.window.is_closed()
  }

  #[cfg(target_os = "linux")]
  pub fn poll_events(&self) -> PollEventsIterator {
    self.engine_impl.window.poll_events()
  }
}

fn generate_chunk_of_perlin() -> World {
  let start_s = time::precise_time_s();

  let seed = Seed::new(1);
  let noise = Brownian3::new(noise::perlin3, 4).wavelength(16.0);

  let y_min = -8;
  let y_max = 7;
  let y_range = y_max - y_min;

  let mut min = f64::MAX;
  let mut max = f64::MIN;
  let mut world: World = Default::default();

  for y in y_min..(y_max + 1) {
    // Normalize into [0, 1].
    let normalized_y = (y as f64 - y_min as f64) / y_range as f64;
    for x in -8..8 {
      for z in -8..8 {
        let p = [x as f64, y as f64, z as f64];
        let val = noise.apply(&seed, &p);

        if val < min {
          min = val;
        }
        if val > max {
          max = val;
        }

        // Probablility to have a block added linearly increases from 0.0 at y_max to 1.0 at y_min.
        if 0.5 * (val + 1.0) >= normalized_y {
          world.add(Block::new(x, y, z));
        }
      }
    }
  }

  let spent_ms = (time::precise_time_s() - start_s) * 1000.0;
  log!("*** Generating a chunk of perlin: {:.3}ms, {} blocks", spent_ms, world.len());
  log!("***   min = {}, max = {}", min, max);

  world
}

fn create_mesh_vertices(world: &World) -> Vertices {
  let mut vertices = Vertices::new(world.len());
  for block in world.iter() {
    // Eliminate definitely invisible faces, i.e. those between two neighboring cubes.
    for face in mesh::CUBE_FACES.iter() {
      if !world.contains(&block.add_v(&face.direction)) {
        vertices.add(&translate(&face.position_coords, block), &face.position_indices, &face.texture_coords);
      }
    }
  }
  vertices
}

/// Accepts vertex coordinates as a flat list: x, y, z, x, y, z, ...
/// Translates them along the vector corresponding to the block.
fn translate(coords: &[f32; 12], block: &Block) -> [f32; 12] {
  let x = block.x as f32;
  let y = block.y as f32;
  let z = block.z as f32;

  [
    coords[0] + x, coords[1] + y, coords[2] + z,
    coords[3] + x, coords[4] + y, coords[5] + z,
    coords[6] + x, coords[7] + y, coords[8] + z,
    coords[9] + x, coords[10] + y, coords[11] + z,
  ]
}

/// A view matrix, eye is on a 10.0 radius circle starting at (0.0, 2.1, 10.0),
/// rotating around (0, 1, 0) counter-clockwise and looking at (0, 2.1, 0).
fn view_matrix(angle: f32) -> Matrix4<f32> {
  let r = 13.0;
  let y = 2.1;  // 0.5 for half block under feet + 1.6 up to eye height.
  let (s, c) = angle.to_radians().sin_cos();
  let eye = Point3::new(r * s, y, r * c);
  let center = Point3::new(0.0, y, 0.0);
  let up = Vector3::new(0.0, 1.0, 0.0);
  Matrix4::look_at(&eye, &center, &up)
}

/// Perspective projection matrix as frustum matrix.
fn projection_matrix(width: i32, height: i32) -> Matrix4<f32> {
  let ratio = width as f32 / height as f32;
  let left = -ratio;
  let right = ratio;
  let bottom = -1.0;
  let top = 1.0;
  let near = 1.0;
  let far = 50.0;
  cgmath::frustum(left, right, bottom, top, near, far)
}
<|endoftext|>


<commit_before>extern mod extra;
use std::vec::from_elem;
mod grid;

/****************************************************************************
 * Something to say Ben??
 ****************************************************************************/

/*
 * Constructs an immutable grid from the contents of an array of strings.
 * The grid is declared mutable, and mutated only inside this fn.
*/
pub fn build_from_file_contents(file_contents: ~[~str]) -> grid::Grid
{
  let height = file_contents.len();
  assert!(height > 0u);
  let width = file_contents[0].len();
  let cells = from_elem(width, grid::Cell { value: grid::alive } );

  let mut result = grid::Grid {
      inner: from_elem(height, cells.clone())
  };
  for row in range(0, height) {
    for column in range(0, width) {
      let file_value: char = file_contents[row][column] as char;
      let cell_value = match file_value {
        'o' => grid::alive,
        '.' => grid::dead,
         _  => fail!("Unexpected cell value found in file.")
      };
      result.inner[row][column] = grid::Cell { value: cell_value };
   }
  }
  return result;
} // fn build_from_file_contents

enum direction {
  above, below, left, right
}  // enum CellValue

/*
  Calculates the neighbor's position given the inputs.
*/
fn neighbor_pos(grid::Row(row): grid::Row, grid::Column(column): grid::Column, dir: direction,
    grid: &grid::Grid) -> (grid::Row, grid::Column)
{
  return match dir {
    above => (grid::Row(row - 1), grid::Column(column)),
    below => (grid::Row(row + 1), grid::Column(column)),
    right => (grid::Row(row), grid::Column(column + 1)),
    left  => (grid::Row(row), grid::Column(column - 1))
  };
}  // fn neighbor_pos

/*
 * Returns a count for how many neighbors of a cell in the grid
 * are alive.
*/
pub fn count_neighbors(row: grid::Row, column: grid::Column, grid: &grid::Grid)
    -> uint
{
  let (same_row, left_column)  = neighbor_pos(row, column, left, grid);
  let (same_row, right_column) = neighbor_pos(row, column, right, grid);
  let (above_row, same_column) = neighbor_pos(row, column, above, grid);
  let (below_row, same_column) = neighbor_pos(row, column, below, grid);

  let (above_left_row, above_left_column) = neighbor_pos(above_row, same_column, left, grid);
  let (above_right_row, above_right_column) = neighbor_pos(above_row, same_column, right, grid);
  let (below_left_row, below_left_column) = neighbor_pos(below_row, same_column, left, grid);
  let (below_right_row, below_right_column) = neighbor_pos(below_row, same_column, right, grid);

  let c0 = grid.cell_alive(same_row, left_column);
  let c1 = grid.cell_alive(same_row, right_column);
  let c2 = grid.cell_alive(above_row, same_column);
  let c3 = grid.cell_alive(below_row, same_column);

  let c4 = grid.cell_alive(above_left_row, above_left_column);
  let c5 = grid.cell_alive(above_right_row, above_right_column);
  let c6 = grid.cell_alive(below_left_row, below_left_column);
  let c7 = grid.cell_alive(below_right_row, below_right_column);
  return c0 + c1 + c2 + c3 + c4 + c5 + c6 + c7;
}

/*pub fn print_neighbor_count(grid: &grid::Grid) {
  let x = grid.inner.len();
  for row in range(0, x) {
    for column in range(0, x) {
      let r = grid::Row(row);
      let c = grid::Column(column);
      let n = count_neighbors(r, c, grid);
      print!("{:u}", n);
    }
    println!("");
  }
}  // fn print_neighbor_count
*/

// 1)Any live cell with fewer than two live neighbours dies, as if caused by
// under-population.
// 2) Any live cell with two or three live neighbours lives on to the next
// generation.
// 3) Any live cell with more than three live neighbours dies, as if by
// overcrowding.
// 4) Any dead cell with exactly three live neighbours becomes a live cell, as
// if by reproduction.
pub fn build_from_grid(prevg: &grid::Grid) -> grid::Grid
{
  let mut result = prevg.clone();
  for row in range(0, prevg.height()) {
    for column in range(0, prevg.width()) {
      let ncount = count_neighbors(grid::Row(row), grid::Column(column), prevg);
      result.inner[row][column] = grid::Cell { value:
        match (prevg.inner[row][column].value, ncount) {
          (grid::dead, 3)     => grid::alive,
          (grid::alive, 2..3) => grid::alive,
          _                   => grid::dead
        }
      };
    }
  }
  return result;
}  // fn build_from_grid
<commit_msg>GridBuilder now imports grid symbols.<commit_after>extern mod extra;
use std::vec::from_elem;
use grid::{Row, Column, alive, dead, Cell, Grid};
mod grid;

/****************************************************************************
 * Something to say Ben??
 ****************************************************************************/

/*
 * Constructs an immutable grid from the contents of an array of strings.
 * The grid is declared mutable, and mutated only inside this fn.
*/
pub fn build_from_file_contents(file_contents: ~[~str]) -> Grid
{
  let height = file_contents.len();
  assert!(height > 0u);
  let width = file_contents[0].len();
  let cells = from_elem(width, Cell { value: alive } );

  let mut result = Grid {
      inner: from_elem(height, cells.clone())
  };
  for row in range(0, height) {
    for column in range(0, width) {
      let file_value: char = file_contents[row][column] as char;
      let cell_value = match file_value {
        'o' => alive,
        '.' => dead,
         _  => fail!("Unexpected cell value found in file.")
      };
      result.inner[row][column] = Cell { value: cell_value };
   }
  }
  return result;
} // fn build_from_file_contents

enum direction {
  above, below, left, right
}  // enum CellValue

/*
  Calculates the neighbor's position given the inputs.
*/
fn neighbor_pos(Row(row): Row, Column(column): Column, dir: direction)
    -> (Row, Column)
{
  return match dir {
    above => (Row(row - 1), Column(column)),
    below => (Row(row + 1), Column(column)),
    right => (Row(row), Column(column + 1)),
    left  => (Row(row), Column(column - 1))
  };
}  // fn neighbor_pos

/*
 * Returns a count for how many neighbors of a cell in the grid
 * are alive.
*/
pub fn count_neighbors(row: Row, column: Column, grid: &Grid)
    -> uint
{
  let (same_row, left_column)  = neighbor_pos(row, column, left);
  let (same_row, right_column) = neighbor_pos(row, column, right);
  let (above_row, same_column) = neighbor_pos(row, column, above);
  let (below_row, same_column) = neighbor_pos(row, column, below);

  let (above_left_row, above_left_column) = neighbor_pos(above_row, same_column, left);
  let (above_right_row, above_right_column) = neighbor_pos(above_row, same_column, right);
  let (below_left_row, below_left_column) = neighbor_pos(below_row, same_column, left);
  let (below_right_row, below_right_column) = neighbor_pos(below_row, same_column, right);

  let c0 = grid.cell_alive(same_row, left_column);
  let c1 = grid.cell_alive(same_row, right_column);
  let c2 = grid.cell_alive(above_row, same_column);
  let c3 = grid.cell_alive(below_row, same_column);

  let c4 = grid.cell_alive(above_left_row, above_left_column);
  let c5 = grid.cell_alive(above_right_row, above_right_column);
  let c6 = grid.cell_alive(below_left_row, below_left_column);
  let c7 = grid.cell_alive(below_right_row, below_right_column);
  return c0 + c1 + c2 + c3 + c4 + c5 + c6 + c7;
}

/*pub fn print_neighbor_count(grid: &Grid) {
  let x = grid.inner.len();
  for row in range(0, x) {
    for column in range(0, x) {
      let r = Row(row);
      let c = Column(column);
      let n = count_neighbors(r, c, grid);
      print!("{:u}", n);
    }
    println!("");
  }
}  // fn print_neighbor_count
*/

// 1)Any live cell with fewer than two live neighbours dies, as if caused by
// under-population.
// 2) Any live cell with two or three live neighbours lives on to the next
// generation.
// 3) Any live cell with more than three live neighbours dies, as if by
// overcrowding.
// 4) Any dead cell with exactly three live neighbours becomes a live cell, as
// if by reproduction.
pub fn build_from_grid(prevg: &Grid) -> Grid
{
  let mut result = prevg.clone();
  for row in range(0, prevg.height()) {
    for column in range(0, prevg.width()) {
      let ncount = count_neighbors(Row(row), Column(column), prevg);
      result.inner[row][column] = Cell { value:
        match (prevg.inner[row][column].value, ncount) {
          (dead, 3)     => alive,
          (alive, 2..3) => alive,
          _             => dead
        }
      };
    }
  }
  return result;
}  // fn build_from_grid
<|endoftext|>