<commit_before>use std::rc::Rc;
use std::cell::RefCell;
use communication::Communicator;

use progress::frontier::MutableAntichain;
use progress::{Timestamp, Graph, Scope};

use progress::count_map::CountMap;
use progress::nested::scope_wrapper::ScopeWrapper;
use progress::nested::product::Product;
use progress::nested::*;

// Builder is intended to act as a guard for subgraph assembly.
// It wraps a subgraph and a reference to its parent, proxying many of their methods.
// At disposal time it is capable of adding to the parent the subgraph boxed as a scope.
// This might be do-able with Drop, but it currently ICEs. Instead, called seal().

// TODO : It may be more ergonomic to have parent: RefCell<&'b mut G>, owning the reference.
// TODO : This avoids a second object and scope when writing code, but introduces the issue that
// TODO : by owning the &'b mut G outer uses of an &'a RefCell<&'b mut G> result in runtime panics.
// TODO : In particular, this requires care on scope entrance, so that the scope does the logic
// TODO : rather than the stream itself, whose Rc<&'b mut G> may be acquired by the scope.

// TODO : It seems plausible that the Graph interface could expose only methods that do not borrow,
// TODO : so that any .borrow_mut().method() would avoid runtime panics if we did not do the above.

pub struct Builder<'a, G: Graph+'a, TInner: Timestamp> {
    subgraph: Option<Subgraph<G::Timestamp, TInner>>,
    parent:   &'a RefCell<G>,
}

impl<'a, G: Graph+'a, TInner: Timestamp> Builder<'a, G, TInner> {
    pub fn new(parent: &'a RefCell<G>) -> Builder<'a, G, TInner> {
        let subgraph = parent.borrow_mut().new_subgraph::<TInner>();
        Builder {
            subgraph: Some(subgraph),
            parent: parent,
        }
    }
    pub fn index(&self) -> u64 { self.subgraph.as_ref().unwrap().index }
    pub fn parent(&self) -> &'a RefCell<G> { self.parent }
    pub fn new_input(&mut self, shared_counts: Rc<RefCell<CountMap<Product<G::Timestamp, TInner>>>>) -> u64 {
        self.subgraph.as_mut().unwrap().inputs += 1;
        self.subgraph.as_mut().unwrap().external_guarantee.push(MutableAntichain::new());
        self.subgraph.as_mut().unwrap().input_messages.push(shared_counts);
        return self.subgraph.as_mut().unwrap().inputs - 1;
    }

    pub fn new_output(&mut self) -> u64 {
        self.subgraph.as_mut().unwrap().outputs += 1;
        self.subgraph.as_mut().unwrap().external_capability.push(MutableAntichain::new());
        return self.subgraph.as_mut().unwrap().outputs - 1;
    }
    pub fn seal(&mut self) {
        // TODO : Comment me out for ICE (step 1/2)
        self.parent.borrow_mut().add_scope(self.subgraph.take().unwrap());
    }
}

impl<'a, TInner: Timestamp, G: Graph+'a> Graph for Builder<'a, G, TInner> {
    type Timestamp = Product<G::Timestamp, TInner>;
    type Communicator = G::Communicator;

    fn connect(&mut self, source: Source, target: Target) {
        self.subgraph.as_mut().unwrap().connect(source, target);
    }
    fn add_boxed_scope(&mut self, scope: Box<Scope<Product<G::Timestamp, TInner>>>) -> u64 {
        let index = self.subgraph.as_ref().unwrap().children.len() as u64;
        self.subgraph.as_mut().unwrap().children.push(ScopeWrapper::new(scope, index));
        index
    }

    fn new_subgraph<T: Timestamp>(&mut self) -> Subgraph<Product<G::Timestamp, TInner>, T> {
        let index = self.subgraph.as_ref().unwrap().children() as u64;
        self.parent.borrow_mut().with_communicator(|x| Subgraph::new_from(x, index))
    }

    fn with_communicator<R, F: FnOnce(&mut Self::Communicator)->R>(&mut self, func: F) -> R {
        self.parent.borrow_mut().with_communicator(func)
    }

    fn builder(&mut self) -> RefCell<&mut Self> { RefCell::new(self) }
}

// TODO : Uncomment me for ICE (step 2/2)
// impl<'a, 'b: 'a, TInner: Timestamp, G: Graph+'b> Drop for SubgraphBuilder<'a, 'b, G, TInner> {
//     fn drop(&mut self) { self.parent.borrow_mut().add_scope(self.subgraph.take().unwrap()); }
// }
<commit_msg>Make .seal take the nested builder by value and stop wrapping the Subgraph in Option.<commit_after>use std::rc::Rc;
use std::cell::RefCell;
use communication::Communicator;

use progress::frontier::MutableAntichain;
use progress::{Timestamp, Graph, Scope};

use progress::count_map::CountMap;
use progress::nested::scope_wrapper::ScopeWrapper;
use progress::nested::product::Product;
use progress::nested::*;

// Builder is intended to act as a guard for subgraph assembly.
// It wraps a subgraph and a reference to its parent, proxying many of their methods.
// At disposal time it is capable of adding to the parent the subgraph boxed as a scope.
// This might be do-able with Drop, but it currently ICEs. Instead, called seal().

// TODO : It may be more ergonomic to have parent: RefCell<&'b mut G>, owning the reference.
// TODO : This avoids a second object and scope when writing code, but introduces the issue that
// TODO : by owning the &'b mut G outer uses of an &'a RefCell<&'b mut G> result in runtime panics.
// TODO : In particular, this requires care on scope entrance, so that the scope does the logic
// TODO : rather than the stream itself, whose Rc<&'b mut G> may be acquired by the scope.

// TODO : It seems plausible that the Graph interface could expose only methods that do not borrow,
// TODO : so that any .borrow_mut().method() would avoid runtime panics if we did not do the above.

pub struct Builder<'a, G: Graph+'a, TInner: Timestamp> {
    subgraph: Subgraph<G::Timestamp, TInner>,
    parent:   &'a RefCell<G>,
}

impl<'a, G: Graph+'a, TInner: Timestamp> Builder<'a, G, TInner> {
    pub fn new(parent: &'a RefCell<G>) -> Builder<'a, G, TInner> {
        let subgraph = parent.borrow_mut().new_subgraph::<TInner>();
        Builder {
            subgraph: subgraph,
            parent: parent,
        }
    }
    pub fn index(&self) -> u64 { self.subgraph.index }
    pub fn parent(&self) -> &'a RefCell<G> { self.parent }
    pub fn new_input(&mut self, shared_counts: Rc<RefCell<CountMap<Product<G::Timestamp, TInner>>>>) -> u64 {
        self.subgraph.inputs += 1;
        self.subgraph.external_guarantee.push(MutableAntichain::new());
        self.subgraph.input_messages.push(shared_counts);
        return self.subgraph.inputs - 1;
    }

    pub fn new_output(&mut self) -> u64 {
        self.subgraph.outputs += 1;
        self.subgraph.external_capability.push(MutableAntichain::new());
        return self.subgraph.outputs - 1;
    }

    pub fn seal(self) {
        // TODO : Comment me out for ICE (step 1/2)
        self.parent.borrow_mut().add_scope(self.subgraph);
    }
}

impl<'a, TInner: Timestamp, G: Graph+'a> Graph for Builder<'a, G, TInner> {
    type Timestamp = Product<G::Timestamp, TInner>;
    type Communicator = G::Communicator;

    fn connect(&mut self, source: Source, target: Target) {
        self.subgraph.connect(source, target);
    }
    fn add_boxed_scope(&mut self, scope: Box<Scope<Product<G::Timestamp, TInner>>>) -> u64 {
        let index = self.subgraph.children.len() as u64;
        self.subgraph.children.push(ScopeWrapper::new(scope, index));
        index
    }

    fn new_subgraph<T: Timestamp>(&mut self) -> Subgraph<Product<G::Timestamp, TInner>, T> {
        let index = self.subgraph.children() as u64;
        self.parent.borrow_mut().with_communicator(|x| Subgraph::new_from(x, index))
    }

    fn with_communicator<R, F: FnOnce(&mut Self::Communicator)->R>(&mut self, func: F) -> R {
        self.parent.borrow_mut().with_communicator(func)
    }
}

// TODO : Uncomment me for ICE (step 2/2)
// impl<'a, 'b: 'a, TInner: Timestamp, G: Graph+'b> Drop for SubgraphBuilder<'a, 'b, G, TInner> {
//     fn drop(&mut self) { self.parent.borrow_mut().add_scope(self.subgraph.take().unwrap()); }
// }
<|endoftext|>


<commit_before>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.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.

//! Implementation of the install aspects of the compiler.
//!
//! This module is responsible for installing the standard library,
//! compiler, and documentation.

use std::env;
use std::fs;
use std::path::{Path, PathBuf, Component};
use std::process::Command;

use dist::{self, pkgname, sanitize_sh, tmpdir};

use builder::{Builder, RunConfig, ShouldRun, Step};
use cache::Interned;

pub fn install_docs(builder: &Builder, stage: u32, host: Interned<String>) {
    install_sh(builder, "docs", "rust-docs", stage, Some(host));
}

pub fn install_std(builder: &Builder, stage: u32) {
    for target in &builder.build.targets {
        install_sh(builder, "std", "rust-std", stage, Some(*target));
    }
}

pub fn install_cargo(builder: &Builder, stage: u32, host: Interned<String>) {
    install_sh(builder, "cargo", "cargo", stage, Some(host));
}

pub fn install_rls(builder: &Builder, stage: u32, host: Interned<String>) {
    install_sh(builder, "rls", "rls", stage, Some(host));
}

pub fn install_analysis(builder: &Builder, stage: u32, host: Interned<String>) {
    install_sh(builder, "analysis", "rust-analysis", stage, Some(host));
}

pub fn install_src(builder: &Builder, stage: u32) {
    install_sh(builder, "src", "rust-src", stage, None);
}
pub fn install_rustc(builder: &Builder, stage: u32, host: Interned<String>) {
    install_sh(builder, "rustc", "rustc", stage, Some(host));
}

fn install_sh(
    builder: &Builder,
    package: &str,
    name: &str,
    stage: u32,
    host: Option<Interned<String>>
) {
    let build = builder.build;
    println!("Install {} stage{} ({:?})", package, stage, host);

    let prefix_default = PathBuf::from("/usr/local");
    let sysconfdir_default = PathBuf::from("/etc");
    let docdir_default = PathBuf::from("share/doc/rust");
    let bindir_default = PathBuf::from("bin");
    let libdir_default = PathBuf::from("lib");
    let mandir_default = PathBuf::from("share/man");
    let prefix = build.config.prefix.as_ref().unwrap_or(&prefix_default);
    let sysconfdir = build.config.sysconfdir.as_ref().unwrap_or(&sysconfdir_default);
    let docdir = build.config.docdir.as_ref().unwrap_or(&docdir_default);
    let bindir = build.config.bindir.as_ref().unwrap_or(&bindir_default);
    let libdir = build.config.libdir.as_ref().unwrap_or(&libdir_default);
    let mandir = build.config.mandir.as_ref().unwrap_or(&mandir_default);

    let sysconfdir = prefix.join(sysconfdir);
    let docdir = prefix.join(docdir);
    let bindir = prefix.join(bindir);
    let libdir = prefix.join(libdir);
    let mandir = prefix.join(mandir);

    let destdir = env::var_os("DESTDIR").map(PathBuf::from);

    let prefix = add_destdir(&prefix, &destdir);
    let sysconfdir = add_destdir(&sysconfdir, &destdir);
    let docdir = add_destdir(&docdir, &destdir);
    let bindir = add_destdir(&bindir, &destdir);
    let libdir = add_destdir(&libdir, &destdir);
    let mandir = add_destdir(&mandir, &destdir);

    let empty_dir = build.out.join("tmp/empty_dir");

    t!(fs::create_dir_all(&empty_dir));
    let package_name = if let Some(host) = host {
        format!("{}-{}", pkgname(build, name), host)
    } else {
        pkgname(build, name)
    };

    let mut cmd = Command::new("sh");
    cmd.current_dir(&empty_dir)
        .arg(sanitize_sh(&tmpdir(build).join(&package_name).join("install.sh")))
        .arg(format!("--prefix={}", sanitize_sh(&prefix)))
        .arg(format!("--sysconfdir={}", sanitize_sh(&sysconfdir)))
        .arg(format!("--docdir={}", sanitize_sh(&docdir)))
        .arg(format!("--bindir={}", sanitize_sh(&bindir)))
        .arg(format!("--libdir={}", sanitize_sh(&libdir)))
        .arg(format!("--mandir={}", sanitize_sh(&mandir)))
        .arg("--disable-ldconfig");
    build.run(&mut cmd);
    t!(fs::remove_dir_all(&empty_dir));
}

fn add_destdir(path: &Path, destdir: &Option<PathBuf>) -> PathBuf {
    let mut ret = match *destdir {
        Some(ref dest) => dest.clone(),
        None => return path.to_path_buf(),
    };
    for part in path.components() {
        match part {
            Component::Normal(s) => ret.push(s),
            _ => {}
        }
    }
    ret
}

macro_rules! install {
    (($sel:ident, $builder:ident, $_config:ident),
       $($name:ident,
       $path:expr,
       $default_cond:expr,
       only_hosts: $only_hosts:expr,
       $run_item:block $(, $c:ident)*;)+) => {
        $(
            #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
        pub struct $name {
            pub stage: u32,
            pub target: Interned<String>,
            pub host: Interned<String>,
        }

        impl Step for $name {
            type Output = ();
            const DEFAULT: bool = true;
            const ONLY_BUILD_TARGETS: bool = true;
            const ONLY_HOSTS: bool = $only_hosts;
            $(const $c: bool = true;)*

            fn should_run(run: ShouldRun) -> ShouldRun {
                let $_config = &run.builder.config;
                run.path($path).default_condition($default_cond)
            }

            fn make_run(run: RunConfig) {
                run.builder.ensure($name {
                    stage: run.builder.top_stage,
                    target: run.target,
                    host: run.host,
                });
            }

            fn run($sel, $builder: &Builder) {
                $run_item
            }
        })+
    }
}

install!((self, builder, _config),
    Docs, "src/doc", _config.docs, only_hosts: false, {
        builder.ensure(dist::Docs { stage: self.stage, host: self.target });
        install_docs(builder, self.stage, self.target);
    };
    Std, "src/libstd", true, only_hosts: true, {
        builder.ensure(dist::Std {
            compiler: builder.compiler(self.stage, self.host),
            target: self.target
        });
        install_std(builder, self.stage);
    };
    Cargo, "cargo", _config.extended, only_hosts: true, {
        builder.ensure(dist::Cargo { stage: self.stage, target: self.target });
        install_cargo(builder, self.stage, self.target);
    };
    Rls, "rls", _config.extended, only_hosts: true, {
        builder.ensure(dist::Rls { stage: self.stage, target: self.target });
        install_rls(builder, self.stage, self.target);
    };
    Analysis, "analysis", _config.extended, only_hosts: false, {
        builder.ensure(dist::Analysis {
            compiler: builder.compiler(self.stage, self.host),
            target: self.target
        });
        install_analysis(builder, self.stage, self.target);
    };
    Src, "src", _config.extended, only_hosts: true, {
        builder.ensure(dist::Src);
        install_src(builder, self.stage);
    }, ONLY_BUILD;
    Rustc, "src/librustc", true, only_hosts: true, {
        builder.ensure(dist::Rustc {
            compiler: builder.compiler(self.stage, self.target),
        });
        install_rustc(builder, self.stage, self.target);
    };
);
<commit_msg>Auto merge of #45322 - infinity0:master, r=alexcrichton<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.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.

//! Implementation of the install aspects of the compiler.
//!
//! This module is responsible for installing the standard library,
//! compiler, and documentation.

use std::env;
use std::fs;
use std::path::{Path, PathBuf, Component};
use std::process::Command;

use dist::{self, pkgname, sanitize_sh, tmpdir};

use builder::{Builder, RunConfig, ShouldRun, Step};
use cache::Interned;

pub fn install_docs(builder: &Builder, stage: u32, host: Interned<String>) {
    install_sh(builder, "docs", "rust-docs", stage, Some(host));
}

pub fn install_std(builder: &Builder, stage: u32, target: Interned<String>) {
    install_sh(builder, "std", "rust-std", stage, Some(target));
}

pub fn install_cargo(builder: &Builder, stage: u32, host: Interned<String>) {
    install_sh(builder, "cargo", "cargo", stage, Some(host));
}

pub fn install_rls(builder: &Builder, stage: u32, host: Interned<String>) {
    install_sh(builder, "rls", "rls", stage, Some(host));
}

pub fn install_analysis(builder: &Builder, stage: u32, host: Interned<String>) {
    install_sh(builder, "analysis", "rust-analysis", stage, Some(host));
}

pub fn install_src(builder: &Builder, stage: u32) {
    install_sh(builder, "src", "rust-src", stage, None);
}
pub fn install_rustc(builder: &Builder, stage: u32, host: Interned<String>) {
    install_sh(builder, "rustc", "rustc", stage, Some(host));
}

fn install_sh(
    builder: &Builder,
    package: &str,
    name: &str,
    stage: u32,
    host: Option<Interned<String>>
) {
    let build = builder.build;
    println!("Install {} stage{} ({:?})", package, stage, host);

    let prefix_default = PathBuf::from("/usr/local");
    let sysconfdir_default = PathBuf::from("/etc");
    let docdir_default = PathBuf::from("share/doc/rust");
    let bindir_default = PathBuf::from("bin");
    let libdir_default = PathBuf::from("lib");
    let mandir_default = PathBuf::from("share/man");
    let prefix = build.config.prefix.as_ref().unwrap_or(&prefix_default);
    let sysconfdir = build.config.sysconfdir.as_ref().unwrap_or(&sysconfdir_default);
    let docdir = build.config.docdir.as_ref().unwrap_or(&docdir_default);
    let bindir = build.config.bindir.as_ref().unwrap_or(&bindir_default);
    let libdir = build.config.libdir.as_ref().unwrap_or(&libdir_default);
    let mandir = build.config.mandir.as_ref().unwrap_or(&mandir_default);

    let sysconfdir = prefix.join(sysconfdir);
    let docdir = prefix.join(docdir);
    let bindir = prefix.join(bindir);
    let libdir = prefix.join(libdir);
    let mandir = prefix.join(mandir);

    let destdir = env::var_os("DESTDIR").map(PathBuf::from);

    let prefix = add_destdir(&prefix, &destdir);
    let sysconfdir = add_destdir(&sysconfdir, &destdir);
    let docdir = add_destdir(&docdir, &destdir);
    let bindir = add_destdir(&bindir, &destdir);
    let libdir = add_destdir(&libdir, &destdir);
    let mandir = add_destdir(&mandir, &destdir);

    let empty_dir = build.out.join("tmp/empty_dir");

    t!(fs::create_dir_all(&empty_dir));
    let package_name = if let Some(host) = host {
        format!("{}-{}", pkgname(build, name), host)
    } else {
        pkgname(build, name)
    };

    let mut cmd = Command::new("sh");
    cmd.current_dir(&empty_dir)
        .arg(sanitize_sh(&tmpdir(build).join(&package_name).join("install.sh")))
        .arg(format!("--prefix={}", sanitize_sh(&prefix)))
        .arg(format!("--sysconfdir={}", sanitize_sh(&sysconfdir)))
        .arg(format!("--docdir={}", sanitize_sh(&docdir)))
        .arg(format!("--bindir={}", sanitize_sh(&bindir)))
        .arg(format!("--libdir={}", sanitize_sh(&libdir)))
        .arg(format!("--mandir={}", sanitize_sh(&mandir)))
        .arg("--disable-ldconfig");
    build.run(&mut cmd);
    t!(fs::remove_dir_all(&empty_dir));
}

fn add_destdir(path: &Path, destdir: &Option<PathBuf>) -> PathBuf {
    let mut ret = match *destdir {
        Some(ref dest) => dest.clone(),
        None => return path.to_path_buf(),
    };
    for part in path.components() {
        match part {
            Component::Normal(s) => ret.push(s),
            _ => {}
        }
    }
    ret
}

macro_rules! install {
    (($sel:ident, $builder:ident, $_config:ident),
       $($name:ident,
       $path:expr,
       $default_cond:expr,
       only_hosts: $only_hosts:expr,
       $run_item:block $(, $c:ident)*;)+) => {
        $(
            #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
        pub struct $name {
            pub stage: u32,
            pub target: Interned<String>,
            pub host: Interned<String>,
        }

        impl Step for $name {
            type Output = ();
            const DEFAULT: bool = true;
            const ONLY_BUILD_TARGETS: bool = true;
            const ONLY_HOSTS: bool = $only_hosts;
            $(const $c: bool = true;)*

            fn should_run(run: ShouldRun) -> ShouldRun {
                let $_config = &run.builder.config;
                run.path($path).default_condition($default_cond)
            }

            fn make_run(run: RunConfig) {
                run.builder.ensure($name {
                    stage: run.builder.top_stage,
                    target: run.target,
                    host: run.host,
                });
            }

            fn run($sel, $builder: &Builder) {
                $run_item
            }
        })+
    }
}

install!((self, builder, _config),
    Docs, "src/doc", _config.docs, only_hosts: false, {
        builder.ensure(dist::Docs { stage: self.stage, host: self.target });
        install_docs(builder, self.stage, self.target);
    };
    Std, "src/libstd", true, only_hosts: true, {
        for target in &builder.build.targets {
            builder.ensure(dist::Std {
                compiler: builder.compiler(self.stage, self.host),
                target: *target
            });
            install_std(builder, self.stage, *target);
        }
    };
    Cargo, "cargo", _config.extended, only_hosts: true, {
        builder.ensure(dist::Cargo { stage: self.stage, target: self.target });
        install_cargo(builder, self.stage, self.target);
    };
    Rls, "rls", _config.extended, only_hosts: true, {
        builder.ensure(dist::Rls { stage: self.stage, target: self.target });
        install_rls(builder, self.stage, self.target);
    };
    Analysis, "analysis", _config.extended, only_hosts: false, {
        builder.ensure(dist::Analysis {
            compiler: builder.compiler(self.stage, self.host),
            target: self.target
        });
        install_analysis(builder, self.stage, self.target);
    };
    Src, "src", _config.extended, only_hosts: true, {
        builder.ensure(dist::Src);
        install_src(builder, self.stage);
    }, ONLY_BUILD;
    Rustc, "src/librustc", true, only_hosts: true, {
        builder.ensure(dist::Rustc {
            compiler: builder.compiler(self.stage, self.target),
        });
        install_rustc(builder, self.stage, self.target);
    };
);
<|endoftext|>


<commit_before>import result::{ok, err};
import std::io;
import std::json;
import zmq::{context, socket, error};

import json = std::json::json;

iface transport {
    fn head(path: str) -> response::t;
    fn get(path: str) -> response::t;
    fn put(path: str, doc: json) -> response::t;
    fn post(path: str, doc: json) -> response::t;
    fn delete(path: str) -> response::t;
}

type client = { transport: transport };

fn mk_client(transport: transport) -> client {
    { transport: transport }
}

#[doc = "Transport to talk to Elasticsearch with zeromq"]
type zmq_transport = { socket: zmq::socket };

#[doc = "Zeromq transport implementation"]
impl of transport for zmq_transport {
    fn head(path: str) -> response::t { self.send("HEAD|" + path) }
    fn get(path: str) -> response::t { self.send("GET|" + path) }
    fn put(path: str, doc: json) -> response::t {
        self.send("PUT|" + path + "|" + json::to_str(doc))
    }
    fn post(path: str, doc: json) -> response::t {
        self.send("POST|" + path + "|" + json::to_str(doc))
    }
    fn delete(path: str) -> response::t {
        self.send("DELETE|" + path)
    }

    fn send(request: str) -> response::t {
        str::as_bytes(request) { |bytes|
            alt self.socket.send_between(bytes, 0u, str::len(request), 0) {
              ok(()) {}
              err(e) { fail e.to_str(); }
            }
        }

        alt self.socket.recv(0) {
          ok(msg) { response::parse(msg) }
          err(e) { fail e.to_str(); }
        }
    }
}

#[doc = "Create a zeromq transport to Elasticsearch"]
fn mk_zmq_transport(ctx: zmq::context, addr: str) -> transport {
    let socket = alt ctx.socket(zmq::REQ) {
      ok(socket) { socket }
      err(e) { fail e.to_str() }
    };

    str::as_bytes(addr) { |bytes|
        alt socket.connect(bytes) {
          ok(()) {}
          err(e) { fail e.to_str(); }
        }
    }

    { socket: socket } as transport
}

#[doc = "Helper function to creating a client with zeromq"]
fn connect_with_zmq(ctx: zmq::context, addr: str) -> client {
    let transport = mk_zmq_transport(ctx, addr);
    mk_client(transport)
}

mod response {
    type t = {
        code: uint,
        status: str,
        doc: json,
    };

    fn parse(msg: [u8]) -> t {
        io::println(#fmt("parse: %?", str::from_bytes(msg)));

        let end = vec::len(msg);

        let (start, code) = parse_code(msg, end);
        let (start, status) = parse_status(msg, start, end);
        let doc = parse_doc(msg, start, end);

        { code: code, status: status, doc: doc }
    }

    fn parse_code(msg: [u8], end: uint) -> (uint, uint) {
        alt vec::position_from(msg, 0u, end) { |c| c == '|' as u8 } {
          none { fail "invalid response" }
          some(i) {
            alt uint::parse_buf(vec::slice(msg, 0u, i), 10u) {
              some(code) { (i + 1u, code) }
              none { fail "invalid status code" }
            }
          }
        }
    }

    fn parse_status(msg: [u8], start: uint, end: uint) -> (uint, str) {
        alt vec::position_from(msg, start, end) { |c| c == '|' as u8 } {
          none { fail "invalid response" }
          some(i) { (i + 1u, str::from_bytes(vec::slice(msg, start, i))) }
        }
    }

    fn parse_doc(msg: [u8], start: uint, end: uint) -> json {
        if start == end { ret json::null; }

        io::with_bytes_reader_between(msg, start, end) { |rdr|
            alt json::from_reader(rdr) {
              ok(json) { json }
              err({line, col, msg}) { fail #fmt("%u:%u: %s", line, col, msg); }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    import std::map;

    #[test]
    fn test() {
        let ctx = alt zmq::init(1) {
          ok(ctx) { ctx }
          err(e) { fail e.to_str(); }
        };

        let client = connect_with_zmq(ctx, "tcp://localhost:9700");
        io::println(#fmt("%?\n", client.transport.head("/")));
        io::println(#fmt("%?\n", client.transport.get("/")));

        let doc = map::new_str_hash();
        doc.insert("foo", json::string("bar"));

        io::println(#fmt("%?\n", client.transport.get("/test/test/1")));
        io::println(#fmt("%?\n", client.transport.put("/test/test/1", json::dict(doc))));
        io::println(#fmt("%?\n", client.transport.get("/test/test/1")));

        io::println(#fmt("%?\n", client.transport.delete("/test/test/1")));
    }
}
<commit_msg>Add an index builder.<commit_after>import result::{ok, err};
import std::io;
import std::json;
import std::map;
import std::map::map;
import zmq::{context, socket, error};

import json = std::json::json;

iface transport {
    fn head(path: str) -> response::t;
    fn get(path: str) -> response::t;
    fn put(path: str, doc: map<str, json>) -> response::t;
    fn post(path: str, doc: map<str, json>) -> response::t;
    fn delete(path: str) -> response::t;
}

type client = { transport: transport };

fn mk_client(transport: transport) -> client {
    { transport: transport }
}

impl client for client {
    fn get(index: str, typ: str, id: str) -> response::t {
        let path = index + "/" + typ + "/" + id;
        self.transport.get(path)
    }
}

enum consistency { CONSISTENCY_DEFAULT, ONE, QUORUM, ALL }
enum replication { REPLICATION_DEFAULT, SYNC, ASYNC }
enum op_type { CREATE, INDEX }
enum version_type { INTERNAL, EXTERNAL }

type index_builder = {
    index: str,
    typ: str,
    mut id: option<str>,
    mut routing: option<str>,
    mut parent: option<str>,
    mut timestamp: option<str>,
    mut ttl: option<str>,
    mut op_type: op_type,
    mut refresh: bool,
    mut version: uint,
    mut version_type: version_type,
    mut percolate: option<str>,
    mut consistency: consistency,
    mut replication: replication,
    mut source: option<map<str, json>>,
};

fn mk_index_builder(index: str, typ: str) -> index_builder {
    {
        index: index,
        typ: typ,
        mut id: none,
        mut routing: none,
        mut parent: none,
        mut timestamp: none,
        mut ttl: none,
        mut op_type: INDEX,
        mut refresh: false,
        mut version: 0u,
        mut version_type: INTERNAL,
        mut percolate: none,
        mut consistency: CONSISTENCY_DEFAULT,
        mut replication: REPLICATION_DEFAULT,
        mut source: none,
    }
}

impl index_builder for index_builder {
    fn set_id(id: str) -> index_builder { self.id = some(id); self }
    fn set_routing(routing: str) -> index_builder {
        self.routing = some(routing);
        self
    }
    fn set_parent(parent: str) -> index_builder {
        self.parent = some(parent);
        self
    }
    fn set_timestamp(timestamp: str) -> index_builder {
        self.timestamp = some(timestamp);
        self
    }
    fn set_ttl(ttl: str) -> index_builder {
        self.ttl = some(ttl);
        self
    }
    fn set_op_type(op_type: op_type) -> index_builder {
        self.op_type = op_type;
        self
    }
    fn set_refresh() -> index_builder { self.refresh = true; self }
    fn set_version(version: uint) -> index_builder {
        self.version = version;
        self
    }
    fn set_version_type(version_type: version_type) -> index_builder {
        self.version_type = version_type;
        self
    }
    fn set_percolate(percolate: str) -> index_builder {
        self.percolate = some(percolate);
        self
    }
    fn set_consistency(consistency: consistency) -> index_builder {
        self.consistency = consistency;
        self
    }
    fn set_replication(replication: replication) -> index_builder {
        self.replication = replication;
        self
    }
    fn set_source(source: map<str, json>) -> index_builder {
        self.source = some(source);
        self
    }
    fn execute(client: client) -> response::t {
        let path = [self.index, self.typ];
        alt self.id {
          none {}
          some(id) { vec::push(path, id); }
        }

        let path = str::connect(path, "/");
        let params = [];

        alt self.routing {
          none {}
          some(routing) { vec::push(params, "routing=" + routing); }
        }

        alt self.parent {
          none {}
          some(parent) { vec::push(params, "parent=" + parent); }
        }

        alt self.timestamp {
          none {}
          some(timestamp) { vec::push(params, "timestamp=" + timestamp); }
        }

        alt self.ttl {
          none {}
          some(ttl) { vec::push(params, "ttl=" + ttl); }
        }

        alt self.op_type {
          CREATE { vec::push(params, "op_type=create"); }
          INDEX { vec::push(params, "op_type=index"); }
        }

        if self.refresh {
            vec::push(params, "refresh=true");
        }

        alt self.percolate {
          none {}
          some(percolate) { vec::push(params, "percolate=" + percolate); }
        }

        alt self.consistency {
          CONSISTENCY_DEFAULT {}
          ONE { vec::push(params, "consistency=one"); }
          QUORUM { vec::push(params, "consistency=quorum"); }
          ALL { vec::push(params, "consistency=all"); }
        }

        alt self.replication {
          REPLICATION_DEFAULT {}
          SYNC { vec::push(params, "replication=sync"); }
          ASYNC { vec::push(params, "replication=async"); }
        }

        if vec::is_not_empty(params) {
            path += "?" + str::connect(params, "&");
        }

        let source = alt self.source {
          none { map::new_str_hash() }
          some(source) { source }
        };

        alt self.id {
          none { client.transport.put(path, source) }
          some(_) { client.transport.post(path, source) }
        }
    }
}

type json_dict_builder = { dict: map<str, json> };

fn mk_json_dict_builder() -> json_dict_builder {
    { dict: map::new_str_hash() }
}

impl json_dict_builder for json_dict_builder {
    fn field_float(key: str, value: float) -> json_dict_builder {
        self.dict.insert(key, json::num(value));
        self
    }
    fn field_str(key: str, value: str) -> json_dict_builder {
        self.dict.insert(key, json::string(value));
        self
    }
    fn field_bool(key: str, value: bool) -> json_dict_builder {
        self.dict.insert(key, json::boolean(value));
        self
    }
    fn field_null(key: str) -> json_dict_builder {
        self.dict.insert(key, json::null);
        self
    }
    fn field_dict(key: str, f: fn(json_dict_builder))
      -> json_dict_builder {
        let builder = mk_json_dict_builder();
        f(builder);
        self.dict.insert(key, json::dict(builder.dict));
        self
    }
    fn field_list(key: str, f: fn(json_list_builder)) -> json_dict_builder {
        let builder = mk_json_list_builder();
        f(builder);
        self.dict.insert(key, json::list(builder.list));
        self
    }
}

type json_list_builder = { mut list: [json] };

fn mk_json_list_builder() -> json_list_builder {
    { mut list: [] }
}

impl json_list_builder for json_list_builder {
    fn add_float(value: float) -> json_list_builder {
        vec::push(self.list, json::num(value));
        self
    }
    fn add_str(value: str) -> json_list_builder {
        vec::push(self.list, json::string(value));
        self
    }
    fn add_bool(value: bool) -> json_list_builder {
        vec::push(self.list, json::boolean(value));
        self
    }
    fn add_null() -> json_list_builder {
        vec::push(self.list, json::null);
        self
    }
    fn add_dict(f: fn(json_dict_builder)) -> json_list_builder {
        let builder = mk_json_dict_builder();
        f(builder);
        vec::push(self.list, json::dict(builder.dict));
        self
    }
    fn add_list(f: fn(json_list_builder)) -> json_list_builder {
        let builder = mk_json_list_builder();
        f(builder);
        vec::push(self.list, json::list(builder.list));
        self
    }
}

#[doc = "Transport to talk to Elasticsearch with zeromq"]
type zmq_transport = { socket: zmq::socket };

#[doc = "Zeromq transport implementation"]
impl of transport for zmq_transport {
    fn head(path: str) -> response::t { self.send("HEAD|" + path) }
    fn get(path: str) -> response::t { self.send("GET|" + path) }
    fn put(path: str, doc: map<str, json>) -> response::t {
        self.send("PUT|" + path + "|" + json::to_str(json::dict(doc)))
    }
    fn post(path: str, doc: map<str, json>) -> response::t {
        self.send("POST|" + path + "|" + json::to_str(json::dict(doc)))
    }
    fn delete(path: str) -> response::t {
        self.send("DELETE|" + path)
    }

    fn send(request: str) -> response::t {
        str::as_bytes(request) { |bytes|
            alt self.socket.send_between(bytes, 0u, str::len(request), 0) {
              ok(()) {}
              err(e) { fail e.to_str(); }
            }
        }

        alt self.socket.recv(0) {
          ok(msg) { response::parse(msg) }
          err(e) { fail e.to_str(); }
        }
    }
}

#[doc = "Create a zeromq transport to Elasticsearch"]
fn mk_zmq_transport(ctx: zmq::context, addr: str) -> transport {
    let socket = alt ctx.socket(zmq::REQ) {
      ok(socket) { socket }
      err(e) { fail e.to_str() }
    };

    str::as_bytes(addr) { |bytes|
        alt socket.connect(bytes) {
          ok(()) {}
          err(e) { fail e.to_str(); }
        }
    }

    { socket: socket } as transport
}

#[doc = "Helper function to creating a client with zeromq"]
fn connect_with_zmq(ctx: zmq::context, addr: str) -> client {
    let transport = mk_zmq_transport(ctx, addr);
    mk_client(transport)
}

mod response {
    type t = {
        code: uint,
        status: str,
        doc: json,
    };

    fn parse(msg: [u8]) -> t {
        io::println(#fmt("parse: %?", str::from_bytes(msg)));

        let end = vec::len(msg);

        let (start, code) = parse_code(msg, end);
        let (start, status) = parse_status(msg, start, end);
        let doc = parse_doc(msg, start, end);

        { code: code, status: status, doc: doc }
    }

    fn parse_code(msg: [u8], end: uint) -> (uint, uint) {
        alt vec::position_from(msg, 0u, end) { |c| c == '|' as u8 } {
          none { fail "invalid response" }
          some(i) {
            alt uint::parse_buf(vec::slice(msg, 0u, i), 10u) {
              some(code) { (i + 1u, code) }
              none { fail "invalid status code" }
            }
          }
        }
    }

    fn parse_status(msg: [u8], start: uint, end: uint) -> (uint, str) {
        alt vec::position_from(msg, start, end) { |c| c == '|' as u8 } {
          none { fail "invalid response" }
          some(i) { (i + 1u, str::from_bytes(vec::slice(msg, start, i))) }
        }
    }

    fn parse_doc(msg: [u8], start: uint, end: uint) -> json {
        if start == end { ret json::null; }

        io::with_bytes_reader_between(msg, start, end) { |rdr|
            alt json::from_reader(rdr) {
              ok(json) { json }
              err({line, col, msg}) { fail #fmt("%u:%u: %s", line, col, msg); }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    import std::map;

    #[test]
    fn test() {
        let ctx = alt zmq::init(1) {
          ok(ctx) { ctx }
          err(e) { fail e.to_str(); }
        };

        let client = connect_with_zmq(ctx, "tcp://localhost:9700");
        io::println(#fmt("%?\n", client.transport.head("/")));
        io::println(#fmt("%?\n", client.transport.get("/")));

        io::println(#fmt("%?\n", client.transport.get("/test/test/1")));

        mk_index_builder("test", "test")
          .set_id("1")
          .set_version(2u)
          .set_source(mk_json_dict_builder()
              .field_float("foo", 5.0)
              .field_str("bar", "wee")
              .field_dict("baz") { |bld|
                  bld.field_float("a", 2.0);
              }
              .field_list("boo") { |bld|
                  bld.add_float(1.0).add_str("zzz");
              }
              .dict
          )
          .execute(client);

        //io::println(#fmt("%?\n", client.get("test", "test", "1")));
        //io::println(#fmt("%?\n", client.transport.put("/test/test/1", doc)));
        io::println(#fmt("%?\n", client.transport.get("/test/test/1")));

        io::println(#fmt("%?\n", client.transport.delete("/test/test/1")));
    }
}
<|endoftext|>


<commit_before>use url::Url;
use std::path::Path;

pub trait ToUrl {
    fn to_url(self) -> Result<Url, String>;
}

impl ToUrl for Url {
    fn to_url(self) -> Result<Url, String> {
        Ok(self)
    }
}

impl<'a> ToUrl for &'a Url {
    fn to_url(self) -> Result<Url, String> {
        Ok(self.clone())
    }
}

impl<'a> ToUrl for &'a str {
    fn to_url(self) -> Result<Url, String> {
        Url::parse(self).map_err(|s| {
            format!("invalid url `{}`: {}", self, s)
        })
    }
}

impl<'a> ToUrl for &'a Path {
    fn to_url(self) -> Result<Url, String> {
        Url::from_file_path(self).map_err(|()| {
            format!("invalid path url `{}`", self.display())
        })
    }
}
<commit_msg>Remove unused `ToUrl` impls.<commit_after>use url::Url;
use std::path::Path;

pub trait ToUrl {
    fn to_url(self) -> Result<Url, String>;
}

impl<'a> ToUrl for &'a str {
    fn to_url(self) -> Result<Url, String> {
        Url::parse(self).map_err(|s| {
            format!("invalid url `{}`: {}", self, s)
        })
    }
}

impl<'a> ToUrl for &'a Path {
    fn to_url(self) -> Result<Url, String> {
        Url::from_file_path(self).map_err(|()| {
            format!("invalid path url `{}`", self.display())
        })
    }
}
<|endoftext|>


<commit_before>extern crate mush;

use mush::{GraphNode,GraphEdge,Graph,Backend,NodeBase,EdgeGuard};
use mush::{UiNode,UiGraph,UiBase};
use mush::{ToolPane};

#[macro_use] extern crate conrod;
extern crate find_folder;
extern crate piston_window;

use conrod::{Theme, Widget,WidgetId, color, Colorable,Canvas};
use piston_window::{EventLoop, Glyphs, PistonWindow, UpdateEvent, WindowSettings};

type Ui = conrod::Ui<Glyphs>;

#[derive(Debug,Copy,Clone,PartialEq)]
struct MyEdge {
    factor: f64,
}
impl GraphEdge for MyEdge {
    fn default() -> MyEdge { MyEdge { factor:0.0f64, } }
}

#[allow(dead_code)]
#[derive(Debug,Copy,Clone,PartialEq)]
enum MyGuard {
    In,
    Out,
    Root,
}

#[derive(Debug,Clone,PartialEq)]
struct MyNode {
    name: String,
    position: [f64;2],
    base: NodeBase,
    uibase: UiBase,
    guard: MyGuard,
    kind: MyGuard,
}
impl GraphNode for MyNode {
    fn default() -> MyNode { MyNode { name: "".to_string(),
                                      position: [0.0,0.0],
                                      base: NodeBase::new(),
                                      uibase: UiBase::default(),
                                      guard: MyGuard::In,
                                      kind: MyGuard::Out }}

    fn get_base(&self) -> &NodeBase { &self.base }
    fn get_base_mut(&mut self) -> &mut NodeBase { &mut self.base }

    fn get_name(&self) -> &str { &self.name }
    fn get_position(&self) -> &[f64;2] { &self.position }

    fn set_name(&mut self, s: &str) { self.name = s.to_string() }
    fn set_position(&mut self, p: [f64;2]) { self.position = p }
}
impl UiNode for MyNode {
    fn get_ui(&self) -> &UiBase {&self.uibase}
    fn get_ui_mut(&mut self) -> &mut UiBase {&mut self.uibase}
}
impl MyNode {
    fn new(p: [f64;2], n: String, id: WidgetId) -> MyNode {
        let mut node = MyNode::default();
        node.name = n;
        node.position = p;
        node.get_ui_mut().set_id(id); //fixme: we don't want to track this manually, toolpane did this for us
        node
    }
}

// setup node-edge guards
impl EdgeGuard for MyNode {
    fn guard(&self, other: &Self) -> bool {
        match (self.guard,other.kind) {
            (MyGuard::In,MyGuard::Root) => true,
            (MyGuard::In,MyGuard::Out) => true,
            _ => false,
        }
    }
}

fn main () {

    // Construct the window.
    let window: PistonWindow =
        WindowSettings::new("mush -> graph library gui", [1000, 600])
            .exit_on_esc(true).build().unwrap();

    // Construct our `Ui`.
    let mut ui = {
        let assets = find_folder::Search::KidsThenParents(3, 5)
            .for_folder("fonts").unwrap();
        let font_path = assets.join("SourceCodePro-Regular.otf");
        let theme = Theme::default();
        let glyph_cache = Glyphs::new(&font_path, window.factory.borrow().clone());
        Ui::new(glyph_cache.unwrap(), theme)
    };

    // Initialize the graph structure
    let mut graph = Graph::default();
    let a = graph.add_node(MyNode::new([200.0, 200.0], "Stuff".to_string(),WidgetId(50)));
    let b = graph.add_node(MyNode::new([50.0, 0.0], "Things".to_string(),WidgetId(85)));
    let c = graph.add_node(MyNode::new([0.0, 100.0], "Whatever".to_string(),WidgetId(120)));
    graph.direct(&a,&b, MyEdge::default());
    graph.direct(&b,&c, MyEdge::default());

    //println!("{:?}", graph);

    let mut tools = ToolPane::new(&mut graph,"Some Project Name".to_string());
    //tools.on_save(|graph| println!("{:?}", graph));

    // Poll events from the window.
    for event in window.ups(60) {
        ui.handle_event(&event);

        event.update(|_| {
            ui.set_widgets(|ui|{
                Canvas::new().color(color::DARK_CHARCOAL).set(WidgetId(0),ui);

                tools.render(ui,&mut graph);
                graph.render(ui);
            });
        });

        event.draw_2d(|c, g| {
            ui.draw(c, g);
        });
    }
}
<commit_msg>realign demo nodes<commit_after>extern crate mush;

use mush::{GraphNode,GraphEdge,Graph,Backend,NodeBase,EdgeGuard};
use mush::{UiNode,UiGraph,UiBase};
use mush::{ToolPane};

#[macro_use] extern crate conrod;
extern crate find_folder;
extern crate piston_window;

use conrod::{Theme, Widget,WidgetId, color, Colorable,Canvas};
use piston_window::{EventLoop, Glyphs, PistonWindow, UpdateEvent, WindowSettings};

type Ui = conrod::Ui<Glyphs>;

#[derive(Debug,Copy,Clone,PartialEq)]
struct MyEdge {
    factor: f64,
}
impl GraphEdge for MyEdge {
    fn default() -> MyEdge { MyEdge { factor:0.0f64, } }
}

#[allow(dead_code)]
#[derive(Debug,Copy,Clone,PartialEq)]
enum MyGuard {
    In,
    Out,
    Root,
}

#[derive(Debug,Clone,PartialEq)]
struct MyNode {
    name: String,
    position: [f64;2],
    base: NodeBase,
    uibase: UiBase,
    guard: MyGuard,
    kind: MyGuard,
}
impl GraphNode for MyNode {
    fn default() -> MyNode { MyNode { name: "".to_string(),
                                      position: [0.0,0.0],
                                      base: NodeBase::new(),
                                      uibase: UiBase::default(),
                                      guard: MyGuard::In,
                                      kind: MyGuard::Out }}

    fn get_base(&self) -> &NodeBase { &self.base }
    fn get_base_mut(&mut self) -> &mut NodeBase { &mut self.base }

    fn get_name(&self) -> &str { &self.name }
    fn get_position(&self) -> &[f64;2] { &self.position }

    fn set_name(&mut self, s: &str) { self.name = s.to_string() }
    fn set_position(&mut self, p: [f64;2]) { self.position = p }
}
impl UiNode for MyNode {
    fn get_ui(&self) -> &UiBase {&self.uibase}
    fn get_ui_mut(&mut self) -> &mut UiBase {&mut self.uibase}
}
impl MyNode {
    fn new(p: [f64;2], n: String, id: WidgetId) -> MyNode {
        let mut node = MyNode::default();
        node.name = n;
        node.position = p;
        node.get_ui_mut().set_id(id); //fixme: we don't want to track this manually, toolpane did this for us
        node
    }
}

// setup node-edge guards
impl EdgeGuard for MyNode {
    fn guard(&self, other: &Self) -> bool {
        match (self.guard,other.kind) {
            (MyGuard::In,MyGuard::Root) => true,
            (MyGuard::In,MyGuard::Out) => true,
            _ => false,
        }
    }
}

fn main () {

    // Construct the window.
    let window: PistonWindow =
        WindowSettings::new("mush -> graph library gui", [1000, 600])
            .exit_on_esc(true).build().unwrap();

    // Construct our `Ui`.
    let mut ui = {
        let assets = find_folder::Search::KidsThenParents(3, 5)
            .for_folder("fonts").unwrap();
        let font_path = assets.join("SourceCodePro-Regular.otf");
        let theme = Theme::default();
        let glyph_cache = Glyphs::new(&font_path, window.factory.borrow().clone());
        Ui::new(glyph_cache.unwrap(), theme)
    };

    // Initialize the graph structure
    let mut graph = Graph::default();
    let a = graph.add_node(MyNode::new([-200.0, -200.0], "Stuff".to_string(),WidgetId(50)));
    let b = graph.add_node(MyNode::new([50.0, 100.0], "Things".to_string(),WidgetId(85)));
    let c = graph.add_node(MyNode::new([100.0, -100.0], "Whatever".to_string(),WidgetId(120)));
    graph.direct(&a,&b, MyEdge::default());
    graph.direct(&b,&c, MyEdge::default());

    //println!("{:?}", graph);

    let mut tools = ToolPane::new(&mut graph,"Some Project Name".to_string());
    //tools.on_save(|graph| println!("{:?}", graph));

    // Poll events from the window.
    for event in window.ups(60) {
        ui.handle_event(&event);

        event.update(|_| {
            ui.set_widgets(|ui|{
                Canvas::new().color(color::DARK_CHARCOAL).set(WidgetId(0),ui);

                tools.render(ui,&mut graph);
                graph.render(ui);
            });
        });

        event.draw_2d(|c, g| {
            ui.draw(c, g);
        });
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

#[macro_use]
extern crate bitfield;

use std::net::Ipv4Addr;

bitfield!{
    struct IpV4Header(MSB0 [u8]);
    u32;
    get_version, _: 3, 0;
    get_ihl, _: 7, 4;
    get_dscp, _: 13, 8;
    get_ecn, _: 15, 14;
    get_total_length, _: 31, 16;
    get_identification, _: 47, 31;
    get_df, _: 49;
    get_mf, _: 50;
    get_fragment_offset, _: 63, 51;
    get_time_to_live, _: 71, 64;
    get_protocol, _: 79, 72;
    get_header_checksum, _: 95, 79;
    u8, get_source_address, _: 103, 96, 4;
    u32, get_destination_address, _: 159, 128;
    }

impl<T: AsRef<[u8]> + AsMut<[u8]>> IpV4Header<T> {
    fn get_source_as_ip_addr(&self) -> Ipv4Addr {
        let mut src = [0; 4];
        for (i, src) in src.iter_mut().enumerate() {
            *src = self.get_source_address(i);
        }
        src.into()
    }

    fn get_destination_as_ip_addr(&self) -> Ipv4Addr {
        self.get_destination_address().into()
    }
}

fn main() {
    let data = [
        0x45,
        0x00,
        0x00,
        0x40,
        0x69,
        0x27,
        0x40,
        0x00,
        0x40,
        0x11,
        0x4d,
        0x0d,
        0xc0,
        0xa8,
        0x01,
        0x2a,
        0xc0,
        0xa8,
        0x01,
        0xfe,
    ];

    let header = IpV4Header(data);

    assert_eq!(header.get_version(), 4);
    assert_eq!(header.get_total_length(), 64);
    assert_eq!(header.get_identification(), 0x6927);
    assert!(header.get_df());
    assert!(!header.get_mf());
    assert_eq!(header.get_fragment_offset(), 0);
    assert_eq!(header.get_protocol(), 0x11);
    println!(
        "from {} to {}",
        header.get_source_as_ip_addr(),
        header.get_destination_as_ip_addr()
    );
}
<commit_msg>Fix brace indentation<commit_after>#![allow(dead_code)]

#[macro_use]
extern crate bitfield;

use std::net::Ipv4Addr;

bitfield!{
    struct IpV4Header(MSB0 [u8]);
    u32;
    get_version, _: 3, 0;
    get_ihl, _: 7, 4;
    get_dscp, _: 13, 8;
    get_ecn, _: 15, 14;
    get_total_length, _: 31, 16;
    get_identification, _: 47, 31;
    get_df, _: 49;
    get_mf, _: 50;
    get_fragment_offset, _: 63, 51;
    get_time_to_live, _: 71, 64;
    get_protocol, _: 79, 72;
    get_header_checksum, _: 95, 79;
    u8, get_source_address, _: 103, 96, 4;
    u32, get_destination_address, _: 159, 128;
}

impl<T: AsRef<[u8]> + AsMut<[u8]>> IpV4Header<T> {
    fn get_source_as_ip_addr(&self) -> Ipv4Addr {
        let mut src = [0; 4];
        for (i, src) in src.iter_mut().enumerate() {
            *src = self.get_source_address(i);
        }
        src.into()
    }

    fn get_destination_as_ip_addr(&self) -> Ipv4Addr {
        self.get_destination_address().into()
    }
}

fn main() {
    let data = [
        0x45,
        0x00,
        0x00,
        0x40,
        0x69,
        0x27,
        0x40,
        0x00,
        0x40,
        0x11,
        0x4d,
        0x0d,
        0xc0,
        0xa8,
        0x01,
        0x2a,
        0xc0,
        0xa8,
        0x01,
        0xfe,
    ];

    let header = IpV4Header(data);

    assert_eq!(header.get_version(), 4);
    assert_eq!(header.get_total_length(), 64);
    assert_eq!(header.get_identification(), 0x6927);
    assert!(header.get_df());
    assert!(!header.get_mf());
    assert_eq!(header.get_fragment_offset(), 0);
    assert_eq!(header.get_protocol(), 0x11);
    println!(
        "from {} to {}",
        header.get_source_as_ip_addr(),
        header.get_destination_as_ip_addr()
    );
}
<|endoftext|>


<commit_before>export writeinstr;
export writer;
export writer_factory;
export writer_util;
export make_writer_factory;
export future_writer_factory;

enum writeinstr {
    write(str),
    done
}

type writer = fn~(+writeinstr);
type writer_factory = fn~(page: doc::page) -> writer;

impl writer_util for writer {
    fn write_str(str: str) {
        self(write(str));
    }

    fn write_line(str: str) {
        self.write_str(str + "\n");
    }

    fn write_done() {
        self(done)
    }
}

fn make_writer_factory(config: config::config) -> writer_factory {
    alt config.output_format {
      config::markdown {
        markdown_writer_factory(config)
      }
      config::pandoc_html {
        pandoc_writer_factory(config)
      }
    }
}

fn markdown_writer_factory(config: config::config) -> writer_factory {
    fn~(page: doc::page) -> writer {
        markdown_writer(config, page)
    }
}

fn pandoc_writer_factory(config: config::config) -> writer_factory {
    fn~(page: doc::page) -> writer {
        pandoc_writer(config, page)
    }
}

fn markdown_writer(
    config: config::config,
    page: doc::page
) -> writer {
    let filename = make_filename(config, page);
    generic_writer {|markdown|
        write_file(filename, markdown);
    }
}

fn pandoc_writer(
    config: config::config,
    page: doc::page
) -> writer {
    assert option::is_some(config.pandoc_cmd);
    let pandoc_cmd = option::get(config.pandoc_cmd);
    let filename = make_filename(config, page);

    let pandoc_args = [
        "--standalone",
        "--section-divs",
        "--from=markdown",
        "--to=html",
        "--css=rust.css",
        "--output=" + filename
    ];

    generic_writer {|markdown|
        import std::run;
        import std::os;
        import std::io;
        import std::io::writer_util;

        #debug("pandoc cmd: %s", pandoc_cmd);
        #debug("pandoc args: %s", str::connect(pandoc_args, " "));

        let pipe_in = os::pipe();
        let pipe_out = os::pipe();
        let pipe_err = os::pipe();
        let pid = run::spawn_process(
            pandoc_cmd, pandoc_args, none, none,
            pipe_in.in, pipe_out.out, pipe_err.out);

        let writer = io::fd_writer(pipe_in.out, false);
        writer.write_str(markdown);

        os::close(pipe_in.in);
        os::close(pipe_out.out);
        os::close(pipe_err.out);
        os::close(pipe_in.out);

        let stdout = result::get(task::try {||
            readclose(pipe_out.in)
        });
        let stderr = result::get(task::try {||
            readclose(pipe_err.in)
        });

        let status = run::waitpid(pid);
        #debug("pandoc result: %i", status);
        if status != 0 {
            #error("pandoc-out: %s", stdout);
            #error("pandoc-err: %s", stderr);
            fail "pandoc failed";
        }
    }
}

fn readclose(fd: ctypes::fd_t) -> str {
    import std::os;
    import std::io;

    // Copied from run::program_output
    let file = os::fd_FILE(fd);
    let reader = io::FILE_reader(file, false);
    let buf = "";
    while !reader.eof() {
        let bytes = reader.read_bytes(4096u);
        buf += str::from_bytes(bytes);
    }
    os::fclose(file);
    ret buf;
}

fn generic_writer(process: fn~(markdown: str)) -> writer {
    let ch = task::spawn_listener {|po: comm::port<writeinstr>|
        let markdown = "";
        let keep_going = true;
        while keep_going {
            alt comm::recv(po) {
              write(s) { markdown += s; }
              done { keep_going = false; }
            }
        }
        process(markdown);
    };

    fn~(+instr: writeinstr) {
        comm::send(ch, instr);
    }
}

fn make_filename(
    config: config::config,
    page: doc::page
) -> str {
    import std::fs;

    let filename = {
        alt page {
          doc::cratepage(doc) {
            if config.output_format == config::pandoc_html &&
                config.output_style == config::doc_per_mod {
                "index"
            } else {
                assert doc.topmod.name() != "";
                doc.topmod.name()
            }
          }
          doc::itempage(doc) {
            str::connect(doc.path() + [doc.name()], "_")
          }
        }
    };
    let ext = alt config.output_format {
      config::markdown { "md" }
      config::pandoc_html { "html" }
    };
    fs::connect(config.output_dir, filename + "." + ext)
}

#[test]
fn should_use_markdown_file_name_based_off_crate() {
    let config = {
        output_dir: "output/dir",
        output_format: config::markdown,
        output_style: config::doc_per_crate
        with config::default_config("input/test.rc")
    };
    let doc = test::mk_doc("test", "");
    let page = doc::cratepage(doc.cratedoc());
    let filename = make_filename(config, page);
    assert filename == "output/dir/test.md";
}

#[test]
fn should_name_html_crate_file_name_index_html_when_doc_per_mod() {
    let config = {
        output_dir: "output/dir",
        output_format: config::pandoc_html,
        output_style: config::doc_per_mod
        with config::default_config("input/test.rc")
    };
    let doc = test::mk_doc("", "");
    let page = doc::cratepage(doc.cratedoc());
    let filename = make_filename(config, page);
    assert filename == "output/dir/index.html";
}

#[test]
fn should_name_mod_file_names_by_path() {
    let config = {
        output_dir: "output/dir",
        output_format: config::pandoc_html,
        output_style: config::doc_per_mod
        with config::default_config("input/test.rc")
    };
    let doc = test::mk_doc("", "mod a { mod b { } }");
    let modb = doc.cratemod().mods()[0].mods()[0];
    let page = doc::itempage(doc::modtag(modb));
    let filename = make_filename(config, page);
    assert  filename == "output/dir/a_b.html";
}

#[cfg(test)]
mod test {
    fn mk_doc(name: str, source: str) -> doc::doc {
        astsrv::from_str(source) {|srv|
            let doc = extract::from_srv(srv, name);
            let doc = path_pass::mk_pass().f(srv, doc);
            doc
        }
    }
}

fn write_file(path: str, s: str) {
    import std::io;
    import std::io::writer_util;

    alt io::file_writer(path, [io::create, io::truncate]) {
      result::ok(writer) {
        writer.write_str(s);
      }
      result::err(e) { fail e }
    }
}

fn future_writer_factory(
) -> (writer_factory, comm::port<(doc::page, str)>) {
    let markdown_po = comm::port();
    let markdown_ch = comm::chan(markdown_po);
    let writer_factory = fn~(page: doc::page) -> writer {
        let writer_po = comm::port();
        let writer_ch = comm::chan(writer_po);
        task::spawn {||
            let (writer, future) = future_writer();
            comm::send(writer_ch, writer);
            let s = future::get(future);
            comm::send(markdown_ch, (page, s));
        }
        comm::recv(writer_po)
    };

    (writer_factory, markdown_po)
}

fn future_writer() -> (writer, future::future<str>) {
    let port = comm::port();
    let chan = comm::chan(port);
    let writer = fn~(+instr: writeinstr) {
        comm::send(chan, copy instr);
    };
    let future = future::from_fn {||
        let res = "";
        while true {
            alt comm::recv(port) {
              write(s) { res += s }
              done { break }
            }
        }
        res
    };
    (writer, future)
}
<commit_msg>rustdoc: Run pandoc in a way that won't deadlock waiting for IO<commit_after>export writeinstr;
export writer;
export writer_factory;
export writer_util;
export make_writer_factory;
export future_writer_factory;

enum writeinstr {
    write(str),
    done
}

type writer = fn~(+writeinstr);
type writer_factory = fn~(page: doc::page) -> writer;

impl writer_util for writer {
    fn write_str(str: str) {
        self(write(str));
    }

    fn write_line(str: str) {
        self.write_str(str + "\n");
    }

    fn write_done() {
        self(done)
    }
}

fn make_writer_factory(config: config::config) -> writer_factory {
    alt config.output_format {
      config::markdown {
        markdown_writer_factory(config)
      }
      config::pandoc_html {
        pandoc_writer_factory(config)
      }
    }
}

fn markdown_writer_factory(config: config::config) -> writer_factory {
    fn~(page: doc::page) -> writer {
        markdown_writer(config, page)
    }
}

fn pandoc_writer_factory(config: config::config) -> writer_factory {
    fn~(page: doc::page) -> writer {
        pandoc_writer(config, page)
    }
}

fn markdown_writer(
    config: config::config,
    page: doc::page
) -> writer {
    let filename = make_filename(config, page);
    generic_writer {|markdown|
        write_file(filename, markdown);
    }
}

fn pandoc_writer(
    config: config::config,
    page: doc::page
) -> writer {
    assert option::is_some(config.pandoc_cmd);
    let pandoc_cmd = option::get(config.pandoc_cmd);
    let filename = make_filename(config, page);

    let pandoc_args = [
        "--standalone",
        "--section-divs",
        "--from=markdown",
        "--to=html",
        "--css=rust.css",
        "--output=" + filename
    ];

    generic_writer {|markdown|
        import std::run;
        import std::os;
        import std::io;
        import std::io::writer_util;

        #debug("pandoc cmd: %s", pandoc_cmd);
        #debug("pandoc args: %s", str::connect(pandoc_args, " "));

        let pipe_in = os::pipe();
        let pipe_out = os::pipe();
        let pipe_err = os::pipe();
        let pid = run::spawn_process(
            pandoc_cmd, pandoc_args, none, none,
            pipe_in.in, pipe_out.out, pipe_err.out);

        let writer = io::fd_writer(pipe_in.out, false);
        writer.write_str(markdown);

        os::close(pipe_in.in);
        os::close(pipe_out.out);
        os::close(pipe_err.out);
        os::close(pipe_in.out);

        let stdout_po = comm::port();
        let stdout_ch = comm::chan(stdout_po);
        task::spawn_sched(task::single_threaded) {||
            comm::send(stdout_ch, readclose(pipe_out.in));
        }
        let stdout = comm::recv(stdout_po);

        let stderr_po = comm::port();
        let stderr_ch = comm::chan(stderr_po);
        task::spawn_sched(task::single_threaded) {||
            comm::send(stderr_ch, readclose(pipe_err.in));
        }
        let stderr = comm::recv(stderr_po);

        let status = run::waitpid(pid);
        #debug("pandoc result: %i", status);
        if status != 0 {
            #error("pandoc-out: %s", stdout);
            #error("pandoc-err: %s", stderr);
            fail "pandoc failed";
        }
    }
}

fn readclose(fd: ctypes::fd_t) -> str {
    import std::os;
    import std::io;

    // Copied from run::program_output
    let file = os::fd_FILE(fd);
    let reader = io::FILE_reader(file, false);
    let buf = "";
    while !reader.eof() {
        let bytes = reader.read_bytes(4096u);
        buf += str::from_bytes(bytes);
    }
    os::fclose(file);
    ret buf;
}

fn generic_writer(process: fn~(markdown: str)) -> writer {
    let ch = task::spawn_listener {|po: comm::port<writeinstr>|
        let markdown = "";
        let keep_going = true;
        while keep_going {
            alt comm::recv(po) {
              write(s) { markdown += s; }
              done { keep_going = false; }
            }
        }
        process(markdown);
    };

    fn~(+instr: writeinstr) {
        comm::send(ch, instr);
    }
}

fn make_filename(
    config: config::config,
    page: doc::page
) -> str {
    import std::fs;

    let filename = {
        alt page {
          doc::cratepage(doc) {
            if config.output_format == config::pandoc_html &&
                config.output_style == config::doc_per_mod {
                "index"
            } else {
                assert doc.topmod.name() != "";
                doc.topmod.name()
            }
          }
          doc::itempage(doc) {
            str::connect(doc.path() + [doc.name()], "_")
          }
        }
    };
    let ext = alt config.output_format {
      config::markdown { "md" }
      config::pandoc_html { "html" }
    };
    fs::connect(config.output_dir, filename + "." + ext)
}

#[test]
fn should_use_markdown_file_name_based_off_crate() {
    let config = {
        output_dir: "output/dir",
        output_format: config::markdown,
        output_style: config::doc_per_crate
        with config::default_config("input/test.rc")
    };
    let doc = test::mk_doc("test", "");
    let page = doc::cratepage(doc.cratedoc());
    let filename = make_filename(config, page);
    assert filename == "output/dir/test.md";
}

#[test]
fn should_name_html_crate_file_name_index_html_when_doc_per_mod() {
    let config = {
        output_dir: "output/dir",
        output_format: config::pandoc_html,
        output_style: config::doc_per_mod
        with config::default_config("input/test.rc")
    };
    let doc = test::mk_doc("", "");
    let page = doc::cratepage(doc.cratedoc());
    let filename = make_filename(config, page);
    assert filename == "output/dir/index.html";
}

#[test]
fn should_name_mod_file_names_by_path() {
    let config = {
        output_dir: "output/dir",
        output_format: config::pandoc_html,
        output_style: config::doc_per_mod
        with config::default_config("input/test.rc")
    };
    let doc = test::mk_doc("", "mod a { mod b { } }");
    let modb = doc.cratemod().mods()[0].mods()[0];
    let page = doc::itempage(doc::modtag(modb));
    let filename = make_filename(config, page);
    assert  filename == "output/dir/a_b.html";
}

#[cfg(test)]
mod test {
    fn mk_doc(name: str, source: str) -> doc::doc {
        astsrv::from_str(source) {|srv|
            let doc = extract::from_srv(srv, name);
            let doc = path_pass::mk_pass().f(srv, doc);
            doc
        }
    }
}

fn write_file(path: str, s: str) {
    import std::io;
    import std::io::writer_util;

    alt io::file_writer(path, [io::create, io::truncate]) {
      result::ok(writer) {
        writer.write_str(s);
      }
      result::err(e) { fail e }
    }
}

fn future_writer_factory(
) -> (writer_factory, comm::port<(doc::page, str)>) {
    let markdown_po = comm::port();
    let markdown_ch = comm::chan(markdown_po);
    let writer_factory = fn~(page: doc::page) -> writer {
        let writer_po = comm::port();
        let writer_ch = comm::chan(writer_po);
        task::spawn {||
            let (writer, future) = future_writer();
            comm::send(writer_ch, writer);
            let s = future::get(future);
            comm::send(markdown_ch, (page, s));
        }
        comm::recv(writer_po)
    };

    (writer_factory, markdown_po)
}

fn future_writer() -> (writer, future::future<str>) {
    let port = comm::port();
    let chan = comm::chan(port);
    let writer = fn~(+instr: writeinstr) {
        comm::send(chan, copy instr);
    };
    let future = future::from_fn {||
        let res = "";
        while true {
            alt comm::recv(port) {
              write(s) { res += s }
              done { break }
            }
        }
        res
    };
    (writer, future)
}
<|endoftext|>


<commit_before>//! This example draws a crude version of the Rust logo.
//! The version is "crude" because it's all very approximate with plenty of guesswork.
//! If you can come up with a way to do this so that it exactly matches the logo, please
//! do submit it!
//! In any case, this is an excellent example of creatively using fills and some other
//! techniques to create a fairly complex drawing.

use turtle::Turtle;

fn main() {
    let mut turtle = Turtle::new();

    turtle.set_fill_color("black");

    turtle.begin_fill();
    turtle.pen_up();
    turtle.forward(130.0);
    turtle.pen_down();

    gear(&mut turtle);
    turtle.end_fill();

    turtle.pen_up();
    turtle.forward(45.0);
    turtle.left(90.0);
    turtle.pen_down();

    inner_gear(&mut turtle);

    letter(&mut turtle);

    turtle.hide();
}

fn gear(turtle: &mut Turtle) {
    // Much of this code was figured out by guessing and checking
    let teeth = 32.0;
    let tooth_size = 20.0;
    let angle = 360.0 / teeth;
    turtle.right(180.0 - angle * 6.0 / 2.0);
    for _ in 0..teeth as u64 {
        turtle.forward(tooth_size);
        turtle.left(180.0 - angle * 7.0);
        turtle.forward(tooth_size);
        turtle.right(180.0 - angle * 6.0);
    }

    turtle.right(angle * 6.0 / 2.0);
}

fn inner_gear(turtle: &mut Turtle) {
    inner_circle(turtle);
    inner_teeth(turtle);
}

fn inner_circle(turtle: &mut Turtle) {
    turtle.set_fill_color("white");
    turtle.begin_fill();
    for _ in 0..360 {
        turtle.forward(1.5);
        turtle.right(1.0);
    }
    turtle.end_fill();
    turtle.set_fill_color("black");
}

fn inner_teeth(turtle: &mut Turtle) {
    let tooth_size = 40.0;
    turtle.pen_up();
    turtle.left(90.0);
    turtle.forward(10.0);
    turtle.right(90.0);
    turtle.pen_down();

    for _ in 0..5 {
        turtle.pen_up();
        turtle.forward(tooth_size / 2.0);
        turtle.pen_down();

        turtle.begin_fill();
        turtle.right(120.0);
        turtle.forward(tooth_size);
        turtle.right(120.0);
        turtle.forward(tooth_size);
        turtle.right(120.0);
        turtle.end_fill();

        turtle.pen_up();
        turtle.forward(tooth_size / 2.0);
        turtle.right(90.0);
        turtle.forward(5.0);
        turtle.left(90.0);
        turtle.pen_down();

        inner_tooth_circle(turtle);

        turtle.pen_up();
        turtle.left(90.0);
        turtle.forward(5.0);
        turtle.right(90.0);
        for _ in 0..360 / 5 / 2 {
            turtle.forward(3.41);
            turtle.right(2.0);
        }
        turtle.pen_down();
    }
}

fn inner_tooth_circle(turtle: &mut Turtle) {
    turtle.set_fill_color("white");
    turtle.begin_fill();
    for _ in 0..360 / 8 {
        turtle.forward(1.0);
        turtle.right(8.0);
    }
    turtle.end_fill();
    turtle.set_fill_color("black");
}

fn letter(turtle: &mut Turtle) {
    turtle.pen_up();
    turtle.right(180.0);
    turtle.pen_down();
    for _ in 0..(360 / 5 - 8) / 2 {
        turtle.forward(3.41);
        turtle.left(2.0);
    }
    // Trick for making the turtle face to the right
    let heading = turtle.heading();
    turtle.right(heading);

    turtle.set_pen_size(24.0);
    turtle.forward(110.0);
    for _ in 0..120 {
        turtle.forward(0.5);
        turtle.right(1.5);
    }

    turtle.forward(52.0);
    turtle.right(90.0);
    turtle.forward(35.0);
    turtle.backward(75.0);

    turtle.left(90.0);
    turtle.forward(65.0);
    turtle.backward(80.0);

    // flat tip
         turtle.set_pen_size(5.0);

         turtle.backward(10.0);
         turtle.left(90.0);

         turtle.forward(9.5);
         turtle.right(90.0);
         turtle.forward(15.0);
         turtle.backward(15.0);
         turtle.left(90.0);

         turtle.backward(19.0);
         turtle.right(90.0);
         turtle.forward(15.0);
         turtle.backward(15.0);
         turtle.left(90.0);

         //resetting position after correction
         turtle.forward(9.5);
         turtle.right(90.0);

         turtle.set_pen_size(24.0);
    // end

    turtle.pen_up();
    turtle.backward(105.0);
    turtle.pen_down();

    turtle.forward(40.0);
    for _ in 0..80 {
        turtle.forward(0.5);
        turtle.right(1.0);
    }

    for _ in 0..30 {
        turtle.forward(0.5);
        turtle.left(0.5);
    }
}
<commit_msg>Updated comments and un-indented lines <commit_after>//! This example draws a crude version of the Rust logo.
//! The version is "crude" because it's all very approximate with plenty of guesswork.
//! If you can come up with a way to do this so that it exactly matches the logo, please
//! do submit it!
//! In any case, this is an excellent example of creatively using fills and some other
//! techniques to create a fairly complex drawing.

use turtle::Turtle;

fn main() {
    let mut turtle = Turtle::new();

    turtle.set_fill_color("black");

    turtle.begin_fill();
    turtle.pen_up();
    turtle.forward(130.0);
    turtle.pen_down();

    gear(&mut turtle);
    turtle.end_fill();

    turtle.pen_up();
    turtle.forward(45.0);
    turtle.left(90.0);
    turtle.pen_down();

    inner_gear(&mut turtle);

    letter(&mut turtle);

    turtle.hide();
}

fn gear(turtle: &mut Turtle) {
    // Much of this code was figured out by guessing and checking
    let teeth = 32.0;
    let tooth_size = 20.0;
    let angle = 360.0 / teeth;
    turtle.right(180.0 - angle * 6.0 / 2.0);
    for _ in 0..teeth as u64 {
        turtle.forward(tooth_size);
        turtle.left(180.0 - angle * 7.0);
        turtle.forward(tooth_size);
        turtle.right(180.0 - angle * 6.0);
    }

    turtle.right(angle * 6.0 / 2.0);
}

fn inner_gear(turtle: &mut Turtle) {
    inner_circle(turtle);
    inner_teeth(turtle);
}

fn inner_circle(turtle: &mut Turtle) {
    turtle.set_fill_color("white");
    turtle.begin_fill();
    for _ in 0..360 {
        turtle.forward(1.5);
        turtle.right(1.0);
    }
    turtle.end_fill();
    turtle.set_fill_color("black");
}

fn inner_teeth(turtle: &mut Turtle) {
    let tooth_size = 40.0;
    turtle.pen_up();
    turtle.left(90.0);
    turtle.forward(10.0);
    turtle.right(90.0);
    turtle.pen_down();

    for _ in 0..5 {
        turtle.pen_up();
        turtle.forward(tooth_size / 2.0);
        turtle.pen_down();

        turtle.begin_fill();
        turtle.right(120.0);
        turtle.forward(tooth_size);
        turtle.right(120.0);
        turtle.forward(tooth_size);
        turtle.right(120.0);
        turtle.end_fill();

        turtle.pen_up();
        turtle.forward(tooth_size / 2.0);
        turtle.right(90.0);
        turtle.forward(5.0);
        turtle.left(90.0);
        turtle.pen_down();

        inner_tooth_circle(turtle);

        turtle.pen_up();
        turtle.left(90.0);
        turtle.forward(5.0);
        turtle.right(90.0);
        for _ in 0..360 / 5 / 2 {
            turtle.forward(3.41);
            turtle.right(2.0);
        }
        turtle.pen_down();
    }
}

fn inner_tooth_circle(turtle: &mut Turtle) {
    turtle.set_fill_color("white");
    turtle.begin_fill();
    for _ in 0..360 / 8 {
        turtle.forward(1.0);
        turtle.right(8.0);
    }
    turtle.end_fill();
    turtle.set_fill_color("black");
}

fn letter(turtle: &mut Turtle) {
    turtle.pen_up();
    turtle.right(180.0);
    turtle.pen_down();
    for _ in 0..(360 / 5 - 8) / 2 {
        turtle.forward(3.41);
        turtle.left(2.0);
    }
    // Trick for making the turtle face to the right
    let heading = turtle.heading();
    turtle.right(heading);

    turtle.set_pen_size(24.0);
    turtle.forward(110.0);
    for _ in 0..120 {
        turtle.forward(0.5);
        turtle.right(1.5);
    }

    turtle.forward(52.0);
    turtle.right(90.0);
    turtle.forward(35.0);
    turtle.backward(75.0);

    turtle.left(90.0);
    turtle.forward(65.0);
    turtle.backward(80.0);

    // Flatten tip of the bottom line of the letter "R"
    // This corrects for the rounded tip of the turtle's pen
    turtle.set_pen_size(5.0);

    turtle.backward(10.0);
    turtle.left(90.0);

    turtle.forward(9.5);
    turtle.right(90.0);
    turtle.forward(15.0);
    turtle.backward(15.0);
    turtle.left(90.0);

    turtle.backward(19.0);
    turtle.right(90.0);
    turtle.forward(15.0);
    turtle.backward(15.0);
    turtle.left(90.0);

    //resetting position after correction
    turtle.forward(9.5);
    turtle.right(90.0);

    turtle.set_pen_size(24.0);
    // end

    turtle.pen_up();
    turtle.backward(105.0);
    turtle.pen_down();

    turtle.forward(40.0);
    for _ in 0..80 {
        turtle.forward(0.5);
        turtle.right(1.0);
    }

    for _ in 0..30 {
        turtle.forward(0.5);
        turtle.left(0.5);
    }
}
<|endoftext|>


<commit_before>use std::{usize, u8, u16, u32, u64};
use std::{isize, i8, i16, i32, i64};
use std::{f32, f64};

/// Numbers which have upper and lower bounds
pub trait Bounded {
    // FIXME (#5527): These should be associated constants
    /// returns the smallest finite number this type can represent
    fn min_value() -> Self;
    /// returns the largest finite number this type can represent
    fn max_value() -> Self;
}

macro_rules! bounded_impl {
    ($t:ty, $min:expr, $max:expr) => {
        impl Bounded for $t {
            #[inline]
            fn min_value() -> $t { $min }

            #[inline]
            fn max_value() -> $t { $max }
        }
    }
}

bounded_impl!(usize, usize::MIN, usize::MAX);
bounded_impl!(u8,    u8::MIN,    u8::MAX);
bounded_impl!(u16,   u16::MIN,   u16::MAX);
bounded_impl!(u32,   u32::MIN,   u32::MAX);
bounded_impl!(u64,   u64::MIN,   u64::MAX);

bounded_impl!(isize, isize::MIN, isize::MAX);
bounded_impl!(i8,    i8::MIN,    i8::MAX);
bounded_impl!(i16,   i16::MIN,   i16::MAX);
bounded_impl!(i32,   i32::MIN,   i32::MAX);
bounded_impl!(i64,   i64::MIN,   i64::MAX);

bounded_impl!(f32, f32::MIN, f32::MAX);

macro_rules! for_each_tuple_ {
    ( $m:ident !! ) => (
        $m! { }
    );
    ( $m:ident !! $h:ident, $($t:ident,)* ) => (
        $m! { $h $($t)* }
        for_each_tuple_! { $m !! $($t,)* }
    );
}
macro_rules! for_each_tuple {
    ( $m:ident ) => (
        for_each_tuple_! { $m !! A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, }
    );
}

macro_rules! bounded_tuple {
    ( $($name:ident)* ) => (
        impl<$($name: Bounded,)*> Bounded for ($($name,)*) {
            #[inline]
            fn min_value() -> Self {
                ($($name::min_value(),)*)
            }
            #[inline]
            fn max_value() -> Self {
                ($($name::max_value(),)*)
            }
        }
    );
}

for_each_tuple!(bounded_tuple);
bounded_impl!(f64, f64::MIN, f64::MAX);
<commit_msg>impl Bounded for Wrapping<T><commit_after>use std::{usize, u8, u16, u32, u64};
use std::{isize, i8, i16, i32, i64};
use std::{f32, f64};
use std::num::Wrapping;

/// Numbers which have upper and lower bounds
pub trait Bounded {
    // FIXME (#5527): These should be associated constants
    /// returns the smallest finite number this type can represent
    fn min_value() -> Self;
    /// returns the largest finite number this type can represent
    fn max_value() -> Self;
}

macro_rules! bounded_impl {
    ($t:ty, $min:expr, $max:expr) => {
        impl Bounded for $t {
            #[inline]
            fn min_value() -> $t { $min }

            #[inline]
            fn max_value() -> $t { $max }
        }
    }
}

bounded_impl!(usize, usize::MIN, usize::MAX);
bounded_impl!(u8,    u8::MIN,    u8::MAX);
bounded_impl!(u16,   u16::MIN,   u16::MAX);
bounded_impl!(u32,   u32::MIN,   u32::MAX);
bounded_impl!(u64,   u64::MIN,   u64::MAX);

bounded_impl!(isize, isize::MIN, isize::MAX);
bounded_impl!(i8,    i8::MIN,    i8::MAX);
bounded_impl!(i16,   i16::MIN,   i16::MAX);
bounded_impl!(i32,   i32::MIN,   i32::MAX);
bounded_impl!(i64,   i64::MIN,   i64::MAX);

impl<T: Bounded> Bounded for Wrapping<T> {
    #[inline] fn min_value() -> Self { Wrapping(T::min_value()) }
    #[inline] fn max_value() -> Self { Wrapping(T::max_value()) }
}

bounded_impl!(f32, f32::MIN, f32::MAX);

macro_rules! for_each_tuple_ {
    ( $m:ident !! ) => (
        $m! { }
    );
    ( $m:ident !! $h:ident, $($t:ident,)* ) => (
        $m! { $h $($t)* }
        for_each_tuple_! { $m !! $($t,)* }
    );
}
macro_rules! for_each_tuple {
    ( $m:ident ) => (
        for_each_tuple_! { $m !! A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, }
    );
}

macro_rules! bounded_tuple {
    ( $($name:ident)* ) => (
        impl<$($name: Bounded,)*> Bounded for ($($name,)*) {
            #[inline]
            fn min_value() -> Self {
                ($($name::min_value(),)*)
            }
            #[inline]
            fn max_value() -> Self {
                ($($name::max_value(),)*)
            }
        }
    );
}

for_each_tuple!(bounded_tuple);
bounded_impl!(f64, f64::MIN, f64::MAX);
<|endoftext|>


<commit_before>// This is a part of rust-encoding.
// Copyright (c) 2013, Kang Seonghoon.
// See README.md and LICENSE.txt for details.

//! Legacy traditional Chinese encodings.

use util::{as_char, StrCharIndex};
use index = index::big5;
use types::*;

/**
 * Big5-2003 with common extensions. (XXX with asymmetric HKSCS-2008 support)
 *
 * This is a traditional Chinese encoding spanning the region `[81-FE] [40-7E A1-FE]`.
 * Originally a proprietary encoding by the consortium of five companies (hence the name),
 * the Republic of China government standardized Big5-2003 in an appendix of CNS 11643
 * so that CNS 11643 plane 1 and plane 2 have
 * an almost identical set of characters as Big5 (but with a different mapping).
 * The Hong Kong government has an official extension to Big5
 * named Hong Kong Supplementary Character Set (HKSCS).
 *
 * This particular implementation of Big5 includes the widespread ETEN and HKSCS extensions,
 * but excludes less common extensions such as Big5+, Big-5E and Unicode-at-on.
 */
#[deriving(Clone)]
pub struct BigFive2003Encoding;

impl Encoding for BigFive2003Encoding {
    fn name(&self) -> &'static str { "big5-2003" }
    fn whatwg_name(&self) -> Option<&'static str> { Some("big5") } // WHATWG compatibility
    fn encoder(&self) -> ~Encoder { BigFive2003Encoder::new() }
    fn decoder(&self) -> ~Decoder { BigFive2003HKSCS2008Decoder::new() }
}

/// An encoder for Big5-2003.
#[deriving(Clone)]
pub struct BigFive2003Encoder;

impl BigFive2003Encoder {
    pub fn new() -> ~Encoder { ~BigFive2003Encoder as ~Encoder }
}

impl Encoder for BigFive2003Encoder {
    fn from_self(&self) -> ~Encoder { BigFive2003Encoder::new() }
    fn is_ascii_compatible(&self) -> bool { true }

    fn raw_feed(&mut self, input: &str, output: &mut ByteWriter) -> (uint, Option<CodecError>) {
        output.writer_hint(input.len());

        for ((i,j), ch) in input.index_iter() {
            if ch < '\u0080' {
                output.write_byte(ch as u8);
            } else {
                let ptr = index::backward(ch as u32);
                if ptr == 0xffff || ptr < (0xa1 - 0x81) * 157 {
                    // no HKSCS extension (XXX doesn't HKSCS include 0xFA40..0xFEFE?)
                    return (i, Some(CodecError {
                        upto: j, cause: "unrepresentable character".into_send_str()
                    }));
                }
                let lead = ptr / 157 + 0x81;
                let trail = ptr % 157;
                let trailoffset = if trail < 0x3f {0x40} else {0x62};
                output.write_byte(lead as u8);
                output.write_byte((trail + trailoffset) as u8);
            }
        }
        (input.len(), None)
    }

    fn raw_finish(&mut self, _output: &mut ByteWriter) -> Option<CodecError> {
        None
    }
}

/// A decoder for Big5-2003 with HKSCS-2008 extension.
#[deriving(Clone)]
pub struct BigFive2003HKSCS2008Decoder {
    lead: u8
}

impl BigFive2003HKSCS2008Decoder {
    pub fn new() -> ~Decoder { ~BigFive2003HKSCS2008Decoder { lead: 0 } as ~Decoder }
}

impl Decoder for BigFive2003HKSCS2008Decoder {
    fn from_self(&self) -> ~Decoder { BigFive2003HKSCS2008Decoder::new() }
    fn is_ascii_compatible(&self) -> bool { true }

    fn raw_feed(&mut self, input: &[u8], output: &mut StringWriter) -> (uint, Option<CodecError>) {
        output.writer_hint(input.len());

        fn map_two_bytes(lead: u8, trail: u8) -> u32 {
            let lead = lead as uint;
            let trail = trail as uint;
            let index = match (lead, trail) {
                (0x81..0xfe, 0x40..0x7e) | (0x81..0xfe, 0xa1..0xfe) => {
                    let trailoffset = if trail < 0x7f {0x40} else {0x62};
                    (lead - 0x81) * 157 + trail - trailoffset
                }
                _ => 0xffff,
            };
            index::forward(index as u16) // may return two-letter replacements 0..3
        }

        let mut i = 0;
        let mut processed = 0;
        let len = input.len();

        if i >= len { return (processed, None); }

        if self.lead != 0 {
            match map_two_bytes(self.lead, input[i]) {
                0xffff => {
                    self.lead = 0;
                    return (processed, Some(CodecError {
                        upto: i, cause: "invalid sequence".into_send_str()
                    }));
                }
                0 /*index=1133*/ => { output.write_str("\u00ca\u0304"); }
                1 /*index=1135*/ => { output.write_str("\u00ca\u030c"); }
                2 /*index=1164*/ => { output.write_str("\u00ea\u0304"); }
                3 /*index=1166*/ => { output.write_str("\u00ea\u030c"); }
                ch => { output.write_char(as_char(ch)); }
            }
            i += 1;
        }

        self.lead = 0;
        processed = i;
        while i < len {
            match input[i] {
                0x00..0x7f => { output.write_char(input[i] as char); }
                0x81..0xfe => {
                    i += 1;
                    if i >= len {
                        self.lead = input[i-1];
                        break;
                    }
                    match map_two_bytes(input[i-1], input[i]) {
                        0xffff => {
                            return (processed, Some(CodecError {
                                upto: i, cause: "invalid sequence".into_send_str()
                            }));
                        }
                        0 /*index=1133*/ => { output.write_str("\u00ca\u0304"); }
                        1 /*index=1135*/ => { output.write_str("\u00ca\u030c"); }
                        2 /*index=1164*/ => { output.write_str("\u00ea\u0304"); }
                        3 /*index=1166*/ => { output.write_str("\u00ea\u030c"); }
                        ch => { output.write_char(as_char(ch)); }
                    }
                }
                _ => {
                    return (processed, Some(CodecError {
                        upto: i+1, cause: "invalid sequence".into_send_str()
                    }));
                }
            }
            i += 1;
            processed = i;
        }
        (processed, None)
    }

    fn raw_finish(&mut self, _output: &mut StringWriter) -> Option<CodecError> {
        let lead = self.lead;
        self.lead = 0;
        if lead != 0 {
            Some(CodecError { upto: 0, cause: "incomplete sequence".into_send_str() })
        } else {
            None
        }
    }
}

#[cfg(test)]
mod bigfive2003_tests {
    use super::BigFive2003Encoding;
    use types::*;

    #[test]
    fn test_encoder_valid() {
        let mut e = BigFive2003Encoding.encoder();
        assert_feed_ok!(e, "A", "", [0x41]);
        assert_feed_ok!(e, "BC", "", [0x42, 0x43]);
        assert_feed_ok!(e, "", "", []);
        assert_feed_ok!(e, "\u4e2d\u83ef\u6c11\u570b", "",
                        [0xa4, 0xa4, 0xb5, 0xd8, 0xa5, 0xc1, 0xb0, 0xea]);
        assert_feed_ok!(e, "1\u20ac/m", "", [0x31, 0xa3, 0xe1, 0x2f, 0x6d]);
        assert_feed_ok!(e, "\uffed", "", [0xf9, 0xfe]);
        assert_finish_ok!(e, []);
    }

    #[test]
    fn test_encoder_invalid() {
        let mut e = BigFive2003Encoding.encoder();
        assert_feed_err!(e, "", "\uffff", "", []);
        assert_feed_err!(e, "?", "\uffff", "!", [0x3f]);
        assert_feed_err!(e, "", "\u3eec", "\u4e00", []); // HKSCS-2008 addition
        assert_finish_ok!(e, []);
    }

    #[test]
    fn test_decoder_valid() {
        let mut d = BigFive2003Encoding.decoder();
        assert_feed_ok!(d, [0x41], [], "A");
        assert_feed_ok!(d, [0x42, 0x43], [], "BC");
        assert_feed_ok!(d, [], [], "");
        assert_feed_ok!(d, [0xa4, 0xa4, 0xb5, 0xd8, 0xa5, 0xc1, 0xb0, 0xea], [],
                        "\u4e2d\u83ef\u6c11\u570b");
        assert_feed_ok!(d, [0x31, 0xa3, 0xe1, 0x2f, 0x6d], [], "1\u20ac/m");
        assert_feed_ok!(d, [0xf9, 0xfe], [], "\uffed");
        assert_feed_ok!(d, [0x87, 0x7e], [], "\u3eec"); // HKSCS-2008 addition
        assert_finish_ok!(d, "");
    }

    // TODO more tests

    #[test]
    fn test_decoder_feed_after_finish() {
        let mut d = BigFive2003Encoding.decoder();
        assert_feed_ok!(d, [0xa4, 0x40], [0xa4], "\u4e00");
        assert_finish_err!(d, "");
        assert_feed_ok!(d, [0xa4, 0x40], [], "\u4e00");
        assert_finish_ok!(d, "");
    }
}

<commit_msg>updated Big5 decoder for the standard update: whatwg/encoding@88a2177754655255df378e1b97cd085420399fe4.<commit_after>// This is a part of rust-encoding.
// Copyright (c) 2013, Kang Seonghoon.
// See README.md and LICENSE.txt for details.

//! Legacy traditional Chinese encodings.

use util::{as_char, StrCharIndex};
use index = index::big5;
use types::*;

/**
 * Big5-2003 with common extensions. (XXX with asymmetric HKSCS-2008 support)
 *
 * This is a traditional Chinese encoding spanning the region `[81-FE] [40-7E A1-FE]`.
 * Originally a proprietary encoding by the consortium of five companies (hence the name),
 * the Republic of China government standardized Big5-2003 in an appendix of CNS 11643
 * so that CNS 11643 plane 1 and plane 2 have
 * an almost identical set of characters as Big5 (but with a different mapping).
 * The Hong Kong government has an official extension to Big5
 * named Hong Kong Supplementary Character Set (HKSCS).
 *
 * This particular implementation of Big5 includes the widespread ETEN and HKSCS extensions,
 * but excludes less common extensions such as Big5+, Big-5E and Unicode-at-on.
 */
#[deriving(Clone)]
pub struct BigFive2003Encoding;

impl Encoding for BigFive2003Encoding {
    fn name(&self) -> &'static str { "big5-2003" }
    fn whatwg_name(&self) -> Option<&'static str> { Some("big5") } // WHATWG compatibility
    fn encoder(&self) -> ~Encoder { BigFive2003Encoder::new() }
    fn decoder(&self) -> ~Decoder { BigFive2003HKSCS2008Decoder::new() }
}

/// An encoder for Big5-2003.
#[deriving(Clone)]
pub struct BigFive2003Encoder;

impl BigFive2003Encoder {
    pub fn new() -> ~Encoder { ~BigFive2003Encoder as ~Encoder }
}

impl Encoder for BigFive2003Encoder {
    fn from_self(&self) -> ~Encoder { BigFive2003Encoder::new() }
    fn is_ascii_compatible(&self) -> bool { true }

    fn raw_feed(&mut self, input: &str, output: &mut ByteWriter) -> (uint, Option<CodecError>) {
        output.writer_hint(input.len());

        for ((i,j), ch) in input.index_iter() {
            if ch < '\u0080' {
                output.write_byte(ch as u8);
            } else {
                let ptr = index::backward(ch as u32);
                if ptr == 0xffff || ptr < (0xa1 - 0x81) * 157 {
                    // no HKSCS extension (XXX doesn't HKSCS include 0xFA40..0xFEFE?)
                    return (i, Some(CodecError {
                        upto: j, cause: "unrepresentable character".into_send_str()
                    }));
                }
                let lead = ptr / 157 + 0x81;
                let trail = ptr % 157;
                let trailoffset = if trail < 0x3f {0x40} else {0x62};
                output.write_byte(lead as u8);
                output.write_byte((trail + trailoffset) as u8);
            }
        }
        (input.len(), None)
    }

    fn raw_finish(&mut self, _output: &mut ByteWriter) -> Option<CodecError> {
        None
    }
}

/// A decoder for Big5-2003 with HKSCS-2008 extension.
#[deriving(Clone)]
pub struct BigFive2003HKSCS2008Decoder {
    lead: u8
}

impl BigFive2003HKSCS2008Decoder {
    pub fn new() -> ~Decoder { ~BigFive2003HKSCS2008Decoder { lead: 0 } as ~Decoder }
}

impl Decoder for BigFive2003HKSCS2008Decoder {
    fn from_self(&self) -> ~Decoder { BigFive2003HKSCS2008Decoder::new() }
    fn is_ascii_compatible(&self) -> bool { true }

    fn raw_feed(&mut self, input: &[u8], output: &mut StringWriter) -> (uint, Option<CodecError>) {
        output.writer_hint(input.len());

        fn map_two_bytes(lead: u8, trail: u8) -> u32 {
            let lead = lead as uint;
            let trail = trail as uint;
            let index = match (lead, trail) {
                (0x81..0xfe, 0x40..0x7e) | (0x81..0xfe, 0xa1..0xfe) => {
                    let trailoffset = if trail < 0x7f {0x40} else {0x62};
                    (lead - 0x81) * 157 + trail - trailoffset
                }
                _ => 0xffff,
            };
            index::forward(index as u16) // may return two-letter replacements 0..3
        }

        let mut i = 0;
        let mut processed = 0;
        let len = input.len();

        if i >= len { return (processed, None); }

        if self.lead != 0 {
            match map_two_bytes(self.lead, input[i]) {
                0xffff => {
                    self.lead = 0;
                    let upto = if input[i] < 0x80 {i} else {i+1};
                    return (processed, Some(CodecError {
                        upto: upto, cause: "invalid sequence".into_send_str()
                    }));
                }
                0 /*index=1133*/ => { output.write_str("\u00ca\u0304"); }
                1 /*index=1135*/ => { output.write_str("\u00ca\u030c"); }
                2 /*index=1164*/ => { output.write_str("\u00ea\u0304"); }
                3 /*index=1166*/ => { output.write_str("\u00ea\u030c"); }
                ch => { output.write_char(as_char(ch)); }
            }
            i += 1;
        }

        self.lead = 0;
        processed = i;
        while i < len {
            match input[i] {
                0x00..0x7f => { output.write_char(input[i] as char); }
                0x81..0xfe => {
                    i += 1;
                    if i >= len {
                        self.lead = input[i-1];
                        break;
                    }
                    match map_two_bytes(input[i-1], input[i]) {
                        0xffff => {
                            let upto = if input[i] < 0x80 {i} else {i+1};
                            return (processed, Some(CodecError {
                                upto: upto, cause: "invalid sequence".into_send_str()
                            }));
                        }
                        0 /*index=1133*/ => { output.write_str("\u00ca\u0304"); }
                        1 /*index=1135*/ => { output.write_str("\u00ca\u030c"); }
                        2 /*index=1164*/ => { output.write_str("\u00ea\u0304"); }
                        3 /*index=1166*/ => { output.write_str("\u00ea\u030c"); }
                        ch => { output.write_char(as_char(ch)); }
                    }
                }
                _ => {
                    return (processed, Some(CodecError {
                        upto: i+1, cause: "invalid sequence".into_send_str()
                    }));
                }
            }
            i += 1;
            processed = i;
        }
        (processed, None)
    }

    fn raw_finish(&mut self, _output: &mut StringWriter) -> Option<CodecError> {
        let lead = self.lead;
        self.lead = 0;
        if lead != 0 {
            Some(CodecError { upto: 0, cause: "incomplete sequence".into_send_str() })
        } else {
            None
        }
    }
}

#[cfg(test)]
mod bigfive2003_tests {
    use super::BigFive2003Encoding;
    use types::*;

    #[test]
    fn test_encoder_valid() {
        let mut e = BigFive2003Encoding.encoder();
        assert_feed_ok!(e, "A", "", [0x41]);
        assert_feed_ok!(e, "BC", "", [0x42, 0x43]);
        assert_feed_ok!(e, "", "", []);
        assert_feed_ok!(e, "\u4e2d\u83ef\u6c11\u570b", "",
                        [0xa4, 0xa4, 0xb5, 0xd8, 0xa5, 0xc1, 0xb0, 0xea]);
        assert_feed_ok!(e, "1\u20ac/m", "", [0x31, 0xa3, 0xe1, 0x2f, 0x6d]);
        assert_feed_ok!(e, "\uffed", "", [0xf9, 0xfe]);
        assert_finish_ok!(e, []);
    }

    #[test]
    fn test_encoder_invalid() {
        let mut e = BigFive2003Encoding.encoder();
        assert_feed_err!(e, "", "\uffff", "", []);
        assert_feed_err!(e, "?", "\uffff", "!", [0x3f]);
        assert_feed_err!(e, "", "\u3eec", "\u4e00", []); // HKSCS-2008 addition
        assert_finish_ok!(e, []);
    }

    #[test]
    fn test_decoder_valid() {
        let mut d = BigFive2003Encoding.decoder();
        assert_feed_ok!(d, [0x41], [], "A");
        assert_feed_ok!(d, [0x42, 0x43], [], "BC");
        assert_feed_ok!(d, [], [], "");
        assert_feed_ok!(d, [0xa4, 0xa4, 0xb5, 0xd8, 0xa5, 0xc1, 0xb0, 0xea], [],
                        "\u4e2d\u83ef\u6c11\u570b");
        assert_feed_ok!(d, [0x31, 0xa3, 0xe1, 0x2f, 0x6d], [], "1\u20ac/m");
        assert_feed_ok!(d, [0xf9, 0xfe], [], "\uffed");
        assert_feed_ok!(d, [0x87, 0x7e], [], "\u3eec"); // HKSCS-2008 addition
        assert_finish_ok!(d, "");
    }

    #[test]
    fn test_decoder_invalid_trail() {
        // unlike most other cases, valid lead + invalid MSB-set trail are entirely consumed.
        // https://www.w3.org/Bugs/Public/show_bug.cgi?id=16771
        let mut d = BigFive2003Encoding.decoder();
        assert_feed_err!(d, [], [0xf0], [0x30, 0x30], "");
        assert_feed_err!(d, [], [0xf0, 0x80], [0x30], "");
        assert_finish_ok!(d, "");
    }

    // TODO more tests

    #[test]
    fn test_decoder_feed_after_finish() {
        let mut d = BigFive2003Encoding.decoder();
        assert_feed_ok!(d, [0xa4, 0x40], [0xa4], "\u4e00");
        assert_finish_err!(d, "");
        assert_feed_ok!(d, [0xa4, 0x40], [], "\u4e00");
        assert_finish_ok!(d, "");
    }
}

<|endoftext|>