<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />
<% from data import Method %>

// CSS Basic User Interface Module Level 1
// https://drafts.csswg.org/css-ui-3/
<% data.new_style_struct("UI", inherited=False, gecko_name="UIReset") %>

// TODO spec says that UAs should not support this
// we should probably remove from gecko (https://bugzilla.mozilla.org/show_bug.cgi?id=1328331)
${helpers.single_keyword("ime-mode", "auto normal active disabled inactive",
                         products="gecko", gecko_ffi_name="mIMEMode",
                         animation_value_type="discrete",
                         spec="https://drafts.csswg.org/css-ui/#input-method-editor")}

${helpers.single_keyword("-moz-user-select", "auto text none all element elements" +
                            " toggle tri-state -moz-all -moz-text",
                         products="gecko",
                         alias="-webkit-user-select",
                         gecko_ffi_name="mUserSelect",
                         gecko_enum_prefix="StyleUserSelect",
                         gecko_strip_moz_prefix=False,
                         aliases="-moz-none=none",
                         animation_value_type="discrete",
                         spec="https://drafts.csswg.org/css-ui-4/#propdef-user-select")}

// TODO(emilio): This probably should be hidden from content.
${helpers.single_keyword("-moz-window-dragging", "default drag no-drag", products="gecko",
                         gecko_ffi_name="mWindowDragging",
                         gecko_enum_prefix="StyleWindowDragging",
                         animation_value_type="discrete",
                         spec="None (Nonstandard Firefox-only property)")}

${helpers.single_keyword("-moz-window-shadow", "none default menu tooltip sheet", products="gecko",
                         gecko_ffi_name="mWindowShadow",
                         gecko_constant_prefix="NS_STYLE_WINDOW_SHADOW",
                         animation_value_type="discrete",
                         enabled_in="chrome",
                         spec="None (Nonstandard internal property)")}

${helpers.predefined_type("-moz-window-opacity", "Opacity", "1.0", products="gecko",
                          gecko_ffi_name="mWindowOpacity",
                          animation_value_type="ComputedValue",
                          enabled_in="chrome",
                          spec="None (Nonstandard internal property)")}

${helpers.predefined_type("-moz-window-transform", "Transform",
                          "generics::transform::Transform::none()",
                          products="gecko", gecko_ffi_name="mSpecifiedWindowTransform",
                          animation_value_type="ComputedValue",
                          enabled_in="chrome",
                          spec="None (Nonstandard internal property)")}

${helpers.predefined_type("-moz-window-transform-origin",
                          "TransformOrigin",
                          "computed::TransformOrigin::initial_value()",
                          animation_value_type="ComputedValue",
                          gecko_ffi_name="mWindowTransformOrigin",
                          products="gecko",
                          boxed=True,
                          enabled_in="chrome",
                          spec="None (Nonstandard internal property)")}

// TODO(emilio): Probably also should be hidden from content.
${helpers.predefined_type("-moz-force-broken-image-icon",
                          "MozForceBrokenImageIcon",
                          "computed::MozForceBrokenImageIcon::false_value()",
                          animation_value_type="discrete",
                          products="gecko",
                          spec="None (Nonstandard Firefox-only property)")}
<commit_msg>style: Have ENABLED_IN flags in nsCSSPropList.h match those in Servo side.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />
<% from data import Method %>

// CSS Basic User Interface Module Level 1
// https://drafts.csswg.org/css-ui-3/
<% data.new_style_struct("UI", inherited=False, gecko_name="UIReset") %>

// TODO spec says that UAs should not support this
// we should probably remove from gecko (https://bugzilla.mozilla.org/show_bug.cgi?id=1328331)
${helpers.single_keyword("ime-mode", "auto normal active disabled inactive",
                         products="gecko", gecko_ffi_name="mIMEMode",
                         animation_value_type="discrete",
                         spec="https://drafts.csswg.org/css-ui/#input-method-editor")}

${helpers.single_keyword("-moz-user-select", "auto text none all element elements" +
                            " toggle tri-state -moz-all -moz-text",
                         products="gecko",
                         alias="-webkit-user-select",
                         gecko_ffi_name="mUserSelect",
                         gecko_enum_prefix="StyleUserSelect",
                         gecko_strip_moz_prefix=False,
                         aliases="-moz-none=none",
                         animation_value_type="discrete",
                         spec="https://drafts.csswg.org/css-ui-4/#propdef-user-select")}

// TODO(emilio): This probably should be hidden from content.
${helpers.single_keyword("-moz-window-dragging", "default drag no-drag", products="gecko",
                         gecko_ffi_name="mWindowDragging",
                         gecko_enum_prefix="StyleWindowDragging",
                         animation_value_type="discrete",
                         spec="None (Nonstandard Firefox-only property)")}

${helpers.single_keyword("-moz-window-shadow", "none default menu tooltip sheet", products="gecko",
                         gecko_ffi_name="mWindowShadow",
                         gecko_constant_prefix="NS_STYLE_WINDOW_SHADOW",
                         animation_value_type="discrete",
                         enabled_in="chrome",
                         spec="None (Nonstandard internal property)")}

// TODO(bug 1419695) This should be hidden from content.
${helpers.predefined_type("-moz-window-opacity", "Opacity", "1.0", products="gecko",
                          gecko_ffi_name="mWindowOpacity",
                          animation_value_type="ComputedValue",
                          spec="None (Nonstandard internal property)")}

// TODO(bug 1419695) This should be hidden from content.
${helpers.predefined_type("-moz-window-transform", "Transform",
                          "generics::transform::Transform::none()",
                          products="gecko", gecko_ffi_name="mSpecifiedWindowTransform",
                          animation_value_type="ComputedValue",
                          spec="None (Nonstandard internal property)")}

// TODO(bug 1419695) This should be hidden from content.
${helpers.predefined_type("-moz-window-transform-origin",
                          "TransformOrigin",
                          "computed::TransformOrigin::initial_value()",
                          animation_value_type="ComputedValue",
                          gecko_ffi_name="mWindowTransformOrigin",
                          products="gecko",
                          boxed=True,
                          spec="None (Nonstandard internal property)")}

// TODO(emilio): Probably also should be hidden from content.
${helpers.predefined_type("-moz-force-broken-image-icon",
                          "MozForceBrokenImageIcon",
                          "computed::MozForceBrokenImageIcon::false_value()",
                          animation_value_type="discrete",
                          products="gecko",
                          spec="None (Nonstandard Firefox-only property)")}
<|endoftext|>


<commit_before>use hoedown::{Markdown, Html as MdHtml};
use hoedown::renderer::html::Flags as HtmlFlags;
use hoedown::renderer::Render;

use result::Result;
use error::MarkdownErrorKind;
use libimagerror::into::IntoError;

pub type HTML = String;

pub fn to_html(buffer: &str) -> Result<HTML> {
    let md = Markdown::new(buffer);
    let mut html = MdHtml::new(HtmlFlags::empty(), 0);
    html.render(&md)
        .to_str()
        .map(String::from)
        .map_err(Box::new)
        .map_err(|e| MarkdownErrorKind::MarkdownRenderError.into_error_with_cause(e))
}

pub mod iter {
    use result::Result;
    use libimagstore::store::Entry;
    use super::HTML;
    use super::to_html;

    pub struct ToHtmlIterator<I: Iterator<Item = Entry>> {
        i: I
    }

    impl<I: Iterator<Item = Entry>> ToHtmlIterator<I> {

        fn new(i: I) -> ToHtmlIterator<I> {
            ToHtmlIterator { i: i }
        }

    }

    impl<I: Iterator<Item = Entry>> Iterator for ToHtmlIterator<I> {
        type Item = Result<HTML>;

        fn next(&mut self) -> Option<Self::Item> {
            self.i.next().map(|entry| to_html(&entry.get_content()[..]))
        }

    }

}
<commit_msg>Impl From<I> for ToHtmlIterator<I><commit_after>use hoedown::{Markdown, Html as MdHtml};
use hoedown::renderer::html::Flags as HtmlFlags;
use hoedown::renderer::Render;

use result::Result;
use error::MarkdownErrorKind;
use libimagerror::into::IntoError;

pub type HTML = String;

pub fn to_html(buffer: &str) -> Result<HTML> {
    let md = Markdown::new(buffer);
    let mut html = MdHtml::new(HtmlFlags::empty(), 0);
    html.render(&md)
        .to_str()
        .map(String::from)
        .map_err(Box::new)
        .map_err(|e| MarkdownErrorKind::MarkdownRenderError.into_error_with_cause(e))
}

pub mod iter {
    use result::Result;
    use libimagstore::store::Entry;
    use super::HTML;
    use super::to_html;

    pub struct ToHtmlIterator<I: Iterator<Item = Entry>> {
        i: I
    }

    impl<I: Iterator<Item = Entry>> ToHtmlIterator<I> {

        fn new(i: I) -> ToHtmlIterator<I> {
            ToHtmlIterator { i: i }
        }

    }

    impl<I: Iterator<Item = Entry>> Iterator for ToHtmlIterator<I> {
        type Item = Result<HTML>;

        fn next(&mut self) -> Option<Self::Item> {
            self.i.next().map(|entry| to_html(&entry.get_content()[..]))
        }

    }

    impl<I: Iterator<Item = Entry>> From<I> for ToHtmlIterator<I> {

        fn from(obj: I) -> ToHtmlIterator<I> {
            ToHtmlIterator::new(obj)
        }

    }

}
<|endoftext|>


<commit_before>use failure::{Error, Fail};
use std::env;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process::{Command, Output};
use tempfile::TempDir;

#[derive(Debug, Fail)]
pub enum CompileError {
    #[fail(display = "File not found: {}", _0)]
    FileNotFound(String),
    #[fail(display = "Clang reported error: {}", _0)]
    Execution { stdout: String, stderr: String },
    #[fail(display = "Lucetc error: {}", _0)]
    Lucetc {
        #[cause]
        e: Error,
    },
    #[fail(display = "IO error: {}", _0)]
    IO {
        #[cause]
        e: std::io::Error,
    },
}

impl From<std::io::Error> for CompileError {
    fn from(e: std::io::Error) -> CompileError {
        CompileError::IO { e }
    }
}

impl CompileError {
    pub fn check(output: Output, print: bool) -> Result<(), Self> {
        if print {
            std::io::stdout().write_all(&output.stdout).unwrap();
            std::io::stderr().write_all(&output.stderr).unwrap();
        }
        if output.status.success() {
            Ok(())
        } else {
            Err(CompileError::Execution {
                stdout: String::from_utf8_lossy(&output.stdout).to_string(),
                stderr: String::from_utf8_lossy(&output.stderr).to_string(),
            })
        }
    }
}

fn wasi_sdk() -> PathBuf {
    Path::new(&env::var("WASI_SDK").unwrap_or("/opt/wasi-sdk".to_owned())).to_path_buf()
}

fn wasm_clang() -> PathBuf {
    match env::var("CLANG") {
        Ok(clang) => Path::new(&clang).to_path_buf(),
        Err(_) => {
            let mut path = wasi_sdk();
            path.push("bin");
            path.push("clang");
            path
        }
    }
}

pub struct Compile {
    input: PathBuf,
    cflags: Vec<String>,
    print_output: bool,
}

pub trait CompileOpts {
    fn cflag<S: AsRef<str>>(&mut self, cflag: S);
    fn with_cflag<S: AsRef<str>>(self, cflag: S) -> Self;

    fn include<S: AsRef<str>>(&mut self, include: S);
    fn with_include<S: AsRef<str>>(self, include: S) -> Self;
}

impl CompileOpts for Compile {
    fn cflag<S: AsRef<str>>(&mut self, cflag: S) {
        self.cflags.push(cflag.as_ref().to_owned());
    }

    fn with_cflag<S: AsRef<str>>(mut self, cflag: S) -> Self {
        self.cflag(cflag);
        self
    }

    fn include<S: AsRef<str>>(&mut self, include: S) {
        self.cflags.push(format!("-I{}", include.as_ref()));
    }

    fn with_include<S: AsRef<str>>(mut self, include: S) -> Self {
        self.include(include);
        self
    }
}

impl Compile {
    pub fn new<P: AsRef<Path>>(input: P) -> Self {
        Compile {
            input: PathBuf::from(input.as_ref()),
            cflags: Vec::new(),
            print_output: false,
        }
    }

    pub fn print_output(&mut self, print: bool) {
        self.print_output = print;
    }

    pub fn with_print_output(mut self, print: bool) -> Self {
        self.print_output(print);
        self
    }

    pub fn compile<P: AsRef<Path>>(&self, output: P) -> Result<(), CompileError> {
        let clang = wasm_clang();
        if !clang.exists() {
            Err(CompileError::FileNotFound(
                clang.to_string_lossy().into_owned(),
            ))?;
        }
        if !self.input.exists() {
            Err(CompileError::FileNotFound(
                self.input.to_string_lossy().into_owned(),
            ))?;
        }
        let mut cmd = Command::new(clang);
        cmd.arg("-c");
        cmd.arg(self.input.clone());
        cmd.arg("-o");
        cmd.arg(output.as_ref());
        for cflag in self.cflags.iter() {
            cmd.arg(cflag);
        }
        let run = cmd.output().expect("clang executable exists");
        CompileError::check(run, self.print_output)
    }
}

pub struct Link {
    input: Vec<PathBuf>,
    cflags: Vec<String>,
    ldflags: Vec<String>,
    print_output: bool,
}

impl Link {
    pub fn new<P: AsRef<Path>>(input: &[P]) -> Self {
        Link {
            input: input.iter().map(|p| PathBuf::from(p.as_ref())).collect(),
            cflags: vec![],
            ldflags: vec![],
            print_output: false,
        }
        .with_ldflag("--no-threads")
    }

    pub fn print_output(&mut self, print: bool) {
        self.print_output = print;
    }

    pub fn with_print_output(mut self, print: bool) -> Self {
        self.print_output(print);
        self
    }

    pub fn link<P: AsRef<Path>>(&self, output: P) -> Result<(), CompileError> {
        let clang = wasm_clang();
        if !clang.exists() {
            Err(CompileError::FileNotFound(
                clang.to_string_lossy().into_owned(),
            ))?;
        }
        let mut cmd = Command::new(clang);
        for input in self.input.iter() {
            if !input.exists() {
                Err(CompileError::FileNotFound(
                    input.to_string_lossy().into_owned(),
                ))?;
            }
            cmd.arg(input.clone());
        }
        cmd.arg("-o");
        cmd.arg(output.as_ref());
        for cflag in self.cflags.iter() {
            cmd.arg(cflag);
        }
        for ldflag in self.ldflags.iter() {
            cmd.arg(format!("-Wl,{}", ldflag));
        }
        let run = cmd.output().expect("clang executable exists");
        CompileError::check(run, self.print_output)
    }
}

pub trait AsLink {
    fn as_link(&mut self) -> &mut Link;
}

impl AsLink for Link {
    fn as_link(&mut self) -> &mut Link {
        self
    }
}

pub trait LinkOpts {
    fn ldflag<S: AsRef<str>>(&mut self, ldflag: S);
    fn with_ldflag<S: AsRef<str>>(self, ldflag: S) -> Self;

    fn export<S: AsRef<str>>(&mut self, export: S);
    fn with_export<S: AsRef<str>>(self, export: S) -> Self;
}

impl<T: AsLink> LinkOpts for T {
    fn ldflag<S: AsRef<str>>(&mut self, ldflag: S) {
        self.as_link().ldflags.push(ldflag.as_ref().to_owned());
    }

    fn with_ldflag<S: AsRef<str>>(mut self, ldflag: S) -> Self {
        self.ldflag(ldflag);
        self
    }

    fn export<S: AsRef<str>>(&mut self, export: S) {
        self.as_link()
            .ldflags
            .push(format!("--export={}", export.as_ref()));
    }

    fn with_export<S: AsRef<str>>(mut self, export: S) -> Self {
        self.export(export);
        self
    }
}

impl<T: AsLink> CompileOpts for T {
    fn cflag<S: AsRef<str>>(&mut self, cflag: S) {
        self.as_link().cflags.push(cflag.as_ref().to_owned());
    }

    fn with_cflag<S: AsRef<str>>(mut self, cflag: S) -> Self {
        self.cflag(cflag);
        self
    }

    fn include<S: AsRef<str>>(&mut self, include: S) {
        self.as_link()
            .cflags
            .push(format!("-I{}", include.as_ref()));
    }

    fn with_include<S: AsRef<str>>(mut self, include: S) -> Self {
        self.include(include);
        self
    }
}

pub struct Lucetc {
    link: Link,
    lucetc: lucetc::Lucetc,
    tmpdir: TempDir,
    wasm_file: PathBuf,
}

impl Lucetc {
    pub fn new<P: AsRef<Path>>(input: &[P]) -> Self {
        let link = Link::new(input);
        let tmpdir = TempDir::new().expect("temporary directory creation failed");
        let wasm_file = tmpdir.path().join("out.wasm");
        let lucetc = lucetc::Lucetc::new(&wasm_file);
        Lucetc {
            link,
            lucetc,
            tmpdir,
            wasm_file,
        }
    }

    pub fn print_output(mut self, print: bool) -> Self {
        self.link.print_output = print;
        self
    }

    pub fn build<P: AsRef<Path>>(self, output: P) -> Result<(), CompileError> {
        self.link.link(&self.wasm_file)?;
        self.lucetc
            .shared_object_file(output.as_ref())
            .map_err(|e| CompileError::Lucetc { e })?;
        Ok(self.tmpdir.close()?)
    }
}

impl AsLink for Lucetc {
    fn as_link(&mut self) -> &mut Link {
        &mut self.link
    }
}

impl lucetc::AsLucetc for Lucetc {
    fn as_lucetc(&mut self) -> &mut lucetc::Lucetc {
        &mut self.lucetc
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use tempfile::TempDir;
    #[test]
    fn wasi_sdk_installed() {
        let clang = wasm_clang();
        assert!(clang.exists(), "clang executable exists");
    }

    fn test_file(name: &str) -> PathBuf {
        let mut p = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
        p.push("test");
        p.push(name);
        assert!(p.exists(), "test file does not exist");
        p
    }

    #[test]
    fn compile_a() {
        let tmp = TempDir::new().expect("create temporary directory");

        let compiler = Compile::new(test_file("a.c"));

        let objfile = tmp.path().join("a.o");

        compiler.compile(objfile.clone()).expect("compile a.c");

        assert!(objfile.exists(), "object file created");

        let mut linker = Link::new(&[objfile]);
        linker.cflag("-nostartfiles");
        linker.ldflag("--no-entry");

        let wasmfile = tmp.path().join("a.wasm");

        linker.link(wasmfile.clone()).expect("link a.wasm");

        assert!(wasmfile.exists(), "wasm file created");
    }

    #[test]
    fn compile_b() {
        let tmp = TempDir::new().expect("create temporary directory");

        let compiler = Compile::new(test_file("b.c"));

        let objfile = tmp.path().join("b.o");

        compiler.compile(objfile.clone()).expect("compile b.c");

        assert!(objfile.exists(), "object file created");

        let mut linker = Link::new(&[objfile]);
        linker.cflag("-nostartfiles");
        linker.ldflag("--no-entry");
        linker.ldflag("--allow-undefined");

        let wasmfile = tmp.path().join("b.wasm");

        linker.link(wasmfile.clone()).expect("link b.wasm");

        assert!(wasmfile.exists(), "wasm file created");
    }

    #[test]
    fn compile_a_and_b() {
        let tmp = TempDir::new().expect("create temporary directory");

        let mut linker = Link::new(&[test_file("a.c"), test_file("b.c")]);
        linker.cflag("-nostartfiles");
        linker.ldflag("--no-entry");

        let wasmfile = tmp.path().join("ab.wasm");

        linker.link(wasmfile.clone()).expect("link ab.wasm");

        assert!(wasmfile.exists(), "wasm file created");
    }

    #[test]
    fn compile_to_lucet() {
        let tmp = TempDir::new().expect("create temporary directory");

        let mut lucetc = Lucetc::new(&[test_file("a.c"), test_file("b.c")]);
        lucetc.cflag("-nostartfiles");
        lucetc.ldflag("--no-entry");

        let so_file = tmp.path().join("ab.so");

        lucetc.build(&so_file).expect("compile ab.so");

        assert!(so_file.exists(), "so file created");
    }
}
<commit_msg>Make lucet-wasi-sdk work with a standard LLVM install<commit_after>use failure::{Error, Fail};
use std::env;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process::{Command, Output};
use tempfile::TempDir;

const WASI_TARGET: &str = "wasm32-unknown-wasi";

#[derive(Debug, Fail)]
pub enum CompileError {
    #[fail(display = "File not found: {}", _0)]
    FileNotFound(String),
    #[fail(display = "Clang reported error: {}", _0)]
    Execution { stdout: String, stderr: String },
    #[fail(display = "Lucetc error: {}", _0)]
    Lucetc {
        #[cause]
        e: Error,
    },
    #[fail(display = "IO error: {}", _0)]
    IO {
        #[cause]
        e: std::io::Error,
    },
}

impl From<std::io::Error> for CompileError {
    fn from(e: std::io::Error) -> CompileError {
        CompileError::IO { e }
    }
}

impl CompileError {
    pub fn check(output: Output, print: bool) -> Result<(), Self> {
        if print {
            std::io::stdout().write_all(&output.stdout).unwrap();
            std::io::stderr().write_all(&output.stderr).unwrap();
        }
        if output.status.success() {
            Ok(())
        } else {
            Err(CompileError::Execution {
                stdout: String::from_utf8_lossy(&output.stdout).to_string(),
                stderr: String::from_utf8_lossy(&output.stderr).to_string(),
            })
        }
    }
}

fn wasi_sdk() -> PathBuf {
    Path::new(&env::var("WASI_SDK").unwrap_or("/opt/wasi-sdk".to_owned())).to_path_buf()
}

fn wasi_sysroot() -> PathBuf {
    match env::var("WASI_SYSROOT") {
        Ok(wasi_sysroot) => Path::new(&wasi_sysroot).to_path_buf(),
        Err(_) => {
            let mut path = wasi_sdk();
            path.push("share");
            path.push("sysroot");
            path
        }
    }
}

fn wasm_clang() -> PathBuf {
    match env::var("CLANG") {
        Ok(clang) => Path::new(&clang).to_path_buf(),
        Err(_) => {
            let mut path = wasi_sdk();
            path.push("bin");
            path.push("clang");
            path
        }
    }
}

pub struct Compile {
    input: PathBuf,
    cflags: Vec<String>,
    print_output: bool,
}

pub trait CompileOpts {
    fn cflag<S: AsRef<str>>(&mut self, cflag: S);
    fn with_cflag<S: AsRef<str>>(self, cflag: S) -> Self;

    fn include<S: AsRef<str>>(&mut self, include: S);
    fn with_include<S: AsRef<str>>(self, include: S) -> Self;
}

impl CompileOpts for Compile {
    fn cflag<S: AsRef<str>>(&mut self, cflag: S) {
        self.cflags.push(cflag.as_ref().to_owned());
    }

    fn with_cflag<S: AsRef<str>>(mut self, cflag: S) -> Self {
        self.cflag(cflag);
        self
    }

    fn include<S: AsRef<str>>(&mut self, include: S) {
        self.cflags.push(format!("-I{}", include.as_ref()));
    }

    fn with_include<S: AsRef<str>>(mut self, include: S) -> Self {
        self.include(include);
        self
    }
}

impl Compile {
    pub fn new<P: AsRef<Path>>(input: P) -> Self {
        Compile {
            input: PathBuf::from(input.as_ref()),
            cflags: Vec::new(),
            print_output: false,
        }
    }

    pub fn print_output(&mut self, print: bool) {
        self.print_output = print;
    }

    pub fn with_print_output(mut self, print: bool) -> Self {
        self.print_output(print);
        self
    }

    pub fn compile<P: AsRef<Path>>(&self, output: P) -> Result<(), CompileError> {
        let clang = wasm_clang();
        if !clang.exists() {
            Err(CompileError::FileNotFound(
                clang.to_string_lossy().into_owned(),
            ))?;
        }
        if !self.input.exists() {
            Err(CompileError::FileNotFound(
                self.input.to_string_lossy().into_owned(),
            ))?;
        }
        let mut cmd = Command::new(clang);
        cmd.arg(format!("--target={}", WASI_TARGET));
        cmd.arg(format!("--sysroot={}", wasi_sysroot().display()));
        cmd.arg("-c");
        cmd.arg(self.input.clone());
        cmd.arg("-o");
        cmd.arg(output.as_ref());
        for cflag in self.cflags.iter() {
            cmd.arg(cflag);
        }
        let run = cmd.output().expect("clang executable exists");
        CompileError::check(run, self.print_output)
    }
}

pub struct Link {
    input: Vec<PathBuf>,
    cflags: Vec<String>,
    ldflags: Vec<String>,
    print_output: bool,
}

impl Link {
    pub fn new<P: AsRef<Path>>(input: &[P]) -> Self {
        Link {
            input: input.iter().map(|p| PathBuf::from(p.as_ref())).collect(),
            cflags: vec![],
            ldflags: vec![],
            print_output: false,
        }
        .with_ldflag("--no-threads")
    }

    pub fn print_output(&mut self, print: bool) {
        self.print_output = print;
    }

    pub fn with_print_output(mut self, print: bool) -> Self {
        self.print_output(print);
        self
    }

    pub fn link<P: AsRef<Path>>(&self, output: P) -> Result<(), CompileError> {
        let clang = wasm_clang();
        if !clang.exists() {
            Err(CompileError::FileNotFound(
                clang.to_string_lossy().into_owned(),
            ))?;
        }
        let mut cmd = Command::new(clang);
        for input in self.input.iter() {
            if !input.exists() {
                Err(CompileError::FileNotFound(
                    input.to_string_lossy().into_owned(),
                ))?;
            }
            cmd.arg(input.clone());
        }
        cmd.arg("-o");
        cmd.arg(output.as_ref());
        for cflag in self.cflags.iter() {
            cmd.arg(cflag);
        }
        for ldflag in self.ldflags.iter() {
            cmd.arg(format!("-Wl,{}", ldflag));
        }
        let run = cmd.output().expect("clang executable exists");
        CompileError::check(run, self.print_output)
    }
}

pub trait AsLink {
    fn as_link(&mut self) -> &mut Link;
}

impl AsLink for Link {
    fn as_link(&mut self) -> &mut Link {
        self
    }
}

pub trait LinkOpts {
    fn ldflag<S: AsRef<str>>(&mut self, ldflag: S);
    fn with_ldflag<S: AsRef<str>>(self, ldflag: S) -> Self;

    fn export<S: AsRef<str>>(&mut self, export: S);
    fn with_export<S: AsRef<str>>(self, export: S) -> Self;
}

impl<T: AsLink> LinkOpts for T {
    fn ldflag<S: AsRef<str>>(&mut self, ldflag: S) {
        self.as_link().ldflags.push(ldflag.as_ref().to_owned());
    }

    fn with_ldflag<S: AsRef<str>>(mut self, ldflag: S) -> Self {
        self.ldflag(ldflag);
        self
    }

    fn export<S: AsRef<str>>(&mut self, export: S) {
        self.as_link()
            .ldflags
            .push(format!("--export={}", export.as_ref()));
    }

    fn with_export<S: AsRef<str>>(mut self, export: S) -> Self {
        self.export(export);
        self
    }
}

impl<T: AsLink> CompileOpts for T {
    fn cflag<S: AsRef<str>>(&mut self, cflag: S) {
        self.as_link().cflags.push(cflag.as_ref().to_owned());
    }

    fn with_cflag<S: AsRef<str>>(mut self, cflag: S) -> Self {
        self.cflag(cflag);
        self
    }

    fn include<S: AsRef<str>>(&mut self, include: S) {
        self.as_link()
            .cflags
            .push(format!("-I{}", include.as_ref()));
    }

    fn with_include<S: AsRef<str>>(mut self, include: S) -> Self {
        self.include(include);
        self
    }
}

pub struct Lucetc {
    link: Link,
    lucetc: lucetc::Lucetc,
    tmpdir: TempDir,
    wasm_file: PathBuf,
}

impl Lucetc {
    pub fn new<P: AsRef<Path>>(input: &[P]) -> Self {
        let link = Link::new(input);
        let tmpdir = TempDir::new().expect("temporary directory creation failed");
        let wasm_file = tmpdir.path().join("out.wasm");
        let lucetc = lucetc::Lucetc::new(&wasm_file);
        Lucetc {
            link,
            lucetc,
            tmpdir,
            wasm_file,
        }
    }

    pub fn print_output(mut self, print: bool) -> Self {
        self.link.print_output = print;
        self
    }

    pub fn build<P: AsRef<Path>>(self, output: P) -> Result<(), CompileError> {
        self.link.link(&self.wasm_file)?;
        self.lucetc
            .shared_object_file(output.as_ref())
            .map_err(|e| CompileError::Lucetc { e })?;
        Ok(self.tmpdir.close()?)
    }
}

impl AsLink for Lucetc {
    fn as_link(&mut self) -> &mut Link {
        &mut self.link
    }
}

impl lucetc::AsLucetc for Lucetc {
    fn as_lucetc(&mut self) -> &mut lucetc::Lucetc {
        &mut self.lucetc
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use tempfile::TempDir;
    #[test]
    fn wasi_sdk_installed() {
        let clang = wasm_clang();
        assert!(clang.exists(), "clang executable exists");
    }

    fn test_file(name: &str) -> PathBuf {
        let mut p = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
        p.push("test");
        p.push(name);
        assert!(p.exists(), "test file does not exist");
        p
    }

    #[test]
    fn compile_a() {
        let tmp = TempDir::new().expect("create temporary directory");

        let compiler = Compile::new(test_file("a.c"));

        let objfile = tmp.path().join("a.o");

        compiler.compile(objfile.clone()).expect("compile a.c");

        assert!(objfile.exists(), "object file created");

        let mut linker = Link::new(&[objfile]);
        linker.cflag("-nostartfiles");
        linker.ldflag("--no-entry");

        let wasmfile = tmp.path().join("a.wasm");

        linker.link(wasmfile.clone()).expect("link a.wasm");

        assert!(wasmfile.exists(), "wasm file created");
    }

    #[test]
    fn compile_b() {
        let tmp = TempDir::new().expect("create temporary directory");

        let compiler = Compile::new(test_file("b.c"));

        let objfile = tmp.path().join("b.o");

        compiler.compile(objfile.clone()).expect("compile b.c");

        assert!(objfile.exists(), "object file created");

        let mut linker = Link::new(&[objfile]);
        linker.cflag("-nostartfiles");
        linker.ldflag("--no-entry");
        linker.ldflag("--allow-undefined");

        let wasmfile = tmp.path().join("b.wasm");

        linker.link(wasmfile.clone()).expect("link b.wasm");

        assert!(wasmfile.exists(), "wasm file created");
    }

    #[test]
    fn compile_a_and_b() {
        let tmp = TempDir::new().expect("create temporary directory");

        let mut linker = Link::new(&[test_file("a.c"), test_file("b.c")]);
        linker.cflag("-nostartfiles");
        linker.ldflag("--no-entry");

        let wasmfile = tmp.path().join("ab.wasm");

        linker.link(wasmfile.clone()).expect("link ab.wasm");

        assert!(wasmfile.exists(), "wasm file created");
    }

    #[test]
    fn compile_to_lucet() {
        let tmp = TempDir::new().expect("create temporary directory");

        let mut lucetc = Lucetc::new(&[test_file("a.c"), test_file("b.c")]);
        lucetc.cflag("-nostartfiles");
        lucetc.ldflag("--no-entry");

        let so_file = tmp.path().join("ab.so");

        lucetc.build(&so_file).expect("compile ab.so");

        assert!(so_file.exists(), "so file created");
    }
}
<|endoftext|>


<commit_before>use crate::{
    channel::Reply,
    id_sequence::IdSequence,
    pinky_swear::{Cancellable, Pinky, PinkySwear},
    Error, Result,
};
use amq_protocol::frame::AMQPFrame;
use log::trace;
use parking_lot::Mutex;
use std::{
    collections::{HashMap, VecDeque},
    fmt,
    sync::Arc,
};

pub(crate) struct ExpectedReply(
    pub(crate) Reply,
    pub(crate) Box<dyn Cancellable<Error> + Send>,
);

impl fmt::Debug for ExpectedReply {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "ExpectedReply({:?})", self.0)
    }
}

pub(crate) type SendId = u64;

#[derive(Clone, Debug)]
pub(crate) enum Priority {
    NORMAL,
    CRITICAL,
}

impl Default for Priority {
    fn default() -> Self {
        Priority::NORMAL
    }
}

#[derive(Clone, Debug, Default)]
pub(crate) struct Frames {
    inner: Arc<Mutex<Inner>>,
}

impl Frames {
    pub(crate) fn push(
        &self,
        channel_id: u16,
        priority: Priority,
        frame: AMQPFrame,
        expected_reply: Option<ExpectedReply>,
    ) -> PinkySwear<Result<()>> {
        self.inner
            .lock()
            .push(channel_id, priority, frame, expected_reply)
    }

    pub(crate) fn push_frames(
        &self,
        channel_id: u16,
        frames: Vec<AMQPFrame>,
    ) -> PinkySwear<Result<()>> {
        self.inner.lock().push_frames(channel_id, frames)
    }

    pub(crate) fn retry(&self, frame: (SendId, AMQPFrame)) {
        self.inner.lock().retry(frame);
    }

    pub(crate) fn pop(&self, flow: bool) -> Option<(SendId, AMQPFrame)> {
        self.inner.lock().pop(flow)
    }

    pub(crate) fn next_expected_reply(&self, channel_id: u16) -> Option<Reply> {
        self.inner
            .lock()
            .expected_replies
            .get_mut(&channel_id)
            .and_then(|replies| replies.pop_front())
            .map(|t| t.0)
    }

    pub(crate) fn mark_sent(&self, send_id: SendId) {
        if let Some((_, pinky, _)) = self.inner.lock().outbox.remove(&send_id) {
            pinky.swear(Ok(()));
        }
    }

    pub(crate) fn has_pending(&self) -> bool {
        self.inner.lock().has_pending()
    }

    pub(crate) fn drop_pending(&self, error: Error) {
        self.inner.lock().drop_pending(error);
    }

    pub(crate) fn clear_expected_replies(&self, channel_id: u16, error: Error) {
        self.inner.lock().clear_expected_replies(channel_id, error);
    }
}

#[derive(Debug)]
struct Inner {
    /* Header frames must follow basic.publish frames directly, otherwise rabbitmq-server send us an UNEXPECTED_FRAME */
    header_frames: VecDeque<(SendId, AMQPFrame)>,
    priority_frames: VecDeque<(SendId, AMQPFrame)>,
    frames: VecDeque<(SendId, AMQPFrame)>,
    low_prio_frames: VecDeque<(SendId, AMQPFrame)>,
    expected_replies: HashMap<u16, VecDeque<ExpectedReply>>,
    outbox: HashMap<SendId, (u16, Pinky<Result<()>>, bool)>,
    send_id: IdSequence<SendId>,
}

impl Default for Inner {
    fn default() -> Self {
        Self {
            header_frames: VecDeque::default(),
            priority_frames: VecDeque::default(),
            frames: VecDeque::default(),
            low_prio_frames: VecDeque::default(),
            expected_replies: HashMap::default(),
            outbox: HashMap::default(),
            send_id: IdSequence::new(false),
        }
    }
}

impl Inner {
    fn push(
        &mut self,
        channel_id: u16,
        priority: Priority,
        frame: AMQPFrame,
        expected_reply: Option<ExpectedReply>,
    ) -> PinkySwear<Result<()>> {
        let send_id = if let Priority::CRITICAL = priority {
            0
        } else {
            self.send_id.next()
        };
        match priority {
            Priority::NORMAL => self.frames.push_back((send_id, frame)),
            Priority::CRITICAL => self.priority_frames.push_front((send_id, frame)),
        }
        let (promise, pinky) = PinkySwear::new();
        self.outbox
            .insert(send_id, (channel_id, pinky, expected_reply.is_some()));
        if let Some(reply) = expected_reply {
            trace!(
                "channel {} state is now waiting for {:?}",
                channel_id,
                reply
            );
            self.expected_replies
                .entry(channel_id)
                .or_default()
                .push_back(reply);
        }
        promise
    }

    fn push_frames(
        &mut self,
        channel_id: u16,
        mut frames: Vec<AMQPFrame>,
    ) -> PinkySwear<Result<()>> {
        let (promise, pinky) = PinkySwear::new();
        let last_frame = frames.pop();

        for frame in frames {
            self.low_prio_frames.push_back((0, frame));
        }
        if let Some(last_frame) = last_frame {
            let send_id = self.send_id.next();
            self.low_prio_frames.push_back((send_id, last_frame));
            self.outbox.insert(send_id, (channel_id, pinky, false));
        } else {
            pinky.swear(Ok(()));
        }

        promise
    }

    fn pop(&mut self, flow: bool) -> Option<(SendId, AMQPFrame)> {
        if let Some(frame) = self
            .header_frames
            .pop_front()
            .or_else(|| self.priority_frames.pop_front())
            .or_else(|| self.frames.pop_front())
        {
            return Some(frame);
        }
        if flow {
            if let Some(frame) = self.low_prio_frames.pop_front() {
                // If the next frame is a header, that means we're a basic.publish
                // Header frame needs to follow directly the basic.publish frame or
                // the AMQP server will close the connection.
                // Push the header into header_frames which is there to handle just that.
                if self
                    .low_prio_frames
                    .front()
                    .map(|(_, frame)| frame.is_header())
                    .unwrap_or(false)
                {
                    // Yes, this will always be Some(), but let's keep our unwrap() count low
                    if let Some(next_frame) = self.low_prio_frames.pop_front() {
                        self.header_frames.push_back(next_frame);
                    }
                }
                return Some(frame);
            }
        }
        None
    }

    fn retry(&mut self, frame: (SendId, AMQPFrame)) {
        if frame.1.is_header() {
            self.header_frames.push_front(frame);
        } else {
            self.priority_frames.push_back(frame);
        }
    }

    fn has_pending(&self) -> bool {
        !(self.header_frames.is_empty()
            && self.priority_frames.is_empty()
            && self.frames.is_empty()
            && self.low_prio_frames.is_empty())
    }

    fn drop_pending(&mut self, error: Error) {
        self.header_frames.clear();
        self.priority_frames.clear();
        self.frames.clear();
        self.low_prio_frames.clear();
        for (_, replies) in self.expected_replies.drain() {
            Self::cancel_expected_replies(replies, error.clone());
        }
        for (_, (_, pinky, _)) in self.outbox.drain() {
            pinky.swear(Ok(()));
        }
    }

    fn clear_expected_replies(&mut self, channel_id: u16, error: Error) {
        let mut outbox = HashMap::default();

        for (send_id, (chan_id, pinky, expects_reply)) in self.outbox.drain() {
            if chan_id == channel_id && expects_reply {
                pinky.swear(Err(error.clone()))
            } else {
                outbox.insert(send_id, (chan_id, pinky, expects_reply));
            }
        }

        self.outbox = outbox;

        if let Some(replies) = self.expected_replies.remove(&channel_id) {
            Self::cancel_expected_replies(replies, error);
        }
    }

    fn cancel_expected_replies(replies: VecDeque<ExpectedReply>, error: Error) {
        for ExpectedReply(_, cancel) in replies {
            cancel.cancel(error.clone());
        }
    }
}
<commit_msg>frames: simplify push<commit_after>use crate::{
    channel::Reply,
    id_sequence::IdSequence,
    pinky_swear::{Cancellable, Pinky, PinkySwear},
    Error, Result,
};
use amq_protocol::frame::AMQPFrame;
use log::trace;
use parking_lot::Mutex;
use std::{
    collections::{HashMap, VecDeque},
    fmt,
    sync::Arc,
};

pub(crate) struct ExpectedReply(
    pub(crate) Reply,
    pub(crate) Box<dyn Cancellable<Error> + Send>,
);

impl fmt::Debug for ExpectedReply {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "ExpectedReply({:?})", self.0)
    }
}

pub(crate) type SendId = u64;

#[derive(Clone, Debug)]
pub(crate) enum Priority {
    CRITICAL,
    NORMAL,
}

impl Default for Priority {
    fn default() -> Self {
        Priority::NORMAL
    }
}

#[derive(Clone, Debug, Default)]
pub(crate) struct Frames {
    inner: Arc<Mutex<Inner>>,
}

impl Frames {
    pub(crate) fn push(
        &self,
        channel_id: u16,
        priority: Priority,
        frame: AMQPFrame,
        expected_reply: Option<ExpectedReply>,
    ) -> PinkySwear<Result<()>> {
        self.inner
            .lock()
            .push(channel_id, priority, frame, expected_reply)
    }

    pub(crate) fn push_frames(
        &self,
        channel_id: u16,
        frames: Vec<AMQPFrame>,
    ) -> PinkySwear<Result<()>> {
        self.inner.lock().push_frames(channel_id, frames)
    }

    pub(crate) fn retry(&self, frame: (SendId, AMQPFrame)) {
        self.inner.lock().retry(frame);
    }

    pub(crate) fn pop(&self, flow: bool) -> Option<(SendId, AMQPFrame)> {
        self.inner.lock().pop(flow)
    }

    pub(crate) fn next_expected_reply(&self, channel_id: u16) -> Option<Reply> {
        self.inner
            .lock()
            .expected_replies
            .get_mut(&channel_id)
            .and_then(|replies| replies.pop_front())
            .map(|t| t.0)
    }

    pub(crate) fn mark_sent(&self, send_id: SendId) {
        if let Some((_, pinky, _)) = self.inner.lock().outbox.remove(&send_id) {
            pinky.swear(Ok(()));
        }
    }

    pub(crate) fn has_pending(&self) -> bool {
        self.inner.lock().has_pending()
    }

    pub(crate) fn drop_pending(&self, error: Error) {
        self.inner.lock().drop_pending(error);
    }

    pub(crate) fn clear_expected_replies(&self, channel_id: u16, error: Error) {
        self.inner.lock().clear_expected_replies(channel_id, error);
    }
}

#[derive(Debug)]
struct Inner {
    /* Header frames must follow basic.publish frames directly, otherwise rabbitmq-server send us an UNEXPECTED_FRAME */
    header_frames: VecDeque<(SendId, AMQPFrame)>,
    priority_frames: VecDeque<(SendId, AMQPFrame)>,
    frames: VecDeque<(SendId, AMQPFrame)>,
    low_prio_frames: VecDeque<(SendId, AMQPFrame)>,
    expected_replies: HashMap<u16, VecDeque<ExpectedReply>>,
    outbox: HashMap<SendId, (u16, Pinky<Result<()>>, bool)>,
    send_id: IdSequence<SendId>,
}

impl Default for Inner {
    fn default() -> Self {
        Self {
            header_frames: VecDeque::default(),
            priority_frames: VecDeque::default(),
            frames: VecDeque::default(),
            low_prio_frames: VecDeque::default(),
            expected_replies: HashMap::default(),
            outbox: HashMap::default(),
            send_id: IdSequence::new(false),
        }
    }
}

impl Inner {
    fn push(
        &mut self,
        channel_id: u16,
        priority: Priority,
        frame: AMQPFrame,
        expected_reply: Option<ExpectedReply>,
    ) -> PinkySwear<Result<()>> {
        let promise = match priority {
            Priority::CRITICAL => {
                self.priority_frames.push_front((0, frame));
                PinkySwear::new_with_data(Ok(()))
            }
            Priority::NORMAL => {
                let (promise, pinky) = PinkySwear::new();
                let send_id = self.send_id.next();
                self.frames.push_back((send_id, frame));
                self.outbox
                    .insert(send_id, (channel_id, pinky, expected_reply.is_some()));
                promise
            }
        };
        if let Some(reply) = expected_reply {
            trace!(
                "channel {} state is now waiting for {:?}",
                channel_id,
                reply
            );
            self.expected_replies
                .entry(channel_id)
                .or_default()
                .push_back(reply);
        }
        promise
    }

    fn push_frames(
        &mut self,
        channel_id: u16,
        mut frames: Vec<AMQPFrame>,
    ) -> PinkySwear<Result<()>> {
        let (promise, pinky) = PinkySwear::new();
        let last_frame = frames.pop();

        for frame in frames {
            self.low_prio_frames.push_back((0, frame));
        }
        if let Some(last_frame) = last_frame {
            let send_id = self.send_id.next();
            self.low_prio_frames.push_back((send_id, last_frame));
            self.outbox.insert(send_id, (channel_id, pinky, false));
        } else {
            pinky.swear(Ok(()));
        }

        promise
    }

    fn pop(&mut self, flow: bool) -> Option<(SendId, AMQPFrame)> {
        if let Some(frame) = self
            .header_frames
            .pop_front()
            .or_else(|| self.priority_frames.pop_front())
            .or_else(|| self.frames.pop_front())
        {
            return Some(frame);
        }
        if flow {
            if let Some(frame) = self.low_prio_frames.pop_front() {
                // If the next frame is a header, that means we're a basic.publish
                // Header frame needs to follow directly the basic.publish frame or
                // the AMQP server will close the connection.
                // Push the header into header_frames which is there to handle just that.
                if self
                    .low_prio_frames
                    .front()
                    .map(|(_, frame)| frame.is_header())
                    .unwrap_or(false)
                {
                    // Yes, this will always be Some(), but let's keep our unwrap() count low
                    if let Some(next_frame) = self.low_prio_frames.pop_front() {
                        self.header_frames.push_back(next_frame);
                    }
                }
                return Some(frame);
            }
        }
        None
    }

    fn retry(&mut self, frame: (SendId, AMQPFrame)) {
        if frame.1.is_header() {
            self.header_frames.push_front(frame);
        } else {
            self.priority_frames.push_back(frame);
        }
    }

    fn has_pending(&self) -> bool {
        !(self.header_frames.is_empty()
            && self.priority_frames.is_empty()
            && self.frames.is_empty()
            && self.low_prio_frames.is_empty())
    }

    fn drop_pending(&mut self, error: Error) {
        self.header_frames.clear();
        self.priority_frames.clear();
        self.frames.clear();
        self.low_prio_frames.clear();
        for (_, replies) in self.expected_replies.drain() {
            Self::cancel_expected_replies(replies, error.clone());
        }
        for (_, (_, pinky, _)) in self.outbox.drain() {
            pinky.swear(Ok(()));
        }
    }

    fn clear_expected_replies(&mut self, channel_id: u16, error: Error) {
        let mut outbox = HashMap::default();

        for (send_id, (chan_id, pinky, expects_reply)) in self.outbox.drain() {
            if chan_id == channel_id && expects_reply {
                pinky.swear(Err(error.clone()))
            } else {
                outbox.insert(send_id, (chan_id, pinky, expects_reply));
            }
        }

        self.outbox = outbox;

        if let Some(replies) = self.expected_replies.remove(&channel_id) {
            Self::cancel_expected_replies(replies, error);
        }
    }

    fn cancel_expected_replies(replies: VecDeque<ExpectedReply>, error: Error) {
        for ExpectedReply(_, cancel) in replies {
            cancel.cancel(error.clone());
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright 2015 Jonathan Anderson
 *
 * Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
 * http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
 * http://opensource.org/licenses/MIT>, at your option. This file may not be
 * copied, modified, or distributed except according to those terms.
 */

//! Dissection of Internet Protocol (IP) packets.
//!
//! This module will eventually contain dissectors for protocols in the IP suite,
//! e.g., `rshark::ip::icmp` and `rshark::ip::tcp`.
//! For now, it only handles IP headers.
//!
//! See [RFC 791](https://tools.ietf.org/html/rfc791).

use {
    Endianness,
    Error,
    NamedValue,
    Protocol,
    RawBytes,
    Result,
    Val,
    unsigned,
};

pub struct IPv4;

impl Protocol for IPv4 {
    fn short_name(&self) -> &str { "IP" }
    fn full_name(&self) -> &str { "Internet Protocol version 4" }

    fn dissect(&self, data : &[u8]) -> Result {
        if data.len() < 20 {
            return Err(Error::Underflow { expected: 20, have: data.len(),
                message: "An IP packet must be at least 20 B".to_string() })
        }

        let mut values:Vec<NamedValue> = vec![];

        // IP version (should be "4")
        let version = data[0] >> 4;
        values.push(("Version".to_string(), Ok(Val::Unsigned(version as u64))));

        // Internet Header Length (IHL): number of 32b words in header
        let words = data[0] & 0x0f;
        values.push(("IHL".to_string(), Ok(Val::Unsigned(words as u64))));

        // Differentiated Services Code Point (DSCP): RFC 2474
        let dscp = data[1] >> 2;
        values.push(("DSCP".to_string(), Ok(Val::Unsigned(dscp as u64))));

        // Explicit Congestion Notification (ECN): RFC 3168
        let ecn = data[1] & 0x03;
        values.push(("ECN".to_string(), Ok(Val::Unsigned(ecn as u64))));

        // Total length (including header)
        let length = unsigned(&data[2..4], Endianness::BigEndian);
        values.push(("Length".to_string(), length.map(|v| Val::Unsigned(v))));

        // Identification (of datagraph fragments): RFC 6864
        values.push(("Identification".to_string(), Ok(Val::Unsigned(data[8] as u64))));

        // Protocol number (assigned by IANA)
        let protocol_id = data[9];
        values.push(("Protocol".to_string(), Ok(Val::Unsigned(protocol_id as u64))));

        // Header checksum
        values.push(("Checksum".to_string(), Ok(Val::Bytes(data[10..12].to_vec()))));

        // Source and destination addresses
        let source = &data[12..16];
        values.push(("Source".to_string(), Ok(Val::Address {
            bytes: source.to_vec(),
            encoded: source.iter().map(|b| b.to_string()).collect::<Vec<_>>().join("."),
        })));

        let dest = &data[16..20];
        values.push(("Destination".to_string(), Ok(Val::Address {
            bytes: dest.to_vec(),
            encoded: dest.iter().map(|b| b.to_string()).collect::<Vec<_>>().join("."),
        })));

        // Parse the remainder according to the specified protocol.
        let remainder = &data[20..];
        let protocol = match protocol_id {
            // TODO: UDP, TCP, etc.
            _ => RawBytes::unknown_protocol(&format!["0x{:x}", protocol_id]),
        };

        values.push(("Protocol Data".to_string(), protocol.dissect(remainder)));

        Ok(Val::Subpacket(values))
    }
}
<commit_msg>Trivial: improve a map().<commit_after>/*
 * Copyright 2015 Jonathan Anderson
 *
 * Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
 * http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
 * http://opensource.org/licenses/MIT>, at your option. This file may not be
 * copied, modified, or distributed except according to those terms.
 */

//! Dissection of Internet Protocol (IP) packets.
//!
//! This module will eventually contain dissectors for protocols in the IP suite,
//! e.g., `rshark::ip::icmp` and `rshark::ip::tcp`.
//! For now, it only handles IP headers.
//!
//! See [RFC 791](https://tools.ietf.org/html/rfc791).

use {
    Endianness,
    Error,
    NamedValue,
    Protocol,
    RawBytes,
    Result,
    Val,
    unsigned,
};

pub struct IPv4;

impl Protocol for IPv4 {
    fn short_name(&self) -> &str { "IP" }
    fn full_name(&self) -> &str { "Internet Protocol version 4" }

    fn dissect(&self, data : &[u8]) -> Result {
        if data.len() < 20 {
            return Err(Error::Underflow { expected: 20, have: data.len(),
                message: "An IP packet must be at least 20 B".to_string() })
        }

        let mut values:Vec<NamedValue> = vec![];

        // IP version (should be "4")
        let version = data[0] >> 4;
        values.push(("Version".to_string(), Ok(Val::Unsigned(version as u64))));

        // Internet Header Length (IHL): number of 32b words in header
        let words = data[0] & 0x0f;
        values.push(("IHL".to_string(), Ok(Val::Unsigned(words as u64))));

        // Differentiated Services Code Point (DSCP): RFC 2474
        let dscp = data[1] >> 2;
        values.push(("DSCP".to_string(), Ok(Val::Unsigned(dscp as u64))));

        // Explicit Congestion Notification (ECN): RFC 3168
        let ecn = data[1] & 0x03;
        values.push(("ECN".to_string(), Ok(Val::Unsigned(ecn as u64))));

        // Total length (including header)
        let length = unsigned(&data[2..4], Endianness::BigEndian);
        values.push(("Length".to_string(), length.map(Val::Unsigned)));

        // Identification (of datagraph fragments): RFC 6864
        values.push(("Identification".to_string(), Ok(Val::Unsigned(data[8] as u64))));

        // Protocol number (assigned by IANA)
        let protocol_id = data[9];
        values.push(("Protocol".to_string(), Ok(Val::Unsigned(protocol_id as u64))));

        // Header checksum
        values.push(("Checksum".to_string(), Ok(Val::Bytes(data[10..12].to_vec()))));

        // Source and destination addresses
        let source = &data[12..16];
        values.push(("Source".to_string(), Ok(Val::Address {
            bytes: source.to_vec(),
            encoded: source.iter().map(|b| b.to_string()).collect::<Vec<_>>().join("."),
        })));

        let dest = &data[16..20];
        values.push(("Destination".to_string(), Ok(Val::Address {
            bytes: dest.to_vec(),
            encoded: dest.iter().map(|b| b.to_string()).collect::<Vec<_>>().join("."),
        })));

        // Parse the remainder according to the specified protocol.
        let remainder = &data[20..];
        let protocol = match protocol_id {
            // TODO: UDP, TCP, etc.
            _ => RawBytes::unknown_protocol(&format!["0x{:x}", protocol_id]),
        };

        values.push(("Protocol Data".to_string(), protocol.dissect(remainder)));

        Ok(Val::Subpacket(values))
    }
}
<|endoftext|>


<commit_before>extern crate ansi_term;
extern crate rand;

use ansi_term::Colour::*;
use rand::Rng;
use std::io;

enum Card {
    ClubsAce,      //  0
    ClubsTen,      //  1
    ClubsKing,     //  2
    ClubsQueen,    //  3
    ClubsJack,     //  4
    ClubsNine,     //  5
    ClubsEight,    //  6
    ClubsSeven,    //  7
    SpadesAce,     //  8
    SpadesTen,     //  9
    SpadesKing,    // 10
    SpadesQueen,   // 11
    SpadesJack,    // 12
    SpadesNine,    // 13
    SpadesEight,   // 14
    SpadesSeven,   // 15
    HeartsAce,     // 16
    HeartsTen,     // 17
    HeartsKing,    // 18
    HeartsQueen,   // 19
    HeartsJack,    // 20
    HeartsNine,    // 21
    HeartsEight,   // 22
    HeartsSeven,   // 23
    DiamondsAce,   // 24
    DiamondsTen,   // 25
    DiamondsKing,  // 26
    DiamondsQueen, // 27
    DiamondsJack,  // 28
    DiamondsNine,  // 29
    DiamondsEight, // 30
    DiamondsSeven, // 31
}

enum Game {
    Suit,
    Grand,
    Null,
}

enum PlayerId {
    A,
    B,
    C,
}

struct Player {
    id: u8,
    cards: Vec<u8>,
}

impl Player {
    fn print_cards(&self) {
        match self.id {
            0 => println!("player A:"),
            1 => println!("player B:"),
            2 => println!("player C:"),
            _ => panic!("Unknown player {}", self.id),
            }
        for index in 0..10 {
            print!("{}:", index);
            print_card(self.cards[index]);
        }
    }
    fn sort_cards(&mut self) {
        let mut sorted: Vec<u8> = Vec::new();
        let mut clubs: Vec<u8> = Vec::new();
        let mut spades: Vec<u8> = Vec::new();
        let mut hearts: Vec<u8> = Vec::new();
        let mut diamonds: Vec<u8> = Vec::new();
        // first find Jacks
        for n in 0..10 {
            match self.cards[n] {
                // ClubsJack
                4 => sorted.push(self.cards[n]),
                // SpadesJack
                12 => sorted.push(self.cards[n]),
                // HeartsJack
                20 => sorted.push(self.cards[n]),
                // DiamondsJack
                28 => sorted.push(self.cards[n]),
                // Clubs
                0 ... 7 => clubs.push(self.cards[n]),
                // Spades
                8 ... 15 => spades.push(self.cards[n]),
                // Hearts
                16 ... 23 => hearts.push(self.cards[n]),
                // Diamonds
                24 ... 31 => diamonds.push(self.cards[n]),
                _ => panic!("Unknown card"),
            }
        }
        clubs.sort();
        //clubs.reverse();
        spades.sort();
        //spades.reverse();
        hearts.sort();
        //hearts.reverse();
        diamonds.sort();
        //diamonds.reverse();
        // then add the suit with the highest count
        let empty: Vec<u8> = Vec::new();
        let mut highest: &Vec<u8> = ∅
        let mut max: u8 = 0u8;
        if clubs.len() > max as usize {
            max = clubs.len() as u8;
            highest = ♣
        }
        if spades.len() > max as usize {
            max = spades.len() as u8;
            highest = ♠
        }
        if hearts.len() > max as usize {
            max = hearts.len() as u8;
            highest = ♥
        }
        if diamonds.len() > max as usize {
            max = diamonds.len() as u8;
            highest = &diamonds;
        }
        // append highest
        if highest == &clubs {
            // append clubs
            for n in 0..clubs.len() {
                sorted.push(clubs[n]);
            }
        }
        if highest == &spades {
            // append spades
            for n in 0..spades.len() {
                sorted.push(spades[n]);
            }
        }
        if highest == &hearts {
            // append hearts
            for n in 0..hearts.len() {
                sorted.push(hearts[n]);
            }
        }
        if highest == &diamonds {
            // append diamonds
            for n in 0..diamonds.len() {
                sorted.push(diamonds[n]);
            }
        }
        // append others
        if highest != &clubs {
            // append clubs
            for n in 0..clubs.len() {
                sorted.push(clubs[n]);
            }
        }
        if highest != &spades {
            // append spades
            for n in 0..spades.len() {
                sorted.push(spades[n]);
            }
        }
        if highest != &hearts {
            // append hearts
            for n in 0..hearts.len() {
                sorted.push(hearts[n]);
            }
        }
        if highest != &diamonds {
            // append diamonds
            for n in 0..diamonds.len() {
                sorted.push(diamonds[n]);
            }
        }
        self.cards = sorted;
    }
}

struct PlayerBuilder {
    id: u8,
    cards: Vec<u8>,
}

impl PlayerBuilder {
    fn new() -> PlayerBuilder {
        PlayerBuilder { cards: Vec::new(), id: 3, }
    }

    fn add(&mut self, newCard: u8) -> &mut PlayerBuilder {
        self.cards.push(newCard);
        self
    }

    fn id(&mut self, newId: u8) -> &mut PlayerBuilder {
        self.id = newId;
        self
    }

    fn finalize(&self) -> Player {
        Player { id: self.id, cards: self.cards.to_vec(), }
    }
}

fn announce(player: u8) -> Game {
    Game::Suit
}

fn bid(dealer: u8) -> (u8, u8) {
    let winner: u8 = dealer;
    let highest: u8 = 18;
    // TODO
    (winner, highest)
}

fn deal(dealerId: u8) {
    let mut cards: Vec<u8> = (0..32).collect();
    // shuffle cards
    let mut upper: u8 = 32;
    let mut shuffled: Vec<u8> = Vec::new();
    for n in 0..32 {
        // randomly select card
        let pile_index: u8 = rand::thread_rng().gen_range(0, upper - n);
        // remove selected card from old pile
        let card = cards.remove(pile_index as usize);
        // add selected card to new pile
        shuffled.push(card);
    }
    // create dealer with the first 10 cards
    let mut dealer = PlayerBuilder::new()
        .id(dealerId)
        .add(shuffled[0])
        .add(shuffled[1])
        .add(shuffled[2])
        .add(shuffled[3])
        .add(shuffled[4])
        .add(shuffled[5])
        .add(shuffled[6])
        .add(shuffled[7])
        .add(shuffled[8])
        .add(shuffled[9])
        .finalize();
    // let the dealer print his own cards
    dealer.sort_cards();
    println!("");
    dealer.print_cards();
    println!("");
    // create the left player (will play first card)
    let mut left = PlayerBuilder::new()
        .id((dealerId + 1) % 3)
        .add(shuffled[10])
        .add(shuffled[11])
        .add(shuffled[12])
        .add(shuffled[13])
        .add(shuffled[14])
        .add(shuffled[15])
        .add(shuffled[16])
        .add(shuffled[17])
        .add(shuffled[18])
        .add(shuffled[19])
        .finalize();
    left.sort_cards();
    println!("");
    left.print_cards();
    println!("");
    // create the right player (will play bid first)
    let mut right = PlayerBuilder::new()
        .id((dealerId + 2) % 3)
        .add(shuffled[20])
        .add(shuffled[21])
        .add(shuffled[22])
        .add(shuffled[23])
        .add(shuffled[24])
        .add(shuffled[25])
        .add(shuffled[26])
        .add(shuffled[27])
        .add(shuffled[28])
        .add(shuffled[29])
        .finalize();
    right.sort_cards();
    println!("");
    right.print_cards();
    println!("");
    // Skat
    println!("Skat:");
    for n in 30..32 {
        print_card(shuffled[n]);
    };
    println!("");
}

fn print_card(card: u8) {
    let club    = "♣";
    let spade   = "♠";
    let heart   = "♥";
    let diamond = "♦";
    match card {
        0 => {
            let mut ace = " A".to_string();
            ace.push_str(club);
            print!("{} ", Black.bold().paint(&ace));
        },
        1 => {
            let mut ten = "10".to_string();
            ten.push_str(club);
            print!("{} ", Black.bold().paint(&ten));
        },
        2 => {
            let mut king = " K".to_string();
            king.push_str(club);
            print!("{} ", Black.bold().paint(&king));
        },
        3 => {
            let mut queen = " Q".to_string();
            queen.push_str(club);
            print!("{} ", Black.bold().paint(&queen));
        },
        4 => {
            let mut jack = " J".to_string();
            jack.push_str(club);
            print!("{} ", Black.bold().paint(&jack));
        },
        5 => {
            let mut nine = " 9".to_string();
            nine.push_str(club);
            print!("{} ", Black.bold().paint(&nine));
        },
        6 => {
            let mut eight = " 8".to_string();
            eight.push_str(club);
            print!("{} ", Black.bold().paint(&eight));
        },
        7 => {
            let mut seven = " 7".to_string();
            seven.push_str(club);
            print!("{} ", Black.bold().paint(&seven));
        },
        8 => {
            let mut ace = " A".to_string();
            ace.push_str(spade);
            print!("{} ", Green.bold().paint(&ace));
        },
        9 => {
            let mut ten = "10".to_string();
            ten.push_str(spade);
            print!("{} ", Green.bold().paint(&ten));
        },
        10 => {
            let mut king = " K".to_string();
            king.push_str(spade);
            print!("{} ", Green.bold().paint(&king));
        },
        11 => {
            let mut queen = " Q".to_string();
            queen.push_str(spade);
            print!("{} ", Green.bold().paint(&queen));
        },
        12 => {
            let mut jack = " J".to_string();
            jack.push_str(spade);
            print!("{} ", Green.bold().paint(&jack));
        },
        13 => {
            let mut nine = " 9".to_string();
            nine.push_str(spade);
            print!("{} ", Green.bold().paint(&nine));
        },
        14 => {
            let mut eight = " 8".to_string();
            eight.push_str(spade);
            print!("{} ", Green.bold().paint(&eight));
        },
        15 => {
            let mut seven = " 7".to_string();
            seven.push_str(spade);
            print!("{} ", Green.bold().paint(&seven));
        },
        16 => {
            let mut ace = " A".to_string();
            ace.push_str(heart);
            print!("{} ", Red.bold().paint(&ace));
        },
        17 => {
            let mut ten = "10".to_string();
            ten.push_str(heart);
            print!("{} ", Red.bold().paint(&ten));
        },
        18 => {
            let mut king = " K".to_string();
            king.push_str(heart);
            print!("{} ", Red.bold().paint(&king));
        },
        19 => {
            let mut queen = " Q".to_string();
            queen.push_str(heart);
            print!("{} ", Red.bold().paint(&queen));
        },
        20 => {
            let mut jack = " J".to_string();
            jack.push_str(heart);
            print!("{} ", Red.bold().paint(&jack));
        },
        21 => {
            let mut nine = " 9".to_string();
            nine.push_str(heart);
            print!("{} ", Red.bold().paint(&nine));
        },
        22 => {
            let mut eight = " 8".to_string();
            eight.push_str(heart);
            print!("{} ", Red.bold().paint(&eight));
        },
        23 => {
            let mut seven = " 7".to_string();
            seven.push_str(heart);
            print!("{} ", Red.bold().paint(&seven));
        },
        24 => {
            let mut ace = " A".to_string();
            ace.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&ace));
        },
        25 => {
            let mut ten = "10".to_string();
            ten.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&ten));
        },
        26 => {
            let mut king = " K".to_string();
            king.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&king));
        },
        27 => {
            let mut queen = " Q".to_string();
            queen.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&queen));
        },
        28 => {
            let mut jack = " J".to_string();
            jack.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&jack));
        },
        29 => {
            let mut nine = " 9".to_string();
            nine.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&nine));
        },
        30 => {
            let mut eight = " 8".to_string();
            eight.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&eight));
        },
        31 => {
            let mut seven = " 7".to_string();
            seven.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&seven));
        },
        _ => panic!("Unknown card"),
    }
}

fn main() {
    // randomly select player
    let player_id: u8 = rand::thread_rng().gen_range(0, 3);
    loop {
        // player with player_id is dealing
        deal(player_id);
        // bid
        let (player, bid) = bid(player_id);
        // announce
        let game = announce(player);
        // play 10 tricks in a row
        for trick in 0..10 {
            println!("trick #{}:", trick);
            // ask for input
            let mut input = String::new();
            io::stdin().read_line(&mut input)
                .ok()
                .expect("failed to read line");
            let input: u8 = match input.trim().parse() {
                Ok(num) => num,
                Err(_) => break,
            };
            // is input valid?
        };
        println!("New game?");
        let mut input = String::new();
        io::stdin().read_line(&mut input)
            .ok()
            .expect("failed to read line");
        let input: u8 = match input.trim().parse() {
            Ok(num) => num,
            Err(_) => break,
        };
        println!("your input: {}", input);
        if input != 1 {
            break;
        }
    }
}
<commit_msg>Let deal() be responsible for creating all players.<commit_after>extern crate ansi_term;
extern crate rand;

use ansi_term::Colour::*;
use rand::Rng;
use std::io;

enum Card {
    ClubsAce,      //  0
    ClubsTen,      //  1
    ClubsKing,     //  2
    ClubsQueen,    //  3
    ClubsJack,     //  4
    ClubsNine,     //  5
    ClubsEight,    //  6
    ClubsSeven,    //  7
    SpadesAce,     //  8
    SpadesTen,     //  9
    SpadesKing,    // 10
    SpadesQueen,   // 11
    SpadesJack,    // 12
    SpadesNine,    // 13
    SpadesEight,   // 14
    SpadesSeven,   // 15
    HeartsAce,     // 16
    HeartsTen,     // 17
    HeartsKing,    // 18
    HeartsQueen,   // 19
    HeartsJack,    // 20
    HeartsNine,    // 21
    HeartsEight,   // 22
    HeartsSeven,   // 23
    DiamondsAce,   // 24
    DiamondsTen,   // 25
    DiamondsKing,  // 26
    DiamondsQueen, // 27
    DiamondsJack,  // 28
    DiamondsNine,  // 29
    DiamondsEight, // 30
    DiamondsSeven, // 31
}

enum Game {
    Suit,
    Grand,
    Null,
}

enum PlayerId {
    A,
    B,
    C,
}

struct Player {
    id: u8,
    cards: Vec<u8>,
}

impl Player {
    fn print_cards(&self) {
        match self.id {
            0 => println!("player A:"),
            1 => println!("player B:"),
            2 => println!("player C:"),
            _ => panic!("Unknown player {}", self.id),
            }
        for index in 0..10 {
            print!("{}:", index);
            print_card(self.cards[index]);
        }
    }
    fn sort_cards(&mut self) {
        let mut sorted: Vec<u8> = Vec::new();
        let mut clubs: Vec<u8> = Vec::new();
        let mut spades: Vec<u8> = Vec::new();
        let mut hearts: Vec<u8> = Vec::new();
        let mut diamonds: Vec<u8> = Vec::new();
        // first find Jacks
        for n in 0..10 {
            match self.cards[n] {
                // ClubsJack
                4 => sorted.push(self.cards[n]),
                // SpadesJack
                12 => sorted.push(self.cards[n]),
                // HeartsJack
                20 => sorted.push(self.cards[n]),
                // DiamondsJack
                28 => sorted.push(self.cards[n]),
                // Clubs
                0 ... 7 => clubs.push(self.cards[n]),
                // Spades
                8 ... 15 => spades.push(self.cards[n]),
                // Hearts
                16 ... 23 => hearts.push(self.cards[n]),
                // Diamonds
                24 ... 31 => diamonds.push(self.cards[n]),
                _ => panic!("Unknown card"),
            }
        }
        clubs.sort();
        //clubs.reverse();
        spades.sort();
        //spades.reverse();
        hearts.sort();
        //hearts.reverse();
        diamonds.sort();
        //diamonds.reverse();
        // then add the suit with the highest count
        let empty: Vec<u8> = Vec::new();
        let mut highest: &Vec<u8> = ∅
        let mut max: u8 = 0u8;
        if clubs.len() > max as usize {
            max = clubs.len() as u8;
            highest = ♣
        }
        if spades.len() > max as usize {
            max = spades.len() as u8;
            highest = ♠
        }
        if hearts.len() > max as usize {
            max = hearts.len() as u8;
            highest = ♥
        }
        if diamonds.len() > max as usize {
            max = diamonds.len() as u8;
            highest = &diamonds;
        }
        // append highest
        if highest == &clubs {
            // append clubs
            for n in 0..clubs.len() {
                sorted.push(clubs[n]);
            }
        }
        if highest == &spades {
            // append spades
            for n in 0..spades.len() {
                sorted.push(spades[n]);
            }
        }
        if highest == &hearts {
            // append hearts
            for n in 0..hearts.len() {
                sorted.push(hearts[n]);
            }
        }
        if highest == &diamonds {
            // append diamonds
            for n in 0..diamonds.len() {
                sorted.push(diamonds[n]);
            }
        }
        // append others
        if highest != &clubs {
            // append clubs
            for n in 0..clubs.len() {
                sorted.push(clubs[n]);
            }
        }
        if highest != &spades {
            // append spades
            for n in 0..spades.len() {
                sorted.push(spades[n]);
            }
        }
        if highest != &hearts {
            // append hearts
            for n in 0..hearts.len() {
                sorted.push(hearts[n]);
            }
        }
        if highest != &diamonds {
            // append diamonds
            for n in 0..diamonds.len() {
                sorted.push(diamonds[n]);
            }
        }
        self.cards = sorted;
    }
}

struct PlayerBuilder {
    id: u8,
    cards: Vec<u8>,
}

impl PlayerBuilder {
    fn new() -> PlayerBuilder {
        PlayerBuilder { cards: Vec::new(), id: 3, }
    }

    fn add(&mut self, newCard: u8) -> &mut PlayerBuilder {
        self.cards.push(newCard);
        self
    }

    fn id(&mut self, newId: u8) -> &mut PlayerBuilder {
        self.id = newId;
        self
    }

    fn finalize(&self) -> Player {
        Player { id: self.id, cards: self.cards.to_vec(), }
    }
}

fn announce(player: u8) -> Game {
    Game::Suit
}

fn bid(dealer: u8) -> (u8, u8) {
    let winner: u8 = dealer;
    let highest: u8 = 18;
    // TODO
    (winner, highest)
}

fn deal(dealerId: u8) -> (Player, Player, Player) {
    let mut cards: Vec<u8> = (0..32).collect();
    // shuffle cards
    let mut upper: u8 = 32;
    let mut shuffled: Vec<u8> = Vec::new();
    for n in 0..32 {
        // randomly select card
        let pile_index: u8 = rand::thread_rng().gen_range(0, upper - n);
        // remove selected card from old pile
        let card = cards.remove(pile_index as usize);
        // add selected card to new pile
        shuffled.push(card);
    }
    // create dealer with the first 10 cards
    let mut dealer = PlayerBuilder::new()
        .id(dealerId)
        .add(shuffled[0])
        .add(shuffled[1])
        .add(shuffled[2])
        .add(shuffled[3])
        .add(shuffled[4])
        .add(shuffled[5])
        .add(shuffled[6])
        .add(shuffled[7])
        .add(shuffled[8])
        .add(shuffled[9])
        .finalize();
    // let the dealer print his own cards
    dealer.sort_cards();
    println!("");
    dealer.print_cards();
    println!("");
    // create the left player (will play first card)
    let mut left = PlayerBuilder::new()
        .id((dealerId + 1) % 3)
        .add(shuffled[10])
        .add(shuffled[11])
        .add(shuffled[12])
        .add(shuffled[13])
        .add(shuffled[14])
        .add(shuffled[15])
        .add(shuffled[16])
        .add(shuffled[17])
        .add(shuffled[18])
        .add(shuffled[19])
        .finalize();
    left.sort_cards();
    println!("");
    left.print_cards();
    println!("");
    // create the right player (will play bid first)
    let mut right = PlayerBuilder::new()
        .id((dealerId + 2) % 3)
        .add(shuffled[20])
        .add(shuffled[21])
        .add(shuffled[22])
        .add(shuffled[23])
        .add(shuffled[24])
        .add(shuffled[25])
        .add(shuffled[26])
        .add(shuffled[27])
        .add(shuffled[28])
        .add(shuffled[29])
        .finalize();
    right.sort_cards();
    println!("");
    right.print_cards();
    println!("");
    // Skat
    println!("Skat:");
    for n in 30..32 {
        print_card(shuffled[n]);
    };
    println!("");
    (dealer, left, right)
}

fn print_card(card: u8) {
    let club    = "♣";
    let spade   = "♠";
    let heart   = "♥";
    let diamond = "♦";
    match card {
        0 => {
            let mut ace = " A".to_string();
            ace.push_str(club);
            print!("{} ", Black.bold().paint(&ace));
        },
        1 => {
            let mut ten = "10".to_string();
            ten.push_str(club);
            print!("{} ", Black.bold().paint(&ten));
        },
        2 => {
            let mut king = " K".to_string();
            king.push_str(club);
            print!("{} ", Black.bold().paint(&king));
        },
        3 => {
            let mut queen = " Q".to_string();
            queen.push_str(club);
            print!("{} ", Black.bold().paint(&queen));
        },
        4 => {
            let mut jack = " J".to_string();
            jack.push_str(club);
            print!("{} ", Black.bold().paint(&jack));
        },
        5 => {
            let mut nine = " 9".to_string();
            nine.push_str(club);
            print!("{} ", Black.bold().paint(&nine));
        },
        6 => {
            let mut eight = " 8".to_string();
            eight.push_str(club);
            print!("{} ", Black.bold().paint(&eight));
        },
        7 => {
            let mut seven = " 7".to_string();
            seven.push_str(club);
            print!("{} ", Black.bold().paint(&seven));
        },
        8 => {
            let mut ace = " A".to_string();
            ace.push_str(spade);
            print!("{} ", Green.bold().paint(&ace));
        },
        9 => {
            let mut ten = "10".to_string();
            ten.push_str(spade);
            print!("{} ", Green.bold().paint(&ten));
        },
        10 => {
            let mut king = " K".to_string();
            king.push_str(spade);
            print!("{} ", Green.bold().paint(&king));
        },
        11 => {
            let mut queen = " Q".to_string();
            queen.push_str(spade);
            print!("{} ", Green.bold().paint(&queen));
        },
        12 => {
            let mut jack = " J".to_string();
            jack.push_str(spade);
            print!("{} ", Green.bold().paint(&jack));
        },
        13 => {
            let mut nine = " 9".to_string();
            nine.push_str(spade);
            print!("{} ", Green.bold().paint(&nine));
        },
        14 => {
            let mut eight = " 8".to_string();
            eight.push_str(spade);
            print!("{} ", Green.bold().paint(&eight));
        },
        15 => {
            let mut seven = " 7".to_string();
            seven.push_str(spade);
            print!("{} ", Green.bold().paint(&seven));
        },
        16 => {
            let mut ace = " A".to_string();
            ace.push_str(heart);
            print!("{} ", Red.bold().paint(&ace));
        },
        17 => {
            let mut ten = "10".to_string();
            ten.push_str(heart);
            print!("{} ", Red.bold().paint(&ten));
        },
        18 => {
            let mut king = " K".to_string();
            king.push_str(heart);
            print!("{} ", Red.bold().paint(&king));
        },
        19 => {
            let mut queen = " Q".to_string();
            queen.push_str(heart);
            print!("{} ", Red.bold().paint(&queen));
        },
        20 => {
            let mut jack = " J".to_string();
            jack.push_str(heart);
            print!("{} ", Red.bold().paint(&jack));
        },
        21 => {
            let mut nine = " 9".to_string();
            nine.push_str(heart);
            print!("{} ", Red.bold().paint(&nine));
        },
        22 => {
            let mut eight = " 8".to_string();
            eight.push_str(heart);
            print!("{} ", Red.bold().paint(&eight));
        },
        23 => {
            let mut seven = " 7".to_string();
            seven.push_str(heart);
            print!("{} ", Red.bold().paint(&seven));
        },
        24 => {
            let mut ace = " A".to_string();
            ace.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&ace));
        },
        25 => {
            let mut ten = "10".to_string();
            ten.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&ten));
        },
        26 => {
            let mut king = " K".to_string();
            king.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&king));
        },
        27 => {
            let mut queen = " Q".to_string();
            queen.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&queen));
        },
        28 => {
            let mut jack = " J".to_string();
            jack.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&jack));
        },
        29 => {
            let mut nine = " 9".to_string();
            nine.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&nine));
        },
        30 => {
            let mut eight = " 8".to_string();
            eight.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&eight));
        },
        31 => {
            let mut seven = " 7".to_string();
            seven.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&seven));
        },
        _ => panic!("Unknown card"),
    }
}

fn main() {
    // randomly select player
    let player_id: u8 = rand::thread_rng().gen_range(0, 3);
    loop {
        // player with player_id is dealing
        let (dealer,
             responder,
             bidder) = deal(player_id);
        // bid
        let (player, bid) = bid(player_id);
        // announce
        let game = announce(player);
        // play 10 tricks in a row
        for trick in 0..10 {
            println!("trick #{}:", trick);
            // ask for input
            let mut input = String::new();
            io::stdin().read_line(&mut input)
                .ok()
                .expect("failed to read line");
            let input: u8 = match input.trim().parse() {
                Ok(num) => num,
                Err(_) => break,
            };
            // is input valid?
        };
        println!("New game?");
        let mut input = String::new();
        io::stdin().read_line(&mut input)
            .ok()
            .expect("failed to read line");
        let input: u8 = match input.trim().parse() {
            Ok(num) => num,
            Err(_) => break,
        };
        println!("your input: {}", input);
        if input != 1 {
            break;
        }
    }
}
<|endoftext|>