<commit_before>use proc_macro2::TokenStream;

use quote::ToTokens;

use shared::path;

use std::path::PathBuf;

use syn;

pub struct TemplateInput<'a> {
    pub ast: &'a syn::DeriveInput,
    pub source: Source,
    pub print: Print,
    pub escaping: EscapeMode,
    pub ext: Option<String>,
    pub parent: Option<&'a syn::Type>,
    pub path: PathBuf,
}

impl<'a> TemplateInput<'a> {
    pub fn new(ast: &'a syn::DeriveInput) -> TemplateInput<'a> {
        let mut meta = None;
        for attr in &ast.attrs {
            match attr.interpret_meta() {
                Some(m) => if m.name() == "template" {
                    meta = Some(m)
                },
                None => {
                    let mut tokens = TokenStream::new();
                    attr.to_tokens(&mut tokens);
                    panic!("unable to interpret attribute: {}", tokens)
                }
            }
        }

        let meta_list = match meta.expect("no attribute 'template' found") {
            syn::Meta::List(inner) => inner,
            _ => panic!("attribute 'template' has incorrect type"),
        };

        let mut source = None;
        let mut print = Print::None;
        let mut escaping = None;
        let mut ext = None;
        for nm_item in meta_list.nested {
            if let syn::NestedMeta::Meta(ref item) = nm_item {
                if let syn::Meta::NameValue(ref pair) = item {
                    match pair.ident.to_string().as_ref() {
                        "path" => if let syn::Lit::Str(ref s) = pair.lit {
                            if source.is_some() {
                                panic!("must specify 'source' or 'path', not both");
                            }
                            source = Some(Source::Path(s.value()));
                        } else {
                            panic!("template path must be string literal");
                        },
                        "source" => if let syn::Lit::Str(ref s) = pair.lit {
                            if source.is_some() {
                                panic!("must specify 'source' or 'path', not both");
                            }
                            source = Some(Source::Source(s.value()));
                        } else {
                            panic!("template source must be string literal");
                        },
                        "print" => if let syn::Lit::Str(ref s) = pair.lit {
                            print = s.value().into();
                        } else {
                            panic!("print value must be string literal");
                        },
                        "escape" => if let syn::Lit::Str(ref s) = pair.lit {
                            escaping = Some(s.value().into());
                        } else {
                            panic!("escape value must be string literal");
                        },
                        "ext" => if let syn::Lit::Str(ref s) = pair.lit {
                            ext = Some(s.value());
                        } else {
                            panic!("ext value must be string literal");
                        },
                        attr => panic!("unsupported annotation key '{}' found", attr),
                    }
                }
            }
        }

        let source = source.expect("template path or source not found in attributes");
        let path = match (&source, &ext) {
            (&Source::Path(ref path), None) => path::find_template_from_path(path, None),
            (&Source::Source(_), Some(ext)) => PathBuf::from(format!("{}.{}", ast.ident, ext)),
            (&Source::Path(_), Some(_)) => {
                panic!("'ext' attribute cannot be used with 'path' attribute")
            }
            (&Source::Source(_), None) => {
                panic!("must include 'ext' attribute when using 'source' attribute")
            }
        };

        let parent = match ast.data {
            syn::Data::Struct(syn::DataStruct {
                fields: syn::Fields::Named(ref fields),
                ..
            }) => fields.named.iter().find(|f| {
                if let Some(field_name) = f.ident.as_ref() {
                    field_name == "_parent"
                } else {
                    false
                }
            }),
            _ => panic!("derive(Template) only works for struct items"),
        };
        let parent = if let Some(parent) = parent {
            Some(&parent.ty)
        } else {
            None
        };

        TemplateInput {
            ast,
            source,
            print,
            escaping: escaping.unwrap_or_else(|| EscapeMode::from_path(&path)),
            ext,
            parent,
            path,
        }
    }
}

pub enum Source {
    Path(String),
    Source(String),
}

#[derive(PartialEq)]
pub enum EscapeMode {
    Html,
    None,
}

impl From<String> for EscapeMode {
    fn from(s: String) -> EscapeMode {
        use self::EscapeMode::*;
        match s.as_ref() {
            "html" => Html,
            "none" => None,
            v => panic!("invalid value for escape option: {}", v),
        }
    }
}

impl EscapeMode {
    fn from_path(path: &PathBuf) -> EscapeMode {
        let extension = path.extension().map(|s| s.to_str().unwrap()).unwrap_or("");
        if HTML_EXTENSIONS.contains(&extension) {
            EscapeMode::Html
        } else {
            EscapeMode::None
        }
    }
}

#[derive(PartialEq)]
pub enum Print {
    All,
    Ast,
    Code,
    None,
}

impl From<String> for Print {
    fn from(s: String) -> Print {
        use self::Print::*;
        match s.as_ref() {
            "all" => All,
            "ast" => Ast,
            "code" => Code,
            "none" => None,
            v => panic!("invalid value for print option: {}", v),
        }
    }
}

const HTML_EXTENSIONS: [&str; 3] = ["html", "htm", "xml"];
<commit_msg>Further simplify code to find parent fields<commit_after>use proc_macro2::TokenStream;

use quote::ToTokens;

use shared::path;

use std::path::PathBuf;

use syn;

pub struct TemplateInput<'a> {
    pub ast: &'a syn::DeriveInput,
    pub source: Source,
    pub print: Print,
    pub escaping: EscapeMode,
    pub ext: Option<String>,
    pub parent: Option<&'a syn::Type>,
    pub path: PathBuf,
}

impl<'a> TemplateInput<'a> {
    pub fn new(ast: &'a syn::DeriveInput) -> TemplateInput<'a> {
        let mut meta = None;
        for attr in &ast.attrs {
            match attr.interpret_meta() {
                Some(m) => if m.name() == "template" {
                    meta = Some(m)
                },
                None => {
                    let mut tokens = TokenStream::new();
                    attr.to_tokens(&mut tokens);
                    panic!("unable to interpret attribute: {}", tokens)
                }
            }
        }

        let meta_list = match meta.expect("no attribute 'template' found") {
            syn::Meta::List(inner) => inner,
            _ => panic!("attribute 'template' has incorrect type"),
        };

        let mut source = None;
        let mut print = Print::None;
        let mut escaping = None;
        let mut ext = None;
        for nm_item in meta_list.nested {
            if let syn::NestedMeta::Meta(ref item) = nm_item {
                if let syn::Meta::NameValue(ref pair) = item {
                    match pair.ident.to_string().as_ref() {
                        "path" => if let syn::Lit::Str(ref s) = pair.lit {
                            if source.is_some() {
                                panic!("must specify 'source' or 'path', not both");
                            }
                            source = Some(Source::Path(s.value()));
                        } else {
                            panic!("template path must be string literal");
                        },
                        "source" => if let syn::Lit::Str(ref s) = pair.lit {
                            if source.is_some() {
                                panic!("must specify 'source' or 'path', not both");
                            }
                            source = Some(Source::Source(s.value()));
                        } else {
                            panic!("template source must be string literal");
                        },
                        "print" => if let syn::Lit::Str(ref s) = pair.lit {
                            print = s.value().into();
                        } else {
                            panic!("print value must be string literal");
                        },
                        "escape" => if let syn::Lit::Str(ref s) = pair.lit {
                            escaping = Some(s.value().into());
                        } else {
                            panic!("escape value must be string literal");
                        },
                        "ext" => if let syn::Lit::Str(ref s) = pair.lit {
                            ext = Some(s.value());
                        } else {
                            panic!("ext value must be string literal");
                        },
                        attr => panic!("unsupported annotation key '{}' found", attr),
                    }
                }
            }
        }

        let source = source.expect("template path or source not found in attributes");
        let path = match (&source, &ext) {
            (&Source::Path(ref path), None) => path::find_template_from_path(path, None),
            (&Source::Source(_), Some(ext)) => PathBuf::from(format!("{}.{}", ast.ident, ext)),
            (&Source::Path(_), Some(_)) => {
                panic!("'ext' attribute cannot be used with 'path' attribute")
            }
            (&Source::Source(_), None) => {
                panic!("must include 'ext' attribute when using 'source' attribute")
            }
        };

        let parent = match ast.data {
            syn::Data::Struct(syn::DataStruct {
                fields: syn::Fields::Named(ref fields),
                ..
            }) => fields
                .named
                .iter()
                .find(|f| f.ident.as_ref().filter(|name| *name == "_parent").is_some())
                .map(|f| &f.ty),
            _ => panic!("derive(Template) only works for struct items"),
        };

        TemplateInput {
            ast,
            source,
            print,
            escaping: escaping.unwrap_or_else(|| EscapeMode::from_path(&path)),
            ext,
            parent,
            path,
        }
    }
}

pub enum Source {
    Path(String),
    Source(String),
}

#[derive(PartialEq)]
pub enum EscapeMode {
    Html,
    None,
}

impl From<String> for EscapeMode {
    fn from(s: String) -> EscapeMode {
        use self::EscapeMode::*;
        match s.as_ref() {
            "html" => Html,
            "none" => None,
            v => panic!("invalid value for escape option: {}", v),
        }
    }
}

impl EscapeMode {
    fn from_path(path: &PathBuf) -> EscapeMode {
        let extension = path.extension().map(|s| s.to_str().unwrap()).unwrap_or("");
        if HTML_EXTENSIONS.contains(&extension) {
            EscapeMode::Html
        } else {
            EscapeMode::None
        }
    }
}

#[derive(PartialEq)]
pub enum Print {
    All,
    Ast,
    Code,
    None,
}

impl From<String> for Print {
    fn from(s: String) -> Print {
        use self::Print::*;
        match s.as_ref() {
            "all" => All,
            "ast" => Ast,
            "code" => Code,
            "none" => None,
            v => panic!("invalid value for print option: {}", v),
        }
    }
}

const HTML_EXTENSIONS: [&str; 3] = ["html", "htm", "xml"];
<|endoftext|>


<commit_before>#[doc(hidden)]
#[macro_export]
macro_rules! __private_serialize {
    () => {
        trait Serialize {
            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
            where
                S: $crate::Serializer;
        }
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __private_deserialize {
    () => {
        trait Deserialize<'de>: Sized {
            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
            where
                D: $crate::Deserializer<'de>;
        }
    };
}

/// Used only by Serde doc tests. Not public API.
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! __serialize_unimplemented {
    ($($func:ident)*) => {
        $(
            __serialize_unimplemented_helper!($func);
        )*
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __serialize_unimplemented_method {
    ($func:ident $(<$t:ident>)* ($($arg:ty),*) -> $ret:ident) => {
        fn $func $(<$t: ?Sized + $crate::Serialize>)* (self $(, _: $arg)*) -> $crate::__private::Result<Self::$ret, Self::Error> {
            unimplemented!()
        }
    };
}

#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! __serialize_unimplemented_helper {
    (bool) => {
        __serialize_unimplemented_method!(serialize_bool(bool) -> Ok);
    };
    (i8) => {
        __serialize_unimplemented_method!(serialize_i8(i8) -> Ok);
    };
    (i16) => {
        __serialize_unimplemented_method!(serialize_i16(i16) -> Ok);
    };
    (i32) => {
        __serialize_unimplemented_method!(serialize_i32(i32) -> Ok);
    };
    (i64) => {
        __serialize_unimplemented_method!(serialize_i64(i64) -> Ok);
    };
    (u8) => {
        __serialize_unimplemented_method!(serialize_u8(u8) -> Ok);
    };
    (u16) => {
        __serialize_unimplemented_method!(serialize_u16(u16) -> Ok);
    };
    (u32) => {
        __serialize_unimplemented_method!(serialize_u32(u32) -> Ok);
    };
    (u64) => {
        __serialize_unimplemented_method!(serialize_u64(u64) -> Ok);
    };
    (f32) => {
        __serialize_unimplemented_method!(serialize_f32(f32) -> Ok);
    };
    (f64) => {
        __serialize_unimplemented_method!(serialize_f64(f64) -> Ok);
    };
    (char) => {
        __serialize_unimplemented_method!(serialize_char(char) -> Ok);
    };
    (str) => {
        __serialize_unimplemented_method!(serialize_str(&str) -> Ok);
    };
    (bytes) => {
        __serialize_unimplemented_method!(serialize_bytes(&[u8]) -> Ok);
    };
    (none) => {
        __serialize_unimplemented_method!(serialize_none() -> Ok);
    };
    (some) => {
        __serialize_unimplemented_method!(serialize_some<T>(&T) -> Ok);
    };
    (unit) => {
        __serialize_unimplemented_method!(serialize_unit() -> Ok);
    };
    (unit_struct) => {
        __serialize_unimplemented_method!(serialize_unit_struct(&str) -> Ok);
    };
    (unit_variant) => {
        __serialize_unimplemented_method!(serialize_unit_variant(&str, u32, &str) -> Ok);
    };
    (newtype_struct) => {
        __serialize_unimplemented_method!(serialize_newtype_struct<T>(&str, &T) -> Ok);
    };
    (newtype_variant) => {
        __serialize_unimplemented_method!(serialize_newtype_variant<T>(&str, u32, &str, &T) -> Ok);
    };
    (seq) => {
        type SerializeSeq = $crate::ser::Impossible<Self::Ok, Self::Error>;
        __serialize_unimplemented_method!(serialize_seq(Option<usize>) -> SerializeSeq);
    };
    (tuple) => {
        type SerializeTuple = $crate::ser::Impossible<Self::Ok, Self::Error>;
        __serialize_unimplemented_method!(serialize_tuple(usize) -> SerializeTuple);
    };
    (tuple_struct) => {
        type SerializeTupleStruct = $crate::ser::Impossible<Self::Ok, Self::Error>;
        __serialize_unimplemented_method!(serialize_tuple_struct(&str, usize) -> SerializeTupleStruct);
    };
    (tuple_variant) => {
        type SerializeTupleVariant = $crate::ser::Impossible<Self::Ok, Self::Error>;
        __serialize_unimplemented_method!(serialize_tuple_variant(&str, u32, &str, usize) -> SerializeTupleVariant);
    };
    (map) => {
        type SerializeMap = $crate::ser::Impossible<Self::Ok, Self::Error>;
        __serialize_unimplemented_method!(serialize_map(Option<usize>) -> SerializeMap);
    };
    (struct) => {
        type SerializeStruct = $crate::ser::Impossible<Self::Ok, Self::Error>;
        __serialize_unimplemented_method!(serialize_struct(&str, usize) -> SerializeStruct);
    };
    (struct_variant) => {
        type SerializeStructVariant = $crate::ser::Impossible<Self::Ok, Self::Error>;
        __serialize_unimplemented_method!(serialize_struct_variant(&str, u32, &str, usize) -> SerializeStructVariant);
    };
}
<commit_msg>Remove unused __private_deserialize macro, originally for doctests<commit_after>#[doc(hidden)]
#[macro_export]
macro_rules! __private_serialize {
    () => {
        trait Serialize {
            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
            where
                S: $crate::Serializer;
        }
    };
}

/// Used only by Serde doc tests. Not public API.
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! __serialize_unimplemented {
    ($($func:ident)*) => {
        $(
            __serialize_unimplemented_helper!($func);
        )*
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __serialize_unimplemented_method {
    ($func:ident $(<$t:ident>)* ($($arg:ty),*) -> $ret:ident) => {
        fn $func $(<$t: ?Sized + $crate::Serialize>)* (self $(, _: $arg)*) -> $crate::__private::Result<Self::$ret, Self::Error> {
            unimplemented!()
        }
    };
}

#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! __serialize_unimplemented_helper {
    (bool) => {
        __serialize_unimplemented_method!(serialize_bool(bool) -> Ok);
    };
    (i8) => {
        __serialize_unimplemented_method!(serialize_i8(i8) -> Ok);
    };
    (i16) => {
        __serialize_unimplemented_method!(serialize_i16(i16) -> Ok);
    };
    (i32) => {
        __serialize_unimplemented_method!(serialize_i32(i32) -> Ok);
    };
    (i64) => {
        __serialize_unimplemented_method!(serialize_i64(i64) -> Ok);
    };
    (u8) => {
        __serialize_unimplemented_method!(serialize_u8(u8) -> Ok);
    };
    (u16) => {
        __serialize_unimplemented_method!(serialize_u16(u16) -> Ok);
    };
    (u32) => {
        __serialize_unimplemented_method!(serialize_u32(u32) -> Ok);
    };
    (u64) => {
        __serialize_unimplemented_method!(serialize_u64(u64) -> Ok);
    };
    (f32) => {
        __serialize_unimplemented_method!(serialize_f32(f32) -> Ok);
    };
    (f64) => {
        __serialize_unimplemented_method!(serialize_f64(f64) -> Ok);
    };
    (char) => {
        __serialize_unimplemented_method!(serialize_char(char) -> Ok);
    };
    (str) => {
        __serialize_unimplemented_method!(serialize_str(&str) -> Ok);
    };
    (bytes) => {
        __serialize_unimplemented_method!(serialize_bytes(&[u8]) -> Ok);
    };
    (none) => {
        __serialize_unimplemented_method!(serialize_none() -> Ok);
    };
    (some) => {
        __serialize_unimplemented_method!(serialize_some<T>(&T) -> Ok);
    };
    (unit) => {
        __serialize_unimplemented_method!(serialize_unit() -> Ok);
    };
    (unit_struct) => {
        __serialize_unimplemented_method!(serialize_unit_struct(&str) -> Ok);
    };
    (unit_variant) => {
        __serialize_unimplemented_method!(serialize_unit_variant(&str, u32, &str) -> Ok);
    };
    (newtype_struct) => {
        __serialize_unimplemented_method!(serialize_newtype_struct<T>(&str, &T) -> Ok);
    };
    (newtype_variant) => {
        __serialize_unimplemented_method!(serialize_newtype_variant<T>(&str, u32, &str, &T) -> Ok);
    };
    (seq) => {
        type SerializeSeq = $crate::ser::Impossible<Self::Ok, Self::Error>;
        __serialize_unimplemented_method!(serialize_seq(Option<usize>) -> SerializeSeq);
    };
    (tuple) => {
        type SerializeTuple = $crate::ser::Impossible<Self::Ok, Self::Error>;
        __serialize_unimplemented_method!(serialize_tuple(usize) -> SerializeTuple);
    };
    (tuple_struct) => {
        type SerializeTupleStruct = $crate::ser::Impossible<Self::Ok, Self::Error>;
        __serialize_unimplemented_method!(serialize_tuple_struct(&str, usize) -> SerializeTupleStruct);
    };
    (tuple_variant) => {
        type SerializeTupleVariant = $crate::ser::Impossible<Self::Ok, Self::Error>;
        __serialize_unimplemented_method!(serialize_tuple_variant(&str, u32, &str, usize) -> SerializeTupleVariant);
    };
    (map) => {
        type SerializeMap = $crate::ser::Impossible<Self::Ok, Self::Error>;
        __serialize_unimplemented_method!(serialize_map(Option<usize>) -> SerializeMap);
    };
    (struct) => {
        type SerializeStruct = $crate::ser::Impossible<Self::Ok, Self::Error>;
        __serialize_unimplemented_method!(serialize_struct(&str, usize) -> SerializeStruct);
    };
    (struct_variant) => {
        type SerializeStructVariant = $crate::ser::Impossible<Self::Ok, Self::Error>;
        __serialize_unimplemented_method!(serialize_struct_variant(&str, u32, &str, usize) -> SerializeStructVariant);
    };
}
<|endoftext|>


<commit_before>use std::fmt;
use std::fmt::{Show, Formatter};
use std::os;
use std::path::Path;
use std::io::process::{Command, ProcessOutput, InheritFd};
use util::{ProcessError, process_error};
use std::collections::HashMap;

#[deriving(Clone,PartialEq)]
pub struct ProcessBuilder {
    program: String,
    args: Vec<String>,
    path: Vec<String>,
    env: HashMap<String, String>,
    cwd: Path
}

impl Show for ProcessBuilder {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        try!(write!(f, "`{}", self.program));

        if self.args.len() > 0 {
            try!(write!(f, " {}", self.args.connect(" ")));
        }

        write!(f, "`")
    }
}

// TODO: Upstream a Windows/Posix branch to Rust proper
static PATH_SEP : &'static str = ":";

impl ProcessBuilder {
    pub fn arg<T: Str>(mut self, arg: T) -> ProcessBuilder {
        self.args.push(arg.as_slice().to_str());
        self
    }

    pub fn args<T: Str>(mut self, arguments: &[T]) -> ProcessBuilder {
        self.args = arguments.iter().map(|a| a.as_slice().to_str()).collect();
        self
    }

    pub fn get_args<'a>(&'a self) -> &'a [String] {
        self.args.as_slice()
    }

    pub fn extra_path(mut self, path: Path) -> ProcessBuilder {
        // For now, just convert to a string, but we should do something better
        self.path.push(path.display().to_str());
        self
    }

    pub fn cwd(mut self, path: Path) -> ProcessBuilder {
        self.cwd = path;
        self
    }

    pub fn env(mut self, key: &str, val: Option<&str>) -> ProcessBuilder {
        match val {
            Some(v) => {
                self.env.insert(key.to_str(), v.to_str());
            },
            None => {
                self.env.remove(&key.to_str());
            }
        }

        self
    }

    // TODO: should InheritFd be hardcoded?
    pub fn exec(&self) -> Result<(), ProcessError> {
        let mut command = self.build_command();
        command
            .env(self.build_env().as_slice())
            .stdout(InheritFd(1))
            .stderr(InheritFd(2));

        let msg = || format!("Could not execute process `{}`",
                             self.debug_string());

        let exit = try!(command.status().map_err(|e|
            process_error(msg(), Some(e), None, None)));

        if exit.success() {
            Ok(())
        } else {
            Err(process_error(msg(), None, Some(&exit), None))
        }
    }

    pub fn exec_with_output(&self) -> Result<ProcessOutput, ProcessError> {
        let mut command = self.build_command();
        command.env(self.build_env().as_slice());

        let msg = || format!("Could not execute process `{}`",
                             self.debug_string());

        let output = try!(command.output().map_err(|e| {
            process_error(msg(), Some(e), None, None)
        }));

        if output.status.success() {
            Ok(output)
        } else {
            Err(process_error(msg(), None, Some(&output.status),
                              Some(&output)))
        }
    }

    pub fn build_command(&self) -> Command {
        let mut command = Command::new(self.program.as_slice());
        command.args(self.args.as_slice()).cwd(&self.cwd);
        command
    }

    fn debug_string(&self) -> String {
        if self.args.len() == 0 {
            self.program.to_str()
        } else {
            format!("{} {}", self.program, self.args.connect(" "))
        }
    }

    fn build_env(&self) -> Vec<(String, String)> {
        let mut ret = Vec::new();

        for (key, val) in self.env.iter() {
            // Skip path
            if key.as_slice() != "PATH" {
                ret.push((key.clone(), val.clone()));
            }
        }

        match self.build_path() {
            Some(path) => ret.push(("PATH".to_str(), path)),
            _ => ()
        }

        ret.as_slice().to_owned()
    }

    fn build_path(&self) -> Option<String> {
        let path = self.path.connect(PATH_SEP);

        match self.env.find_equiv(&("PATH")) {
            Some(existing) => {
                if self.path.is_empty() {
                    Some(existing.clone())
                } else {
                    Some(format!("{}{}{}", existing, PATH_SEP, path))
                }
            },
            None => {
                if self.path.is_empty() {
                    None
                } else {
                    Some(path)
                }
            }
        }
    }
}

pub fn process(cmd: &str) -> ProcessBuilder {
    ProcessBuilder {
        program: cmd.to_str(),
        args: vec!(),
        path: vec!(),
        cwd: os::getcwd(),
        env: system_env()
    }
}

fn system_env() -> HashMap<String, String> {
    let mut ret = HashMap::new();

    for &(ref key, ref val) in os::env().iter() {
        ret.insert(key.to_str(), val.to_str());
    }

    ret
}
<commit_msg>Use correct path separator on windows<commit_after>use std::fmt;
use std::fmt::{Show, Formatter};
use std::os;
use std::path::Path;
use std::io::process::{Command, ProcessOutput, InheritFd};
use util::{ProcessError, process_error};
use std::collections::HashMap;

#[deriving(Clone,PartialEq)]
pub struct ProcessBuilder {
    program: String,
    args: Vec<String>,
    path: Vec<String>,
    env: HashMap<String, String>,
    cwd: Path
}

impl Show for ProcessBuilder {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        try!(write!(f, "`{}", self.program));

        if self.args.len() > 0 {
            try!(write!(f, " {}", self.args.connect(" ")));
        }

        write!(f, "`")
    }
}

// TODO: Upstream a Windows/Posix branch to Rust proper
#[cfg(unix)]
static PATH_SEP : &'static str = ":";
#[cfg(windows)]
static PATH_SEP : &'static str = ";";

impl ProcessBuilder {
    pub fn arg<T: Str>(mut self, arg: T) -> ProcessBuilder {
        self.args.push(arg.as_slice().to_str());
        self
    }

    pub fn args<T: Str>(mut self, arguments: &[T]) -> ProcessBuilder {
        self.args = arguments.iter().map(|a| a.as_slice().to_str()).collect();
        self
    }

    pub fn get_args<'a>(&'a self) -> &'a [String] {
        self.args.as_slice()
    }

    pub fn extra_path(mut self, path: Path) -> ProcessBuilder {
        // For now, just convert to a string, but we should do something better
        self.path.push(path.display().to_str());
        self
    }

    pub fn cwd(mut self, path: Path) -> ProcessBuilder {
        self.cwd = path;
        self
    }

    pub fn env(mut self, key: &str, val: Option<&str>) -> ProcessBuilder {
        match val {
            Some(v) => {
                self.env.insert(key.to_str(), v.to_str());
            },
            None => {
                self.env.remove(&key.to_str());
            }
        }

        self
    }

    // TODO: should InheritFd be hardcoded?
    pub fn exec(&self) -> Result<(), ProcessError> {
        let mut command = self.build_command();
        command
            .env(self.build_env().as_slice())
            .stdout(InheritFd(1))
            .stderr(InheritFd(2));

        let msg = || format!("Could not execute process `{}`",
                             self.debug_string());

        let exit = try!(command.status().map_err(|e|
            process_error(msg(), Some(e), None, None)));

        if exit.success() {
            Ok(())
        } else {
            Err(process_error(msg(), None, Some(&exit), None))
        }
    }

    pub fn exec_with_output(&self) -> Result<ProcessOutput, ProcessError> {
        let mut command = self.build_command();
        command.env(self.build_env().as_slice());

        let msg = || format!("Could not execute process `{}`",
                             self.debug_string());

        let output = try!(command.output().map_err(|e| {
            process_error(msg(), Some(e), None, None)
        }));

        if output.status.success() {
            Ok(output)
        } else {
            Err(process_error(msg(), None, Some(&output.status),
                              Some(&output)))
        }
    }

    pub fn build_command(&self) -> Command {
        let mut command = Command::new(self.program.as_slice());
        command.args(self.args.as_slice()).cwd(&self.cwd);
        command
    }

    fn debug_string(&self) -> String {
        if self.args.len() == 0 {
            self.program.to_str()
        } else {
            format!("{} {}", self.program, self.args.connect(" "))
        }
    }

    fn build_env(&self) -> Vec<(String, String)> {
        let mut ret = Vec::new();

        for (key, val) in self.env.iter() {
            // Skip path
            if key.as_slice() != "PATH" {
                ret.push((key.clone(), val.clone()));
            }
        }

        match self.build_path() {
            Some(path) => ret.push(("PATH".to_str(), path)),
            _ => ()
        }

        ret.as_slice().to_owned()
    }

    fn build_path(&self) -> Option<String> {
        let path = self.path.connect(PATH_SEP);

        match self.env.find_equiv(&("PATH")) {
            Some(existing) => {
                if self.path.is_empty() {
                    Some(existing.clone())
                } else {
                    Some(format!("{}{}{}", existing, PATH_SEP, path))
                }
            },
            None => {
                if self.path.is_empty() {
                    None
                } else {
                    Some(path)
                }
            }
        }
    }
}

pub fn process(cmd: &str) -> ProcessBuilder {
    ProcessBuilder {
        program: cmd.to_str(),
        args: vec!(),
        path: vec!(),
        cwd: os::getcwd(),
        env: system_env()
    }
}

fn system_env() -> HashMap<String, String> {
    let mut ret = HashMap::new();

    for &(ref key, ref val) in os::env().iter() {
        ret.insert(key.to_str(), val.to_str());
    }

    ret
}
<|endoftext|>


<commit_before>use futures::{Async, AsyncSink, Future, Poll};
use futures::stream::Stream;
use futures::sink::Sink;
use state_machine_future::RentToOwn;
use tokio_core::reactor::Handle;
use tokio_retry::{self, Retry};
use tokio_retry::strategy::{FibonacciBackoff, jitter};
use std::io;
use std::error;
use std::time::Duration;
use std::fmt;
use std::collections::VecDeque;

pub type ConnectionError = io::Error;
pub type SessionId = u32;

#[derive(Debug, Clone, PartialEq)]
pub enum Event {
    Connected {
        session_id: SessionId,
    }
}

pub enum Message<Item> {
    Packet {
        session_id: SessionId,
        content: Item,
    },
    Control {
        event: Event,
    }
}

impl <Item> Clone for Message<Item> where Item: Clone {
    fn clone(&self) -> Message<Item> {
        match self {
            &Message::Packet { session_id, ref content } => {
                Message::Packet {
                    session_id: session_id,
                    content: content.clone()
                }
            },
            &Message::Control { ref event } => {
                Message::Control {
                    event: event.clone()
                }
            }
        }
    }
}

impl <Item> fmt::Debug for Message<Item> where Item: fmt::Debug {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Message::Packet { session_id, ref content } => {
                write!(f, "Message::Packet<session_id={:?}, content={:?}>", session_id, content)
            },
            &Message::Control { ref event } => {
                write!(f, "Message::Control<event={:?}>", event)
            }
        }
    }
}

pub trait NewTransport {
    type Future: Future<Item=Self::Transport,Error=Self::Error>;
    type Transport;
    type Error: error::Error + Sync + Send;

    fn new_transport(&self) -> Self::Future;
}

#[derive(StateMachineFuture)]
pub enum Connection<Item, S, K, T, N> where S: Stream<Item=Item,Error=io::Error>, K: Sink<SinkItem=Message<Item>,SinkError=io::Error>, T: Stream<Item=Item,Error=io::Error>+Sink<SinkItem=Item,SinkError=io::Error>, N: NewTransport<Transport=T>+Clone+'static {
    #[state_machine_future(start, transitions(Connecting, Finished, Error))]
    NotConnected {
        handle: Handle,
        stream: S,
        sink: K,
        error_count: u32,
        session_id: u32,
        new_transport: N,
    },

    #[state_machine_future(transitions(NotConnected, Connected, Finished, Error))]
    Connecting {
        handle: Handle,
        stream: S,
        sink: K,
        tcp_future: Box<Future<Item=T,Error=io::Error>>,
        error_count: u32,
        session_id: u32,
        new_transport: N,
    },

    #[state_machine_future(transitions(Connected, NotConnected, Finished, Error))]
    Connected {
        handle: Handle,
        stream: S,
        sink: K,
        tcp: T,
        outbound: Option<Item>,
        outbound_inflight: u32,
        inbound: VecDeque<Message<Item>>,
        inbound_inflight: u32,
        error_count: u32,
        session_id: u32,
        new_transport: N,
    },

    #[state_machine_future(ready)]
    Finished(()),

    #[state_machine_future(error)]
    Error(ConnectionError),
}

impl <Item, S, K, T, N> Connection<Item, S, K, T, N> where S: Stream<Item=Item,Error=io::Error>, K: Sink<SinkItem=Message<Item>,SinkError=io::Error>, T: Stream<Item=Item,Error=io::Error>+Sink<SinkItem=Item,SinkError=io::Error>, N: NewTransport<Transport=T>+Clone+'static {
    pub fn new(handle: Handle, stream: S, sink: K, new_transport: N) -> ConnectionFuture<Item, S, K, T, N> {
        debug!("constructing new connection future");
        Connection::start(handle, stream, sink, 0, 0, new_transport)
    }
}

impl <Item, S, K, T, N> PollConnection<Item, S, K, T, N> for Connection<Item, S, K, T, N> where S: Stream<Item=Item,Error=io::Error>, K: Sink<SinkItem=Message<Item>,SinkError=io::Error>, T: Stream<Item=Item,Error=io::Error>+Sink<SinkItem=Item,SinkError=io::Error>, N: NewTransport<Transport=T>+Clone+'static {
    fn poll_not_connected<'a>(not_connected: &'a mut RentToOwn<'a, NotConnected<Item, S, K, T, N>>) -> Poll<AfterNotConnected<Item, S, K, T, N>, ConnectionError> {
        trace!("not connected");

        let retry_strategy = FibonacciBackoff ::from_millis(1)
            .max_delay(Duration::from_millis(2000))
            .map(jitter);

        let handle = not_connected.handle.clone();
        let new_transport = not_connected.new_transport.clone();

        let tcp_future = Box::new(Retry::spawn(handle, retry_strategy, move || {
            new_transport.new_transport()
        }).map_err(|e| {
            match e {
                tokio_retry::Error::OperationError(e) => io::Error::new(io::ErrorKind::Other, e),
                tokio_retry::Error::TimerError(e) => e,
            }
        })) as (Box<Future<Item=T,Error=io::Error>>);

        let not_connected = not_connected.take();
        Ok(Async::Ready(Connecting {
            handle: not_connected.handle,
            stream: not_connected.stream,
            sink: not_connected.sink,
            tcp_future: tcp_future,
            error_count: not_connected.error_count,
            session_id: not_connected.session_id,
            new_transport: not_connected.new_transport,
        }.into()))
    }

    fn poll_connecting<'a>(connecting: &'a mut RentToOwn<'a, Connecting<Item, S, K, T, N>>) -> Poll<AfterConnecting<Item, S, K, T, N>, ConnectionError> {
        trace!("connecting");

        let tcp = try_ready!(connecting.tcp_future.poll());

        let connecting = connecting.take();
        Ok(Async::Ready(Connected {
            handle: connecting.handle,
            stream: connecting.stream,
            sink: connecting.sink,
            tcp: tcp,
            inbound: VecDeque::new(),
            inbound_inflight: 0,
            outbound: None,
            outbound_inflight: 0,
            error_count: connecting.error_count,
            session_id: connecting.session_id,
            new_transport: connecting.new_transport,
        }.into()))
    }

    fn poll_connected<'a>(connected: &'a mut RentToOwn<'a, Connected<Item, S, K, T, N>>) -> Poll<AfterConnected<Item, S, K, T, N>, ConnectionError> {
        trace!("connected");

        // we make progress if any poll returns Ready
        // if we make progress then we return a state or state change
        // otherwise return NotReady
        let mut progress = false;

        let mut received = connected.inbound.pop_front();
        if received.is_none() && connected.inbound_inflight == 0 {
            received = match connected.tcp.poll() {
                Ok(Async::Ready(Some(msg))) => {
                    trace!("transport received msg");
                    progress = true;
                    Some(Message::Packet{session_id: connected.session_id, content: msg})
                },
                Ok(Async::Ready(None)) => {
                    trace!("transport returned end of stream");

                    let connected = connected.take();

                    return Ok(Async::Ready(NotConnected {
                        handle: connected.handle,
                        stream: connected.stream,
                        sink: connected.sink,
                        error_count: connected.error_count,
                        session_id: connected.session_id + 1,
                        new_transport: connected.new_transport,
                    }.into()));
                },
                Ok(Async::NotReady) => {
                    trace!("transport not ready to read");
                    None
                },
                Err(e) => {
                    trace!("transport read error: {:?}", e);
                    let connected = connected.take();

                    return Ok(Async::Ready(NotConnected {
                        handle: connected.handle,
                        stream: connected.stream,
                        sink: connected.sink,
                        error_count: connected.error_count + 1,
                        session_id: connected.session_id + 1,
                        new_transport: connected.new_transport,
                    }.into()));
                }
            };
        }

        let mut sending = connected.outbound.take();
        if sending.is_none() {
            sending = match try!(connected.stream.poll()) {
                Async::Ready(Some(msg)) => {
                    progress = true;

                    Some(msg)
                },
                Async::Ready(None) => {
                    trace!("stream finished");
                    return Ok(Async::Ready(Finished(()).into()));
                },
                Async::NotReady => {
                    trace!("stream not ready to read");
                    None
                }
            };
        }

        if let Some(sending) = sending {
            match connected.tcp.start_send(sending) {
                Ok(AsyncSink::Ready) => {
                    trace!("transport wrote message");
                    progress = true;
                    connected.outbound_inflight += 1;
                },
                Ok(AsyncSink::NotReady(sending)) => {
                    trace!("tcpstream not ready to write");
                    connected.outbound = Some(sending);
                },
                Err(err) => {
                    trace!("transport write error: {:?}", err);
                    let connected = connected.take();

                    return Ok(Async::Ready(NotConnected {
                        handle: connected.handle,
                        stream: connected.stream,
                        sink: connected.sink,
                        error_count: connected.error_count + 1,
                        session_id: connected.session_id + 1,
                        new_transport: connected.new_transport,
                    }.into()));
                }
            }
        }

        if let Some(msg) = received {
            match try!(connected.sink.start_send(msg)) {
                AsyncSink::Ready => {
                    trace!("sink started send");
                    progress = true;
                    connected.inbound_inflight += 1;
                },
                AsyncSink::NotReady(msg) => {
                    trace!("sink not ready");
                    connected.inbound.insert(0, msg);
                },
            }
        }

        if connected.inbound_inflight != 0 {
            match try!(connected.sink.poll_complete()) {
                Async::Ready(()) => {
                    trace!("sink polled complete");
                    progress = true;
                    connected.inbound_inflight = 0;
                },
                Async::NotReady => {
                    trace!("sink polled not ready");
                    // do nothing
                }
            }
        }

        if connected.outbound_inflight != 0 {
            match try!(connected.tcp.poll_complete()) {
                Async::Ready(()) => {
                    trace!("transport poll complete");
                    progress = true;
                    connected.outbound_inflight = 0;
                },
                Async::NotReady => {
                    trace!("transport sink polled not ready");
                    // do nothing
                }
            }
        }

        if progress {
            trace!("made progress");

            let connected = connected.take();

            return Ok(Async::Ready(Connected {
                handle: connected.handle,
                stream: connected.stream,
                sink: connected.sink,
                tcp: connected.tcp,
                inbound: connected.inbound,
                inbound_inflight: connected.inbound_inflight,
                outbound: connected.outbound,
                outbound_inflight: connected.outbound_inflight,
                error_count: connected.error_count,
                session_id: connected.session_id,
                new_transport: connected.new_transport,
            }.into()));
        } else {
            trace!("did not make progress");

            return Ok(Async::NotReady);
        }
    }
}
<commit_msg>send connected event message when new connection is established<commit_after>use futures::{Async, AsyncSink, Future, Poll};
use futures::stream::Stream;
use futures::sink::Sink;
use state_machine_future::RentToOwn;
use tokio_core::reactor::Handle;
use tokio_retry::{self, Retry};
use tokio_retry::strategy::{FibonacciBackoff, jitter};
use std::io;
use std::error;
use std::time::Duration;
use std::fmt;
use std::collections::VecDeque;

pub type ConnectionError = io::Error;
pub type SessionId = u32;

#[derive(Debug, Clone, PartialEq)]
pub enum Event {
    Connected {
        session_id: SessionId,
    }
}

pub enum Message<Item> {
    Packet {
        session_id: SessionId,
        content: Item,
    },
    Control {
        event: Event,
    }
}

impl <Item> Clone for Message<Item> where Item: Clone {
    fn clone(&self) -> Message<Item> {
        match self {
            &Message::Packet { session_id, ref content } => {
                Message::Packet {
                    session_id: session_id,
                    content: content.clone()
                }
            },
            &Message::Control { ref event } => {
                Message::Control {
                    event: event.clone()
                }
            }
        }
    }
}

impl <Item> fmt::Debug for Message<Item> where Item: fmt::Debug {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Message::Packet { session_id, ref content } => {
                write!(f, "Message::Packet<session_id={:?}, content={:?}>", session_id, content)
            },
            &Message::Control { ref event } => {
                write!(f, "Message::Control<event={:?}>", event)
            }
        }
    }
}

pub trait NewTransport {
    type Future: Future<Item=Self::Transport,Error=Self::Error>;
    type Transport;
    type Error: error::Error + Sync + Send;

    fn new_transport(&self) -> Self::Future;
}

#[derive(StateMachineFuture)]
pub enum Connection<Item, S, K, T, N> where S: Stream<Item=Item,Error=io::Error>, K: Sink<SinkItem=Message<Item>,SinkError=io::Error>, T: Stream<Item=Item,Error=io::Error>+Sink<SinkItem=Item,SinkError=io::Error>, N: NewTransport<Transport=T>+Clone+'static {
    #[state_machine_future(start, transitions(Connecting, Finished, Error))]
    NotConnected {
        handle: Handle,
        stream: S,
        sink: K,
        error_count: u32,
        session_id: u32,
        new_transport: N,
    },

    #[state_machine_future(transitions(NotConnected, Connected, Finished, Error))]
    Connecting {
        handle: Handle,
        stream: S,
        sink: K,
        tcp_future: Box<Future<Item=T,Error=io::Error>>,
        error_count: u32,
        session_id: u32,
        new_transport: N,
    },

    #[state_machine_future(transitions(Connected, NotConnected, Finished, Error))]
    Connected {
        handle: Handle,
        stream: S,
        sink: K,
        tcp: T,
        outbound: Option<Item>,
        outbound_inflight: u32,
        inbound: VecDeque<Message<Item>>,
        inbound_inflight: u32,
        error_count: u32,
        session_id: u32,
        new_transport: N,
    },

    #[state_machine_future(ready)]
    Finished(()),

    #[state_machine_future(error)]
    Error(ConnectionError),
}

impl <Item, S, K, T, N> Connection<Item, S, K, T, N> where S: Stream<Item=Item,Error=io::Error>, K: Sink<SinkItem=Message<Item>,SinkError=io::Error>, T: Stream<Item=Item,Error=io::Error>+Sink<SinkItem=Item,SinkError=io::Error>, N: NewTransport<Transport=T>+Clone+'static {
    pub fn new(handle: Handle, stream: S, sink: K, new_transport: N) -> ConnectionFuture<Item, S, K, T, N> {
        debug!("constructing new connection future");
        Connection::start(handle, stream, sink, 0, 0, new_transport)
    }
}

impl <Item, S, K, T, N> PollConnection<Item, S, K, T, N> for Connection<Item, S, K, T, N> where S: Stream<Item=Item,Error=io::Error>, K: Sink<SinkItem=Message<Item>,SinkError=io::Error>, T: Stream<Item=Item,Error=io::Error>+Sink<SinkItem=Item,SinkError=io::Error>, N: NewTransport<Transport=T>+Clone+'static {
    fn poll_not_connected<'a>(not_connected: &'a mut RentToOwn<'a, NotConnected<Item, S, K, T, N>>) -> Poll<AfterNotConnected<Item, S, K, T, N>, ConnectionError> {
        trace!("not connected");

        let retry_strategy = FibonacciBackoff ::from_millis(1)
            .max_delay(Duration::from_millis(2000))
            .map(jitter);

        let handle = not_connected.handle.clone();
        let new_transport = not_connected.new_transport.clone();

        let tcp_future = Box::new(Retry::spawn(handle, retry_strategy, move || {
            new_transport.new_transport()
        }).map_err(|e| {
            match e {
                tokio_retry::Error::OperationError(e) => io::Error::new(io::ErrorKind::Other, e),
                tokio_retry::Error::TimerError(e) => e,
            }
        })) as (Box<Future<Item=T,Error=io::Error>>);

        let not_connected = not_connected.take();
        Ok(Async::Ready(Connecting {
            handle: not_connected.handle,
            stream: not_connected.stream,
            sink: not_connected.sink,
            tcp_future: tcp_future,
            error_count: not_connected.error_count,
            session_id: not_connected.session_id,
            new_transport: not_connected.new_transport,
        }.into()))
    }

    fn poll_connecting<'a>(connecting: &'a mut RentToOwn<'a, Connecting<Item, S, K, T, N>>) -> Poll<AfterConnecting<Item, S, K, T, N>, ConnectionError> {
        trace!("connecting");

        let tcp = try_ready!(connecting.tcp_future.poll());

        let connecting = connecting.take();
        Ok(Async::Ready(Connected {
            handle: connecting.handle,
            stream: connecting.stream,
            sink: connecting.sink,
            tcp: tcp,
            inbound: VecDeque::from(vec![
                Message::Control {
                    event: Event::Connected {
                        session_id: connecting.session_id
                    }
                }
            ]),
            inbound_inflight: 0,
            outbound: None,
            outbound_inflight: 0,
            error_count: connecting.error_count,
            session_id: connecting.session_id,
            new_transport: connecting.new_transport,
        }.into()))
    }

    fn poll_connected<'a>(connected: &'a mut RentToOwn<'a, Connected<Item, S, K, T, N>>) -> Poll<AfterConnected<Item, S, K, T, N>, ConnectionError> {
        trace!("connected");

        // we make progress if any poll returns Ready
        // if we make progress then we return a state or state change
        // otherwise return NotReady
        let mut progress = false;

        let mut received = connected.inbound.pop_front();
        if received.is_none() && connected.inbound_inflight == 0 {
            received = match connected.tcp.poll() {
                Ok(Async::Ready(Some(msg))) => {
                    trace!("transport received msg");
                    progress = true;
                    Some(Message::Packet{session_id: connected.session_id, content: msg})
                },
                Ok(Async::Ready(None)) => {
                    trace!("transport returned end of stream");

                    let connected = connected.take();

                    return Ok(Async::Ready(NotConnected {
                        handle: connected.handle,
                        stream: connected.stream,
                        sink: connected.sink,
                        error_count: connected.error_count,
                        session_id: connected.session_id + 1,
                        new_transport: connected.new_transport,
                    }.into()));
                },
                Ok(Async::NotReady) => {
                    trace!("transport not ready to read");
                    None
                },
                Err(e) => {
                    trace!("transport read error: {:?}", e);
                    let connected = connected.take();

                    return Ok(Async::Ready(NotConnected {
                        handle: connected.handle,
                        stream: connected.stream,
                        sink: connected.sink,
                        error_count: connected.error_count + 1,
                        session_id: connected.session_id + 1,
                        new_transport: connected.new_transport,
                    }.into()));
                }
            };
        }

        let mut sending = connected.outbound.take();
        if sending.is_none() {
            sending = match try!(connected.stream.poll()) {
                Async::Ready(Some(msg)) => {
                    progress = true;

                    Some(msg)
                },
                Async::Ready(None) => {
                    trace!("stream finished");
                    return Ok(Async::Ready(Finished(()).into()));
                },
                Async::NotReady => {
                    trace!("stream not ready to read");
                    None
                }
            };
        }

        if let Some(sending) = sending {
            match connected.tcp.start_send(sending) {
                Ok(AsyncSink::Ready) => {
                    trace!("transport wrote message");
                    progress = true;
                    connected.outbound_inflight += 1;
                },
                Ok(AsyncSink::NotReady(sending)) => {
                    trace!("tcpstream not ready to write");
                    connected.outbound = Some(sending);
                },
                Err(err) => {
                    trace!("transport write error: {:?}", err);
                    let connected = connected.take();

                    return Ok(Async::Ready(NotConnected {
                        handle: connected.handle,
                        stream: connected.stream,
                        sink: connected.sink,
                        error_count: connected.error_count + 1,
                        session_id: connected.session_id + 1,
                        new_transport: connected.new_transport,
                    }.into()));
                }
            }
        }

        if let Some(msg) = received {
            match try!(connected.sink.start_send(msg)) {
                AsyncSink::Ready => {
                    trace!("sink started send");
                    progress = true;
                    connected.inbound_inflight += 1;
                },
                AsyncSink::NotReady(msg) => {
                    trace!("sink not ready");
                    connected.inbound.insert(0, msg);
                },
            }
        }

        if connected.inbound_inflight != 0 {
            match try!(connected.sink.poll_complete()) {
                Async::Ready(()) => {
                    trace!("sink polled complete");
                    progress = true;
                    connected.inbound_inflight = 0;
                },
                Async::NotReady => {
                    trace!("sink polled not ready");
                    // do nothing
                }
            }
        }

        if connected.outbound_inflight != 0 {
            match try!(connected.tcp.poll_complete()) {
                Async::Ready(()) => {
                    trace!("transport poll complete");
                    progress = true;
                    connected.outbound_inflight = 0;
                },
                Async::NotReady => {
                    trace!("transport sink polled not ready");
                    // do nothing
                }
            }
        }

        if progress {
            trace!("made progress");

            let connected = connected.take();

            return Ok(Async::Ready(Connected {
                handle: connected.handle,
                stream: connected.stream,
                sink: connected.sink,
                tcp: connected.tcp,
                inbound: connected.inbound,
                inbound_inflight: connected.inbound_inflight,
                outbound: connected.outbound,
                outbound_inflight: connected.outbound_inflight,
                error_count: connected.error_count,
                session_id: connected.session_id,
                new_transport: connected.new_transport,
            }.into()));
        } else {
            trace!("did not make progress");

            return Ok(Async::NotReady);
        }
    }
}
<|endoftext|>


<commit_before>//! Sprite rendering

use super::{Ppu, Rgb};

use arrayvec::ArrayVec;
use std::mem::replace;

/// Render state stored inside the `Ppu`. We use this to cache the visible sprites for each
/// scanline, just like the real PPU would.
#[derive(Default)]
pub struct SpriteRenderState {
    /// Contains up to 34 `SpriteTile`s that are visible on the current scanline
    visible_sprite_tiles: Vec<SpriteTile>,
}

/// Unpacked OAM entry for internal use.
struct OamEntry {
    /// First tile (0-255), needs to take name table selection bit into account
    tile: u8,
    /// Sprite's name table (0 or 1).
    name_table: u8,
    /// 9 bits, considered signed (-256 - 255)
    x: i16,
    y: u8,
    /// 0-3
    priority: u8,
    /// 0-7. The first palette entry is `128+ppp*16`.
    palette: u8,
    #[allow(dead_code)] // FIXME
    hflip: bool,
    #[allow(dead_code)]
    vflip: bool,
    size_toggle: bool,
}

/// Informations about a single tile of a sprite, needed for drawing.
struct SpriteTile {
    /// Address of character data for this tile
    chr_addr: u16,
    /// X position of the tile on the screen.
    x: i16,
    /// Y position of the scanline inside the tile (0-7)
    /// FIXME Can we just store the pixel row that's on the scanline? (for each priority)
    y_off: u8,
    /// Priority of the sprite (0-3)
    priority: u8,
    /// Palette of the sprite (0-7)
    palette: u8,

    // FIXME hflip/vflip
}

impl Ppu {
    /// Returns the OAM entry of the given sprite. Always returns a valid entry if `index` is valid
    /// (0...127), panics otherwise.
    fn get_oam_entry(&self, index: u8) -> OamEntry {
        debug_assert!(index <= 127, "attempted to access sprite #{}", index);

        // FIXME Is this correct?
        let start = index as u16 * 4;
        let mut x = self.oam[start] as u16;

        // vhoopppN
        let byte4 = self.oam[start + 3];
        let vflip = byte4 & 0x80 != 0;
        let hflip = byte4 & 0x40 != 0;
        let priority = (byte4 & 0x30) >> 4;
        let palette = (byte4 & 0x0e) >> 1;

        // Read the second table. Each byte contains information of 4 sprites (2 bits per sprite):
        // Bits 1/3/5/6 is the size-toggle bit, bits 0/2/4/6 is the MSb of the x coord
        let byte = self.oam[512 + index as u16 / 4];
        let index_in_byte = index & 0b11;
        let msb_mask = 1 << (index_in_byte * 2);
        let size_mask = 2 << (index_in_byte * 2);
        let size_toggle = byte & size_mask != 0;
        if byte & msb_mask != 0 {
            // MSb of `x` is set, so `x` is negative. Since `x` is a signed 9-bit value, we have to
            // sign-extend it to 16 bits by setting all bits starting from the MSb to 1.
            x = 0xfff0 | x;
        }

        OamEntry {
            tile: self.oam[start + 2],
            name_table: byte4 & 1,
            x: x as i16,
            y: self.oam[start + 1],
            priority: priority,
            palette: palette,
            hflip: hflip,
            vflip: vflip,
            size_toggle: size_toggle,
        }
    }

    pub fn collect_sprite_data_for_scanline(&mut self) {
        let first_sprite = if self.oamaddh & 0x80 == 0 {
            0
        } else {
            // Priority rotation enabled
            (self.oamaddl as u16 & 0xfe) >> 1
        };

        // Find the first 32 sprites on the current scanline
        // NB Priority is ignored for this step, it's only used for drawing, which isn't done here
        let mut visible_sprites = ArrayVec::<[_; 32]>::new();
        for i in first_sprite..first_sprite+128 {
            let entry = self.get_oam_entry((i & 0x7f) as u8);   // limit to 127
            if self.sprite_on_scanline(&entry) {
                if let Some(_) = visible_sprites.push(entry) {
                    // FIXME: Sprite overflow. Set bit 6 of $213e.
                    break
                }
            }
        }

        // "Starting with the last sprite in Range, load up to 34 8x8 tiles (from left-to-right,
        // after flipping). If there are more than 34 tiles in Range, set bit 7 of $213e. Only
        // those tiles with -8 < X < 256 are counted."
        // A few notes:
        // * Sprite tiles are always 8x8 pixels
        // * Sprites do not have tile maps like BGs do
        // * "left-to-right" refers to how tiles of sprites are loaded, not the sprite order
        // * Tiles are loaded iff they are on the current scanline (and have `-8 < X < 256`)
        // FIXME Is this ^^ correct?

        // FIXME Use `ArrayVec<[_; 34]>` when it works
        let mut visible_tiles = replace(&mut self.sprite_render_state.visible_sprite_tiles, Vec::new());
        visible_tiles.clear();

        // Word address of first sprite character table
        let name_base: u16 = (self.obsel as u16 & 0b111) << 13;
        let name_select: u16 = (self.obsel as u16 >> 3) & 0b11;

        // Start at the last sprite found
        'collect_tiles: for sprite in visible_sprites.iter().rev() {
            // How many tiles are there?
            let (sprite_w, _) = self.obj_size(sprite.size_toggle);
            let sprite_w_tiles = sprite_w / 8;
            // Offset into the sprite
            let sprite_y_off = self.scanline - sprite.y as u16;
            // Tile Y coordinate of the tile row we're interested in (tiles on the scanline)
            let y_tile = sprite_y_off / 8;
            // Y offset into the tile row
            let tile_y_off = (sprite_y_off % 8) as u8;

            // Calculate VRAM word address of first tile. Depends on base/name bits in `$2101`.
            let tile_start_word_addr =
                (name_base |
                ((sprite.tile as u16) << 4) |
                (sprite.name_table as u16 * ((name_select + 1) << 12))) & 0x7fff;
            let tile_start_addr = tile_start_word_addr * 2;

            // The character data for the first tile is stored at `tile_start_addr`, in the same
            // format as BG character data (bitplanes, etc.). Keep in mind that sprites do not have
            // tilemaps.
            // One 8x8 tile is 32 Bytes large (4 bits per pixel).
            // Tiles in a single (8 pixel high) row of the sprite are stored sequentially: Tile
            // coord (1,0) is stored directly behind (0,0), which is stored at `tile_start_addr`.
            // Rows of tiles, however, are always stored 512 Bytes (or 16 tiles/128 pixels) apart:
            // If tile (0,0) is at address $0000, tile (0,1) is at $0200. This is independent of
            // the sprite size, which means that there are "holes" in the sprite character data,
            // which are used to store the data of other sprites.

            // Start address of the row of tiles on the scanline
            let y_row_start_addr = tile_start_addr.wrapping_add(512 * y_tile);

            // FIXME "Only those tiles with -8 < X < 256 are counted."
            // Add all tiles in this row to our tile list (left to right)
            for i in 0..sprite_w_tiles as i16 {
                if visible_tiles.len() < 34 {
                    visible_tiles.push(SpriteTile {
                        chr_addr: y_row_start_addr + 32 * i as u16,
                        x: sprite.x + 8 * i,
                        y_off: tile_y_off,
                        priority: sprite.priority,
                        palette: sprite.palette,
                    });
                } else {
                    // FIXME Set sprite tile overflow flag
                    break 'collect_tiles
                }
            }
        }

        self.sprite_render_state.visible_sprite_tiles = visible_tiles;
    }

    /// Determines if the given sprite has any tiles on the current scanline
    fn sprite_on_scanline(&self, sprite: &OamEntry) -> bool {
        let (w, h) = self.obj_size(sprite.size_toggle);
        let (w, h) = (w as i16, h as u16);

        // "If any OBJ is at X=256 (or X=-256, same difference), consider it as being at X=0 when
        // considering Range and Time."
        // X=256 can not occur, since X is a signed 9-bit value (range is -256 - 255)
        let x = if sprite.x == -256 { 0 } else { sprite.x };
        let y = sprite.y as u16;

        // "Only those sprites with -size < X < 256 are considered in Range." (`size` is `w` here)
        // We don't check `X < 256`, since that cannot occur (X is a signed 9-bit integer)
        // A sprite moved past the right edge of the screen will wrap to `-256`, which is handled
        // by this check.
        if -w < x {
            if y <= self.scanline && y + h >= self.scanline {
                // Sprite is on scanline
                true
            } else {
                false
            }
        } else {
            false
        }
    }

    pub fn maybe_draw_sprite_pixel(&self, prio: u8) -> Option<Rgb> {
        if self.tm & 0x10 == 0 { return None }  // OBJ layer disabled

        for tile in &self.sprite_render_state.visible_sprite_tiles {
            if tile.priority == prio {
                // The tile must be on this scanline, we just have to check X
                if tile.x <= self.x as i16 && tile.x + 8 > self.x as i16 {
                    let x_offset = self.x as i16 - tile.x;
                    debug_assert!(0 <= x_offset && x_offset <= 7, "x_offset = {}", x_offset);
                    let rel_color = self.read_chr_entry(4,  // 16 colors
                                                        tile.chr_addr,
                                                        8,  // 8x8 tiles
                                                        (x_offset as u8, tile.y_off));
                    debug_assert!(rel_color < 16, "rel_color = {} (but is 4-bit!)", rel_color);

                    // color index 0 is always transparent
                    if rel_color == 0 { return None }

                    let abs_color = 128 + tile.palette * 16 + rel_color;
                    // FIXME Color math
                    let rgb = self.lookup_color(abs_color);
                    return Some(rgb)
                }
            }
        }

        None
    }
}
<commit_msg>Fix sign extension of sprite's X coordinate<commit_after>//! Sprite rendering

use super::{Ppu, Rgb};

use arrayvec::ArrayVec;
use std::mem::replace;

/// Render state stored inside the `Ppu`. We use this to cache the visible sprites for each
/// scanline, just like the real PPU would.
#[derive(Default)]
pub struct SpriteRenderState {
    /// Contains up to 34 `SpriteTile`s that are visible on the current scanline
    visible_sprite_tiles: Vec<SpriteTile>,
}

/// Unpacked OAM entry for internal use.
struct OamEntry {
    /// First tile (0-255), needs to take name table selection bit into account
    tile: u8,
    /// Sprite's name table (0 or 1).
    name_table: u8,
    /// 9 bits, considered signed (-256 - 255)
    x: i16,
    y: u8,
    /// 0-3
    priority: u8,
    /// 0-7. The first palette entry is `128+ppp*16`.
    palette: u8,
    #[allow(dead_code)] // FIXME
    hflip: bool,
    #[allow(dead_code)]
    vflip: bool,
    size_toggle: bool,
}

/// Informations about a single tile of a sprite, needed for drawing.
struct SpriteTile {
    /// Address of character data for this tile
    chr_addr: u16,
    /// X position of the tile on the screen.
    x: i16,
    /// Y position of the scanline inside the tile (0-7)
    /// FIXME Can we just store the pixel row that's on the scanline? (for each priority)
    y_off: u8,
    /// Priority of the sprite (0-3)
    priority: u8,
    /// Palette of the sprite (0-7)
    palette: u8,

    // FIXME hflip/vflip
}

impl Ppu {
    /// Returns the OAM entry of the given sprite. Always returns a valid entry if `index` is valid
    /// (0...127), panics otherwise.
    fn get_oam_entry(&self, index: u8) -> OamEntry {
        debug_assert!(index <= 127, "attempted to access sprite #{}", index);

        // OAM entry start address (low table)
        let start = index as u16 * 4;
        let mut x = self.oam[start] as u16;

        // vhoopppN
        let byte4 = self.oam[start + 3];
        let vflip = byte4 & 0x80 != 0;
        let hflip = byte4 & 0x40 != 0;
        let priority = (byte4 & 0x30) >> 4;
        let palette = (byte4 & 0x0e) >> 1;

        // Read the second table. Each byte contains information of 4 sprites (2 bits per sprite):
        // Bits 1/3/5/6 is the size-toggle bit, bits 0/2/4/6 is the MSb of the x coord
        let byte = self.oam[512 + index as u16 / 4];
        let index_in_byte = index & 0b11;
        let msb_mask = 1 << (index_in_byte * 2);
        let size_mask = 2 << (index_in_byte * 2);
        let size_toggle = byte & size_mask != 0;
        if byte & msb_mask != 0 {
            // MSb of `x` is set, so `x` is negative. Since `x` is a signed 9-bit value, we have to
            // sign-extend it to 16 bits by setting all bits starting from the MSb to 1.
            x = 0xff00 | x;
        }

        OamEntry {
            tile: self.oam[start + 2],
            name_table: byte4 & 1,
            x: x as i16,
            y: self.oam[start + 1],
            priority: priority,
            palette: palette,
            hflip: hflip,
            vflip: vflip,
            size_toggle: size_toggle,
        }
    }

    pub fn collect_sprite_data_for_scanline(&mut self) {
        let first_sprite = if self.oamaddh & 0x80 == 0 {
            0
        } else {
            // Priority rotation enabled
            (self.oamaddl as u16 & 0xfe) >> 1
        };

        // Find the first 32 sprites on the current scanline
        // NB Priority is ignored for this step, it's only used for drawing, which isn't done here
        let mut visible_sprites = ArrayVec::<[_; 32]>::new();
        for i in first_sprite..first_sprite+128 {
            let entry = self.get_oam_entry((i & 0x7f) as u8);   // limit to 127
            if self.sprite_on_scanline(&entry) {
                if let Some(_) = visible_sprites.push(entry) {
                    // FIXME: Sprite overflow. Set bit 6 of $213e.
                    break
                }
            }
        }

        // "Starting with the last sprite in Range, load up to 34 8x8 tiles (from left-to-right,
        // after flipping). If there are more than 34 tiles in Range, set bit 7 of $213e. Only
        // those tiles with -8 < X < 256 are counted."
        // A few notes:
        // * Sprite tiles are always 8x8 pixels
        // * Sprites do not have tile maps like BGs do
        // * "left-to-right" refers to how tiles of sprites are loaded, not the sprite order
        // * Tiles are loaded iff they are on the current scanline (and have `-8 < X < 256`)
        // FIXME Is this ^^ correct?

        // FIXME Use `ArrayVec<[_; 34]>` when it works
        let mut visible_tiles = replace(&mut self.sprite_render_state.visible_sprite_tiles, Vec::new());
        visible_tiles.clear();

        // Word address of first sprite character table
        let name_base: u16 = (self.obsel as u16 & 0b111) << 13;
        let name_select: u16 = (self.obsel as u16 >> 3) & 0b11;

        // Start at the last sprite found
        'collect_tiles: for sprite in visible_sprites.iter().rev() {
            // How many tiles are there?
            let (sprite_w, _) = self.obj_size(sprite.size_toggle);
            let sprite_w_tiles = sprite_w / 8;
            // Offset into the sprite
            let sprite_y_off = self.scanline - sprite.y as u16;
            // Tile Y coordinate of the tile row we're interested in (tiles on the scanline)
            let y_tile = sprite_y_off / 8;
            // Y offset into the tile row
            let tile_y_off = (sprite_y_off % 8) as u8;

            // Calculate VRAM word address of first tile. Depends on base/name bits in `$2101`.
            let tile_start_word_addr =
                (name_base |
                ((sprite.tile as u16) << 4) |
                (sprite.name_table as u16 * ((name_select + 1) << 12))) & 0x7fff;
            let tile_start_addr = tile_start_word_addr * 2;

            // The character data for the first tile is stored at `tile_start_addr`, in the same
            // format as BG character data (bitplanes, etc.). Keep in mind that sprites do not have
            // tilemaps.
            // One 8x8 tile is 32 Bytes large (4 bits per pixel).
            // Tiles in a single (8 pixel high) row of the sprite are stored sequentially: Tile
            // coord (1,0) is stored directly behind (0,0), which is stored at `tile_start_addr`.
            // Rows of tiles, however, are always stored 512 Bytes (or 16 tiles/128 pixels) apart:
            // If tile (0,0) is at address $0000, tile (0,1) is at $0200. This is independent of
            // the sprite size, which means that there are "holes" in the sprite character data,
            // which are used to store the data of other sprites.

            // Start address of the row of tiles on the scanline
            let y_row_start_addr = tile_start_addr.wrapping_add(512 * y_tile);

            // FIXME "Only those tiles with -8 < X < 256 are counted."
            // Add all tiles in this row to our tile list (left to right)
            for i in 0..sprite_w_tiles as i16 {
                if visible_tiles.len() < 34 {
                    visible_tiles.push(SpriteTile {
                        chr_addr: y_row_start_addr + 32 * i as u16,
                        x: sprite.x + 8 * i,
                        y_off: tile_y_off,
                        priority: sprite.priority,
                        palette: sprite.palette,
                    });
                } else {
                    // FIXME Set sprite tile overflow flag
                    break 'collect_tiles
                }
            }
        }

        self.sprite_render_state.visible_sprite_tiles = visible_tiles;
    }

    /// Determines if the given sprite has any tiles on the current scanline
    fn sprite_on_scanline(&self, sprite: &OamEntry) -> bool {
        let (w, h) = self.obj_size(sprite.size_toggle);
        let (w, h) = (w as i16, h as u16);

        // "If any OBJ is at X=256 (or X=-256, same difference), consider it as being at X=0 when
        // considering Range and Time."
        // X=256 can not occur, since X is a signed 9-bit value (range is -256 - 255)
        let x = if sprite.x == -256 { 0 } else { sprite.x };
        let y = sprite.y as u16;

        // "Only those sprites with -size < X < 256 are considered in Range." (`size` is `w` here)
        // We don't check `X < 256`, since that cannot occur (X is a signed 9-bit integer)
        // A sprite moved past the right edge of the screen will wrap to `-256`, which is handled
        // by this check.
        if -w < x {
            if y <= self.scanline && y + h >= self.scanline {
                // Sprite is on scanline
                true
            } else {
                false
            }
        } else {
            false
        }
    }

    pub fn maybe_draw_sprite_pixel(&self, prio: u8) -> Option<Rgb> {
        if self.tm & 0x10 == 0 { return None }  // OBJ layer disabled

        for tile in &self.sprite_render_state.visible_sprite_tiles {
            if tile.priority == prio {
                // The tile must be on this scanline, we just have to check X
                if tile.x <= self.x as i16 && tile.x + 8 > self.x as i16 {
                    let x_offset = self.x as i16 - tile.x;
                    debug_assert!(0 <= x_offset && x_offset <= 7, "x_offset = {}", x_offset);
                    let rel_color = self.read_chr_entry(4,  // 16 colors
                                                        tile.chr_addr,
                                                        8,  // 8x8 tiles
                                                        (x_offset as u8, tile.y_off));
                    debug_assert!(rel_color < 16, "rel_color = {} (but is 4-bit!)", rel_color);

                    // color index 0 is always transparent
                    if rel_color == 0 { return None }

                    let abs_color = 128 + tile.palette * 16 + rel_color;
                    // FIXME Color math
                    let rgb = self.lookup_color(abs_color);
                    return Some(rgb)
                }
            }
        }

        None
    }
}
<|endoftext|>


<commit_before>use core::slice;

/// Internal enum mapping type
///
/// This trait is internally used by `#[derive(EnumMap)]`. Despite it being
/// a public trait, it's not intended to be public. `Internal<T>` is
/// implemented by any enum type where V is a generic type representing a
/// value. The purpose of this generic type is to allow providing a value
/// type for arrays, as Rust currently does not support higher kinded types.
/// Users aren't expected to use this trait directly, but rather to use
/// `EnumMap<K, V>` which uses this internally.
///
/// This trait is also implemented by `bool`, `u8` and `Option` type. While `u8` is
/// strictly speaking not an actual enum, there are good reasons to consider
/// it like one, as array of `u8` keys is a relatively common pattern.
pub trait Internal<V>: Sized {
    /// Representation of an enum map for type `V`, usually an array.
    type Array;
    #[doc(hidden)]
    fn slice(&Self::Array) -> &[V];
    #[doc(hidden)]
    fn slice_mut(&mut Self::Array) -> &mut [V];
    #[doc(hidden)]
    fn from_usize(usize) -> Self;
    #[doc(hidden)]
    fn to_usize(self) -> usize;
    #[doc(hidden)]
    fn from_function<F: FnMut(Self) -> V>(F) -> Self::Array;
}

impl<T> Internal<T> for bool {
    type Array = [T; 2];
    fn slice(array: &[T; 2]) -> &[T] {
        array
    }
    fn slice_mut(array: &mut [T; 2]) -> &mut [T] {
        array
    }
    fn from_usize(value: usize) -> Self {
        match value {
            0 => false,
            1 => true,
            _ => unreachable!(),
        }
    }
    fn to_usize(self) -> usize {
        self as usize
    }
    fn from_function<F: FnMut(Self) -> T>(mut f: F) -> [T; 2] {
        [f(false), f(true)]
    }
}

impl<T> Internal<T> for u8 {
    type Array = [T; 256];
    fn slice(array: &[T; 256]) -> &[T] {
        array
    }
    fn slice_mut(array: &mut [T; 256]) -> &mut [T] {
        array
    }
    fn from_usize(value: usize) -> Self {
        value as u8
    }
    fn to_usize(self) -> usize {
        self as usize
    }
    fn from_function<F: FnMut(Self) -> T>(mut f: F) -> [T; 256] {
        array![|i| f(i); 256]
    }
}

#[repr(C)]
pub struct OptionInternal<T, U> {
    none: T,
    some: U,
}

impl<T, U: Internal<T>> Internal<T> for Option<U> {
    type Array = OptionInternal<T, U::Array>;
    fn slice(array: &Self::Array) -> &[T] {
        unsafe {
            slice::from_raw_parts(
                array as *const _ as *const T,
                1 + U::slice(&array.some).len(),
            )
        }
    }
    fn slice_mut(array: &mut Self::Array) -> &mut [T] {
        unsafe {
            slice::from_raw_parts_mut(array as *mut _ as *mut T, 1 + U::slice(&array.some).len())
        }
    }
    fn from_usize(value: usize) -> Self {
        match value {
            0 => None,
            v => Some(U::from_usize(v - 1)),
        }
    }
    fn to_usize(self) -> usize {
        match self {
            None => 0,
            Some(x) => x.to_usize() + 1,
        }
    }
    fn from_function<F: FnMut(Self) -> T>(mut f: F) -> Self::Array {
        OptionInternal {
            none: f(None),
            some: U::from_function(|x| f(Some(x))),
        }
    }
}
<commit_msg>Document why OptionInternal is needed<commit_after>use core::slice;

/// Internal enum mapping type
///
/// This trait is internally used by `#[derive(EnumMap)]`. Despite it being
/// a public trait, it's not intended to be public. `Internal<T>` is
/// implemented by any enum type where V is a generic type representing a
/// value. The purpose of this generic type is to allow providing a value
/// type for arrays, as Rust currently does not support higher kinded types.
/// Users aren't expected to use this trait directly, but rather to use
/// `EnumMap<K, V>` which uses this internally.
///
/// This trait is also implemented by `bool`, `u8` and `Option` type. While `u8` is
/// strictly speaking not an actual enum, there are good reasons to consider
/// it like one, as array of `u8` keys is a relatively common pattern.
pub trait Internal<V>: Sized {
    /// Representation of an enum map for type `V`, usually an array.
    type Array;
    #[doc(hidden)]
    fn slice(&Self::Array) -> &[V];
    #[doc(hidden)]
    fn slice_mut(&mut Self::Array) -> &mut [V];
    #[doc(hidden)]
    fn from_usize(usize) -> Self;
    #[doc(hidden)]
    fn to_usize(self) -> usize;
    #[doc(hidden)]
    fn from_function<F: FnMut(Self) -> V>(F) -> Self::Array;
}

impl<T> Internal<T> for bool {
    type Array = [T; 2];
    fn slice(array: &[T; 2]) -> &[T] {
        array
    }
    fn slice_mut(array: &mut [T; 2]) -> &mut [T] {
        array
    }
    fn from_usize(value: usize) -> Self {
        match value {
            0 => false,
            1 => true,
            _ => unreachable!(),
        }
    }
    fn to_usize(self) -> usize {
        self as usize
    }
    fn from_function<F: FnMut(Self) -> T>(mut f: F) -> [T; 2] {
        [f(false), f(true)]
    }
}

impl<T> Internal<T> for u8 {
    type Array = [T; 256];
    fn slice(array: &[T; 256]) -> &[T] {
        array
    }
    fn slice_mut(array: &mut [T; 256]) -> &mut [T] {
        array
    }
    fn from_usize(value: usize) -> Self {
        value as u8
    }
    fn to_usize(self) -> usize {
        self as usize
    }
    fn from_function<F: FnMut(Self) -> T>(mut f: F) -> [T; 256] {
        array![|i| f(i); 256]
    }
}

// C representation is needed to ensure Rust compiler won't reorder those 2 fields.
#[repr(C)]
pub struct OptionInternal<T, U> {
    none: T,
    some: U,
}

impl<T, U: Internal<T>> Internal<T> for Option<U> {
    type Array = OptionInternal<T, U::Array>;
    fn slice(array: &Self::Array) -> &[T] {
        unsafe {
            slice::from_raw_parts(
                array as *const _ as *const T,
                1 + U::slice(&array.some).len(),
            )
        }
    }
    fn slice_mut(array: &mut Self::Array) -> &mut [T] {
        unsafe {
            slice::from_raw_parts_mut(array as *mut _ as *mut T, 1 + U::slice(&array.some).len())
        }
    }
    fn from_usize(value: usize) -> Self {
        match value {
            0 => None,
            v => Some(U::from_usize(v - 1)),
        }
    }
    fn to_usize(self) -> usize {
        match self {
            None => 0,
            Some(x) => x.to_usize() + 1,
        }
    }
    fn from_function<F: FnMut(Self) -> T>(mut f: F) -> Self::Array {
        OptionInternal {
            none: f(None),
            some: U::from_function(|x| f(Some(x))),
        }
    }
}
<|endoftext|>


<commit_before>extern crate stratis_shared as shared;
extern crate stratis;

use stratis::{Server,Client};
use shared::opcode;
use shared::events::Event;

use std::thread;
use std::time::Duration;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::Receiver;

fn assert_opcode (rx: &Receiver<Event>, op: u8) -> Event {
    match rx.try_recv() {
        Ok(ev) => {
            assert_eq!(ev.0,op);
            return ev
        },
        _ => { panic!("no events received"); }
    }
}

fn assert_client () -> (Arc<Mutex<Client>>,Receiver<Event>) {
    let host = "127.0.0.1:65432";
    let _handle = thread::spawn(move || {
        let mut _server = Server::new(host);
    });
    let (mut client, rx) = Client::default();
    client.connect(host);
    client.register();

    let client = Arc::new(Mutex::new(client));
    Client::login(&client);

    assert!(client.lock().unwrap().stream.is_some());

    (client,rx)
}

#[test]
fn client () {
    let (_client, rx) = assert_client();

    thread::sleep(Duration::from_millis(100));

    // we recv player twice
    // once for our own login
    // and again for each player that's connected
    assert_opcode(&rx,opcode::PLAYER);
    assert_opcode(&rx,opcode::PLAYER);

    thread::sleep(Duration::from_millis(100));
}
<commit_msg>wip: proper rand port<commit_after>extern crate stratis_shared as shared;
extern crate stratis;

extern crate rand;

use stratis::{Server,Client};
use shared::opcode;
use shared::events::Event;

use std::thread;
use std::time::Duration;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::Receiver;

use rand::distributions::{IndependentSample,Range};

fn assert_opcode (rx: &Receiver<Event>, op: u8) -> Event {
    match rx.try_recv() {
        Ok(ev) => {
            assert_eq!(ev.0,op);
            return ev
        },
        _ => { panic!("no events received"); }
    }
}

fn assert_client () -> (Arc<Mutex<Client>>,Receiver<Event>) {
    let btw = Range::new(25000,64000);
    let mut rng = rand::thread_rng();

    let v = btw.ind_sample(&mut rng);
    println!("{:?}",v);

    let host = "127.0.0.1:".to_owned() + stringify!(btw.ind_sample(&mut rng));
    let host_ = host.clone();
    let _handle = thread::spawn(move || {
        let mut _server = Server::new(&host_);
    });
    let (mut client, rx) = Client::default();
    client.connect(&host);
    client.register();

    let client = Arc::new(Mutex::new(client));
    Client::login(&client);

    assert!(client.lock().unwrap().stream.is_some());

    (client,rx)
}

#[test]
fn client () {
    let (_client, rx) = assert_client();

    thread::sleep(Duration::from_millis(100));

    // we recv player twice
    // once for our own login
    // and again for each player that's connected
    assert_opcode(&rx,opcode::PLAYER);
    assert_opcode(&rx,opcode::PLAYER);
}

#[test]
fn client_chat () {
    let (client, rx) = assert_client();

    thread::sleep(Duration::from_millis(100));
    let text = "test";
    client.lock().unwrap().chat(text);

    assert_opcode(&rx,opcode::PLAYER);
    assert_opcode(&rx,opcode::PLAYER);
    let id = assert_opcode(&rx,opcode::CHAT).1;
    let text_ = client.lock().unwrap()
        .msg_cache.get_mut(&id).unwrap()
        .remove(0);

    assert_eq!(text,text_);
}
<|endoftext|>


<commit_before>//! This module provides a microfacet model for transmission (a BTDF), see
//! [Walter et al. 07](https://www.cs.cornell.edu/~srm/publications/EGSR07-btdf.pdf)
//! for details.

use std::f32;
use enum_set::EnumSet;

use linalg::{self, Vector};
use film::Colorf;
use bxdf::{self, BxDF, BxDFType};
use bxdf::fresnel::{Dielectric, Fresnel};
use bxdf::microfacet::{MicrofacetDistribution};

/// Struct providing the microfacet BTDF, implemented as described in
/// [Walter et al. 07](https://www.cs.cornell.edu/~srm/publications/EGSR07-btdf.pdf)
#[derive(Copy, Clone)]
pub struct MicrofacetTransmission<'a> {
    reflectance: Colorf,
    fresnel: &'a Dielectric,
    /// Microfacet distribution describing the structure of the microfacets of
    /// the material
    microfacet: &'a MicrofacetDistribution,
}

impl<'a> MicrofacetTransmission<'a> {
    /// Create a new transmissive microfacet BRDF
    pub fn new(c: &Colorf, fresnel: &'a Dielectric, microfacet: &'a MicrofacetDistribution)
            -> MicrofacetTransmission<'a> {
        MicrofacetTransmission { reflectance: *c, fresnel: fresnel, microfacet: microfacet }
    }
    /// Convenience method for getting `eta_i` and `eta_t` in the right order for if
    /// we're entering or exiting this material based on the direction of the outgoing
    /// ray.
    fn eta_for_interaction(&self, w_o: &Vector) -> (f32, f32) {
        if bxdf::cos_theta(w_o) > 0.0 {
            (self.fresnel.eta_i, self.fresnel.eta_t)
        } else {
            (self.fresnel.eta_t, self.fresnel.eta_i)
        }
    }
    /// Compute the Jacobian for the change of variables (see [Walter et al 07] section 4.2),
    /// here we compute equation 17 in that section.
    fn jacobian(w_o: &Vector, w_i: &Vector, w_h: &Vector, eta: (f32, f32)) -> f32 {
        let wi_dot_h = linalg::dot(w_i, w_h);
        let wo_dot_h = linalg::dot(w_o, w_h);
        let denom = f32::powf(eta.1 * wi_dot_h + eta.0 * wo_dot_h, 2.0);
        if denom != 0.0 {
            f32::abs(f32::powf(eta.0, 2.0) * f32::abs(wo_dot_h) / denom)
        } else {
            0.0
        }
    }
    fn half_vector(w_o: &Vector, w_i: &Vector, eta: (f32, f32)) -> Vector {
        (-eta.1 * *w_i - eta.0 * *w_o).normalized()
    }
}

impl<'a> BxDF for MicrofacetTransmission<'a> {
    fn bxdf_type(&self) -> EnumSet<BxDFType> {
        let mut e = EnumSet::new();
        e.insert(BxDFType::Glossy);
        e.insert(BxDFType::Transmission);
        e
    }
    fn eval(&self, w_o: &Vector, w_i: &Vector) -> Colorf {
        if bxdf::same_hemisphere(w_o, w_i) {
            return Colorf::black();
        }
        let cos_to = bxdf::cos_theta(w_o);
        let cos_ti = bxdf::cos_theta(w_i);
        if cos_to == 0.0 || cos_ti == 0.0 {
            return Colorf::black();
        }
        let eta = self.eta_for_interaction(w_o);
        let w_h = MicrofacetTransmission::half_vector(w_o, w_i, eta);
        let d = self.microfacet.normal_distribution(&w_h);
        let f = Colorf::broadcast(1.0) - self.fresnel.fresnel(linalg::dot(w_o, &w_h));
        let g = self.microfacet.shadowing_masking(w_i, w_o, &w_h);
        let wi_dot_h = linalg::dot(w_i, &w_h);
        let jacobian = MicrofacetTransmission::jacobian(w_o, w_i, &w_h, eta);
        self.reflectance * (f32::abs(wi_dot_h) / (f32::abs(w_i.z) * f32::abs(w_o.z)))
            * (f * g * d) * jacobian
    }
    fn sample(&self, w_o: &Vector, samples: &(f32, f32)) -> (Colorf, Vector, f32) {
        let mut w_h = self.microfacet.sample(w_o, samples);
        if !bxdf::same_hemisphere(w_o, &w_h) {
            w_h = -w_h;
        }
        let eta = self.eta_for_interaction(w_o);
        if let Some(w_i) = linalg::refract(w_o, &w_h, eta.0 / eta.1) {
            if bxdf::same_hemisphere(w_o, &w_i) {
                (Colorf::black(), Vector::broadcast(0.0), 0.0)
            } else {
                (self.eval(w_o, &w_i), w_i, self.pdf(w_o, &w_i))
            }
        } else {
            (Colorf::black(), Vector::broadcast(0.0), 0.0)
        }
    }
    fn pdf(&self, w_o: &Vector, w_i: &Vector) -> f32 {
        if bxdf::same_hemisphere(w_o, w_i) {
            0.0
        } else {
            let eta = self.eta_for_interaction(w_o);
            let w_h = MicrofacetTransmission::half_vector(w_o, w_i, eta);
            self.microfacet.pdf(&w_h) * MicrofacetTransmission::jacobian(w_o, w_i, &w_h, eta)
        }
    }
}

<commit_msg>small typo fix, though does not change render<commit_after>//! This module provides a microfacet model for transmission (a BTDF), see
//! [Walter et al. 07](https://www.cs.cornell.edu/~srm/publications/EGSR07-btdf.pdf)
//! for details.

use std::f32;
use enum_set::EnumSet;

use linalg::{self, Vector};
use film::Colorf;
use bxdf::{self, BxDF, BxDFType};
use bxdf::fresnel::{Dielectric, Fresnel};
use bxdf::microfacet::{MicrofacetDistribution};

/// Struct providing the microfacet BTDF, implemented as described in
/// [Walter et al. 07](https://www.cs.cornell.edu/~srm/publications/EGSR07-btdf.pdf)
#[derive(Copy, Clone)]
pub struct MicrofacetTransmission<'a> {
    reflectance: Colorf,
    fresnel: &'a Dielectric,
    /// Microfacet distribution describing the structure of the microfacets of
    /// the material
    microfacet: &'a MicrofacetDistribution,
}

impl<'a> MicrofacetTransmission<'a> {
    /// Create a new transmissive microfacet BRDF
    pub fn new(c: &Colorf, fresnel: &'a Dielectric, microfacet: &'a MicrofacetDistribution)
            -> MicrofacetTransmission<'a> {
        MicrofacetTransmission { reflectance: *c, fresnel: fresnel, microfacet: microfacet }
    }
    /// Convenience method for getting `eta_i` and `eta_t` in the right order for if
    /// we're entering or exiting this material based on the direction of the outgoing
    /// ray.
    fn eta_for_interaction(&self, w_o: &Vector) -> (f32, f32) {
        if bxdf::cos_theta(w_o) > 0.0 {
            (self.fresnel.eta_i, self.fresnel.eta_t)
        } else {
            (self.fresnel.eta_t, self.fresnel.eta_i)
        }
    }
    /// Compute the Jacobian for the change of variables (see [Walter et al 07] section 4.2),
    /// here we compute equation 17 in that section.
    fn jacobian(w_o: &Vector, w_i: &Vector, w_h: &Vector, eta: (f32, f32)) -> f32 {
        let wi_dot_h = linalg::dot(w_i, w_h);
        let wo_dot_h = linalg::dot(w_o, w_h);
        let denom = f32::powf(eta.1 * wi_dot_h + eta.0 * wo_dot_h, 2.0);
        if denom != 0.0 {
            f32::abs(f32::powf(eta.0, 2.0) * f32::abs(wo_dot_h) / denom)
        } else {
            0.0
        }
    }
    fn half_vector(w_o: &Vector, w_i: &Vector, eta: (f32, f32)) -> Vector {
        (-eta.1 * *w_i - eta.0 * *w_o).normalized()
    }
}

impl<'a> BxDF for MicrofacetTransmission<'a> {
    fn bxdf_type(&self) -> EnumSet<BxDFType> {
        let mut e = EnumSet::new();
        e.insert(BxDFType::Glossy);
        e.insert(BxDFType::Transmission);
        e
    }
    fn eval(&self, w_o: &Vector, w_i: &Vector) -> Colorf {
        if bxdf::same_hemisphere(w_o, w_i) {
            return Colorf::black();
        }
        let cos_to = bxdf::cos_theta(w_o);
        let cos_ti = bxdf::cos_theta(w_i);
        if cos_to == 0.0 || cos_ti == 0.0 {
            return Colorf::black();
        }
        let eta = self.eta_for_interaction(w_o);
        let w_h = MicrofacetTransmission::half_vector(w_o, w_i, eta);
        let d = self.microfacet.normal_distribution(&w_h);
        let f = Colorf::broadcast(1.0) - self.fresnel.fresnel(linalg::dot(w_i, &w_h));
        let g = self.microfacet.shadowing_masking(w_i, w_o, &w_h);
        let wi_dot_h = linalg::dot(w_i, &w_h);
        let jacobian = MicrofacetTransmission::jacobian(w_o, w_i, &w_h, eta);
        self.reflectance * (f32::abs(wi_dot_h) / (f32::abs(w_i.z) * f32::abs(w_o.z)))
            * (f * g * d) * jacobian
    }
    fn sample(&self, w_o: &Vector, samples: &(f32, f32)) -> (Colorf, Vector, f32) {
        let mut w_h = self.microfacet.sample(w_o, samples);
        if !bxdf::same_hemisphere(w_o, &w_h) {
            w_h = -w_h;
        }
        let eta = self.eta_for_interaction(w_o);
        if let Some(w_i) = linalg::refract(w_o, &w_h, eta.0 / eta.1) {
            if bxdf::same_hemisphere(w_o, &w_i) {
                (Colorf::black(), Vector::broadcast(0.0), 0.0)
            } else {
                (self.eval(w_o, &w_i), w_i, self.pdf(w_o, &w_i))
            }
        } else {
            (Colorf::black(), Vector::broadcast(0.0), 0.0)
        }
    }
    fn pdf(&self, w_o: &Vector, w_i: &Vector) -> f32 {
        if bxdf::same_hemisphere(w_o, w_i) {
            0.0
        } else {
            let eta = self.eta_for_interaction(w_o);
            let w_h = MicrofacetTransmission::half_vector(w_o, w_i, eta);
            self.microfacet.pdf(&w_h) * MicrofacetTransmission::jacobian(w_o, w_i, &w_h, eta)
        }
    }
}

<|endoftext|>