<commit_before>//! rfc1071 checksum abstraction

/// Calculates rfc1071 checksum value
pub fn computeChecksum(packet: &[u8]) -> u16 {
    let len = packet.len();
    let mut sum = 0u32;
    let mut i = 0;
    while i < len {
        let word = (packet[i] as u32) << 8 | packet[i + 1] as u32;
        sum = sum + word;
        i = i + 2;
    }
    while sum >> 16 != 0 {
        sum = (sum >> 16) + (sum & 0xFFFF);
    }
    return !sum as u16;
}
<commit_msg>renamed generic checksum function to a snake-case name<commit_after>//! rfc1071 checksum abstraction

/// Calculates rfc1071 checksum value
pub fn compute_rfc1071_checksum(packet: &[u8]) -> u16 {
    let len = packet.len();
    let mut sum = 0u32;
    let mut i = 0;
    while i < len {
        let word = (packet[i] as u32) << 8 | packet[i + 1] as u32;
        sum = sum + word;
        i = i + 2;
    }
    while sum >> 16 != 0 {
        sum = (sum >> 16) + (sum & 0xFFFF);
    }
    return !sum as u16;
}
<|endoftext|>


<commit_before>pub enum Expression {
  IdentifierExpression {name: String}
}

pub enum PatternElement {
  TextElement {value: String},
  Placeable {expressions: Vec<Expression>}
}

pub enum Value {
  Pattern {source: String, elements: Vec<PatternElement>}
}

pub enum Entry {
  Entity {id: Identifier, value: Value}
}

pub struct Identifier {
  pub name: String,
  pub namespace: String
}

pub struct Parser<'a> {
  source: std::str::Chars<'a>,
  ch: Option<char>,
  pos: u16
}

impl<'a> Parser<'a> {
  pub fn new(source: &'a str) -> Parser<'a> {
    Parser {
      source: source.chars(),
      ch: None,
      pos: 0
    }
  }

  fn bump(&mut self) {
    self.ch = self.source.next();

    self.pos += 1;
  }

  fn ch_is(&self, ch: char) -> bool {
    self.ch == Some(ch)
  }

  fn get_ws(&mut self) {
    while self.ch_is(' ') ||
          self.ch_is('\n') ||
          self.ch_is('\t') ||
          self.ch_is('\r') { self.bump(); }
  }

  fn get_line_ws(&mut self) {
    while self.ch_is(' ') ||
          self.ch_is('\t') { self.bump(); }
  }

  pub fn parse(&mut self) -> Vec<Entry> {
    let mut entries: Vec<Entry> = Vec::new();

    self.get_ws();

    self.bump();

    loop {
      if self.ch == None {
        break;
      }

      entries.push(self.get_entry());
      self.get_ws();
    }
    entries
  }

  fn get_entry(&mut self) -> Entry {
    let val = self.get_entity();

    val
  }

  fn get_entity(&mut self) -> Entry {
    let id = self.get_identifier(true);
    self.get_line_ws();

    if !self.ch_is('=') {
      panic!();
    }
    self.bump();

    self.get_line_ws();

    let value = self.get_pattern();

    Entry::Entity{id: id, value: value}
  }

  fn get_identifier(&mut self, ns_sep: bool) -> Identifier {
    let mut id = String::new();
    let mut namespace = String::new();

    if ns_sep {
      let ns = self.get_identifier(false);
      if self.ch_is(':') {
        namespace = ns.name;
        self.bump();
      } else if ns.name.len() > 0 {
        id = ns.name;
      }
    }

    let ch = match self.ch {
      Some(c) => c,
      None => panic!(),
    };

    match ch {
      'a'...'z' | 'A'...'Z' | '_' => id.push(ch),
        _ => panic!(),
    }
    self.bump();

    loop {
      let ch = match self.ch {
        Some(c) => c,
        None => break,
      };

      match ch {
        'a'...'z' | 'A'...'Z' | '0'...'9' | '_' | '-' => id.push(ch),
        _ => break,
      }
      self.bump();
    }

    Identifier{name: id, namespace: namespace}
  }

  fn get_pattern(&mut self) -> Value {
    let mut s = String::new();
    let mut elements = vec![];

    loop {
      match self.ch {
        Some(c) if c == '\n' => { self.bump(); break },
        Some(c) => s.push(c),
        None => { break }
      }
      self.bump();
    }

    elements.push(PatternElement::TextElement {value: s.clone()});

    Value::Pattern{source: s, elements: elements}
  }
}
<commit_msg>Do not panic on namespace in get_identifeir<commit_after>pub enum Expression {
  IdentifierExpression {name: String}
}

pub enum PatternElement {
  TextElement {value: String},
  Placeable {expressions: Vec<Expression>}
}

pub enum Value {
  Pattern {source: String, elements: Vec<PatternElement>}
}

pub enum Entry {
  Entity {id: Identifier, value: Value}
}

pub struct Identifier {
  pub name: String,
  pub namespace: String
}

pub struct Parser<'a> {
  source: std::str::Chars<'a>,
  ch: Option<char>,
  pos: u16
}

impl<'a> Parser<'a> {
  pub fn new(source: &'a str) -> Parser<'a> {
    Parser {
      source: source.chars(),
      ch: None,
      pos: 0
    }
  }

  fn bump(&mut self) {
    self.ch = self.source.next();

    self.pos += 1;
  }

  fn ch_is(&self, ch: char) -> bool {
    self.ch == Some(ch)
  }

  fn get_ws(&mut self) {
    while self.ch_is(' ') ||
          self.ch_is('\n') ||
          self.ch_is('\t') ||
          self.ch_is('\r') { self.bump(); }
  }

  fn get_line_ws(&mut self) {
    while self.ch_is(' ') ||
          self.ch_is('\t') { self.bump(); }
  }

  pub fn parse(&mut self) -> Vec<Entry> {
    let mut entries: Vec<Entry> = Vec::new();

    self.get_ws();

    self.bump();

    loop {
      if self.ch == None {
        break;
      }

      entries.push(self.get_entry());
      self.get_ws();
    }
    entries
  }

  fn get_entry(&mut self) -> Entry {
    let val = self.get_entity();

    val
  }

  fn get_entity(&mut self) -> Entry {
    let id = self.get_identifier(true);
    self.get_line_ws();

    if !self.ch_is('=') {
      panic!();
    }
    self.bump();

    self.get_line_ws();

    let value = self.get_pattern();

    Entry::Entity{id: id, value: value}
  }

  fn get_identifier(&mut self, ns_sep: bool) -> Identifier {
    let mut id = String::new();
    let mut namespace = String::new();

    if ns_sep {
      let ns = self.get_identifier(false);
      if self.ch_is(':') {
        namespace = ns.name;
        self.bump();
      } else if ns.name.len() > 0 {
        id = ns.name;
      }
    }

    let ch = match self.ch {
      Some(c) => c,
      None => panic!(),
    };

    match ch {
      'a'...'z' | 'A'...'Z' | '_' => id.push(ch),
        _ => return Identifier{name: id, namespace: namespace},
    }
    self.bump();

    loop {
      let ch = match self.ch {
        Some(c) => c,
        None => break,
      };

      match ch {
        'a'...'z' | 'A'...'Z' | '0'...'9' | '_' | '-' => id.push(ch),
        _ => break,
      }
      self.bump();
    }

    Identifier{name: id, namespace: namespace}
  }

  fn get_pattern(&mut self) -> Value {
    let mut s = String::new();
    let mut elements = vec![];

    loop {
      match self.ch {
        Some(c) if c == '\n' => { self.bump(); break },
        Some(c) => s.push(c),
        None => { break }
      }
      self.bump();
    }

    elements.push(PatternElement::TextElement {value: s.clone()});

    Value::Pattern{source: s, elements: elements}
  }
}
<|endoftext|>


<commit_before>// Copyright 2012-2014 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.

use rustc_lint;
use rustc_driver::{driver, target_features, abort_on_err};
use rustc::dep_graph::DepGraph;
use rustc::session::{self, config};
use rustc::hir::def_id::DefId;
use rustc::hir::def::{Def, ExportMap};
use rustc::middle::privacy::AccessLevels;
use rustc::ty::{self, TyCtxt, GlobalArenas, Ty};
use rustc::hir::map as hir_map;
use rustc::lint;
use rustc::util::nodemap::{FxHashMap, NodeMap};
use rustc_trans::back::link;
use rustc_resolve as resolve;
use rustc_metadata::cstore::CStore;

use syntax::{ast, codemap};
use syntax::feature_gate::UnstableFeatures;
use errors;
use errors::emitter::ColorConfig;

use std::cell::{RefCell, Cell};
use std::mem;
use std::rc::Rc;
use std::path::PathBuf;

use visit_ast::RustdocVisitor;
use clean;
use clean::Clean;
use html::render::RenderInfo;
use arena::DroplessArena;

pub use rustc::session::config::Input;
pub use rustc::session::search_paths::SearchPaths;

pub type ExternalPaths = FxHashMap<DefId, (Vec<String>, clean::TypeKind)>;

pub struct DocContext<'a, 'tcx: 'a> {
    pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
    pub populated_all_crate_impls: Cell<bool>,
    // Note that external items for which `doc(hidden)` applies to are shown as
    // non-reachable while local items aren't. This is because we're reusing
    // the access levels from crateanalysis.
    /// Later on moved into `clean::Crate`
    pub access_levels: RefCell<AccessLevels<DefId>>,
    /// Later on moved into `html::render::CACHE_KEY`
    pub renderinfo: RefCell<RenderInfo>,
    /// Later on moved through `clean::Crate` into `html::render::CACHE_KEY`
    pub external_traits: RefCell<FxHashMap<DefId, clean::Trait>>,

    // The current set of type and lifetime substitutions,
    // for expanding type aliases at the HIR level:

    /// Table type parameter definition -> substituted type
    pub ty_substs: RefCell<FxHashMap<Def, clean::Type>>,
    /// Table node id of lifetime parameter definition -> substituted lifetime
    pub lt_substs: RefCell<FxHashMap<ast::NodeId, clean::Lifetime>>,
    pub export_map: ExportMap,

    /// Table from HIR Ty nodes to their resolved Ty.
    pub hir_ty_to_ty: NodeMap<Ty<'tcx>>,
}

impl<'a, 'tcx> DocContext<'a, 'tcx> {
    pub fn sess(&self) -> &session::Session {
        &self.tcx.sess
    }

    /// Call the closure with the given parameters set as
    /// the substitutions for a type alias' RHS.
    pub fn enter_alias<F, R>(&self,
                             ty_substs: FxHashMap<Def, clean::Type>,
                             lt_substs: FxHashMap<ast::NodeId, clean::Lifetime>,
                             f: F) -> R
    where F: FnOnce() -> R {
        let (old_tys, old_lts) =
            (mem::replace(&mut *self.ty_substs.borrow_mut(), ty_substs),
             mem::replace(&mut *self.lt_substs.borrow_mut(), lt_substs));
        let r = f();
        *self.ty_substs.borrow_mut() = old_tys;
        *self.lt_substs.borrow_mut() = old_lts;
        r
    }
}

pub trait DocAccessLevels {
    fn is_doc_reachable(&self, DefId) -> bool;
}

impl DocAccessLevels for AccessLevels<DefId> {
    fn is_doc_reachable(&self, did: DefId) -> bool {
        self.is_public(did)
    }
}

pub fn run_core(search_paths: SearchPaths,
                cfgs: Vec<String>,
                externs: config::Externs,
                input: Input,
                triple: Option<String>,
                maybe_sysroot: Option<PathBuf>) -> (clean::Crate, RenderInfo)
{
    // Parse, resolve, and typecheck the given crate.

    let cpath = match input {
        Input::File(ref p) => Some(p.clone()),
        _ => None
    };

    let warning_lint = lint::builtin::WARNINGS.name_lower();

    let sessopts = config::Options {
        maybe_sysroot: maybe_sysroot,
        search_paths: search_paths,
        crate_types: vec![config::CrateTypeRlib],
        lint_opts: vec![(warning_lint, lint::Allow)],
        lint_cap: Some(lint::Allow),
        externs: externs,
        target_triple: triple.unwrap_or(config::host_triple().to_string()),
        // Ensure that rustdoc works even if rustc is feature-staged
        unstable_features: UnstableFeatures::Allow,
        actually_rustdoc: true,
        ..config::basic_options().clone()
    };

    let codemap = Rc::new(codemap::CodeMap::new());
    let diagnostic_handler = errors::Handler::with_tty_emitter(ColorConfig::Auto,
                                                               true,
                                                               false,
                                                               Some(codemap.clone()));

    let dep_graph = DepGraph::new(false);
    let _ignore = dep_graph.in_ignore();
    let cstore = Rc::new(CStore::new(&dep_graph));
    let mut sess = session::build_session_(
        sessopts, &dep_graph, cpath, diagnostic_handler, codemap, cstore.clone()
    );
    rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));

    let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs));
    target_features::add_configuration(&mut cfg, &sess);
    sess.parse_sess.config = cfg;

    let krate = panictry!(driver::phase_1_parse_input(&sess, &input));

    let name = link::find_crate_name(Some(&sess), &krate.attrs, &input);

    let driver::ExpansionResult { defs, analysis, resolutions, mut hir_forest, .. } = {
        driver::phase_2_configure_and_expand(
            &sess, &cstore, krate, None, &name, None, resolve::MakeGlobMap::No, |_| Ok(()),
        ).expect("phase_2_configure_and_expand aborted in rustdoc!")
    };

    let arena = DroplessArena::new();
    let arenas = GlobalArenas::new();
    let hir_map = hir_map::map_crate(&mut hir_forest, defs);

    abort_on_err(driver::phase_3_run_analysis_passes(&sess,
                                                     hir_map,
                                                     analysis,
                                                     resolutions,
                                                     &arena,
                                                     &arenas,
                                                     &name,
                                                     |tcx, analysis, _, result| {
        if let Err(_) = result {
            sess.fatal("Compilation failed, aborting rustdoc");
        }

        let ty::CrateAnalysis { access_levels, export_map, hir_ty_to_ty, .. } = analysis;

        // Convert from a NodeId set to a DefId set since we don't always have easy access
        // to the map from defid -> nodeid
        let access_levels = AccessLevels {
            map: access_levels.map.into_iter()
                                  .map(|(k, v)| (tcx.map.local_def_id(k), v))
                                  .collect()
        };

        let ctxt = DocContext {
            tcx: tcx,
            populated_all_crate_impls: Cell::new(false),
            access_levels: RefCell::new(access_levels),
            external_traits: Default::default(),
            renderinfo: Default::default(),
            ty_substs: Default::default(),
            lt_substs: Default::default(),
            export_map: export_map,
            hir_ty_to_ty: hir_ty_to_ty,
        };
        debug!("crate: {:?}", tcx.map.krate());

        let krate = {
            let mut v = RustdocVisitor::new(&ctxt);
            v.visit(tcx.map.krate());
            v.clean(&ctxt)
        };

        (krate, ctxt.renderinfo.into_inner())
    }), &sess)
}
<commit_msg>Avoid rustdoc ICE when an unstable feature is used<commit_after>// Copyright 2012-2014 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.

use rustc_lint;
use rustc_driver::{driver, target_features, abort_on_err};
use rustc::dep_graph::DepGraph;
use rustc::session::{self, config};
use rustc::hir::def_id::DefId;
use rustc::hir::def::{Def, ExportMap};
use rustc::middle::privacy::AccessLevels;
use rustc::ty::{self, TyCtxt, GlobalArenas, Ty};
use rustc::hir::map as hir_map;
use rustc::lint;
use rustc::util::nodemap::{FxHashMap, NodeMap};
use rustc_trans::back::link;
use rustc_resolve as resolve;
use rustc_metadata::cstore::CStore;

use syntax::{ast, codemap};
use syntax::feature_gate::UnstableFeatures;
use errors;
use errors::emitter::ColorConfig;

use std::cell::{RefCell, Cell};
use std::mem;
use std::rc::Rc;
use std::path::PathBuf;

use visit_ast::RustdocVisitor;
use clean;
use clean::Clean;
use html::render::RenderInfo;
use arena::DroplessArena;

pub use rustc::session::config::Input;
pub use rustc::session::search_paths::SearchPaths;

pub type ExternalPaths = FxHashMap<DefId, (Vec<String>, clean::TypeKind)>;

pub struct DocContext<'a, 'tcx: 'a> {
    pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
    pub populated_all_crate_impls: Cell<bool>,
    // Note that external items for which `doc(hidden)` applies to are shown as
    // non-reachable while local items aren't. This is because we're reusing
    // the access levels from crateanalysis.
    /// Later on moved into `clean::Crate`
    pub access_levels: RefCell<AccessLevels<DefId>>,
    /// Later on moved into `html::render::CACHE_KEY`
    pub renderinfo: RefCell<RenderInfo>,
    /// Later on moved through `clean::Crate` into `html::render::CACHE_KEY`
    pub external_traits: RefCell<FxHashMap<DefId, clean::Trait>>,

    // The current set of type and lifetime substitutions,
    // for expanding type aliases at the HIR level:

    /// Table type parameter definition -> substituted type
    pub ty_substs: RefCell<FxHashMap<Def, clean::Type>>,
    /// Table node id of lifetime parameter definition -> substituted lifetime
    pub lt_substs: RefCell<FxHashMap<ast::NodeId, clean::Lifetime>>,
    pub export_map: ExportMap,

    /// Table from HIR Ty nodes to their resolved Ty.
    pub hir_ty_to_ty: NodeMap<Ty<'tcx>>,
}

impl<'a, 'tcx> DocContext<'a, 'tcx> {
    pub fn sess(&self) -> &session::Session {
        &self.tcx.sess
    }

    /// Call the closure with the given parameters set as
    /// the substitutions for a type alias' RHS.
    pub fn enter_alias<F, R>(&self,
                             ty_substs: FxHashMap<Def, clean::Type>,
                             lt_substs: FxHashMap<ast::NodeId, clean::Lifetime>,
                             f: F) -> R
    where F: FnOnce() -> R {
        let (old_tys, old_lts) =
            (mem::replace(&mut *self.ty_substs.borrow_mut(), ty_substs),
             mem::replace(&mut *self.lt_substs.borrow_mut(), lt_substs));
        let r = f();
        *self.ty_substs.borrow_mut() = old_tys;
        *self.lt_substs.borrow_mut() = old_lts;
        r
    }
}

pub trait DocAccessLevels {
    fn is_doc_reachable(&self, DefId) -> bool;
}

impl DocAccessLevels for AccessLevels<DefId> {
    fn is_doc_reachable(&self, did: DefId) -> bool {
        self.is_public(did)
    }
}

pub fn run_core(search_paths: SearchPaths,
                cfgs: Vec<String>,
                externs: config::Externs,
                input: Input,
                triple: Option<String>,
                maybe_sysroot: Option<PathBuf>) -> (clean::Crate, RenderInfo)
{
    // Parse, resolve, and typecheck the given crate.

    let cpath = match input {
        Input::File(ref p) => Some(p.clone()),
        _ => None
    };

    let warning_lint = lint::builtin::WARNINGS.name_lower();

    let sessopts = config::Options {
        maybe_sysroot: maybe_sysroot,
        search_paths: search_paths,
        crate_types: vec![config::CrateTypeRlib],
        lint_opts: vec![(warning_lint, lint::Allow)],
        lint_cap: Some(lint::Allow),
        externs: externs,
        target_triple: triple.unwrap_or(config::host_triple().to_string()),
        // Ensure that rustdoc works even if rustc is feature-staged
        unstable_features: UnstableFeatures::Allow,
        actually_rustdoc: true,
        ..config::basic_options().clone()
    };

    let codemap = Rc::new(codemap::CodeMap::new());
    let diagnostic_handler = errors::Handler::with_tty_emitter(ColorConfig::Auto,
                                                               true,
                                                               false,
                                                               Some(codemap.clone()));

    let dep_graph = DepGraph::new(false);
    let _ignore = dep_graph.in_ignore();
    let cstore = Rc::new(CStore::new(&dep_graph));
    let mut sess = session::build_session_(
        sessopts, &dep_graph, cpath, diagnostic_handler, codemap, cstore.clone()
    );
    rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));

    let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs));
    target_features::add_configuration(&mut cfg, &sess);
    sess.parse_sess.config = cfg;

    let krate = panictry!(driver::phase_1_parse_input(&sess, &input));

    let name = link::find_crate_name(Some(&sess), &krate.attrs, &input);

    let driver::ExpansionResult { defs, analysis, resolutions, mut hir_forest, .. } = {
        let result = driver::phase_2_configure_and_expand(&sess,
                                                          &cstore,
                                                          krate,
                                                          None,
                                                          &name,
                                                          None,
                                                          resolve::MakeGlobMap::No,
                                                          |_| Ok(()));
        abort_on_err(result, &sess)
    };

    let arena = DroplessArena::new();
    let arenas = GlobalArenas::new();
    let hir_map = hir_map::map_crate(&mut hir_forest, defs);

    abort_on_err(driver::phase_3_run_analysis_passes(&sess,
                                                     hir_map,
                                                     analysis,
                                                     resolutions,
                                                     &arena,
                                                     &arenas,
                                                     &name,
                                                     |tcx, analysis, _, result| {
        if let Err(_) = result {
            sess.fatal("Compilation failed, aborting rustdoc");
        }

        let ty::CrateAnalysis { access_levels, export_map, hir_ty_to_ty, .. } = analysis;

        // Convert from a NodeId set to a DefId set since we don't always have easy access
        // to the map from defid -> nodeid
        let access_levels = AccessLevels {
            map: access_levels.map.into_iter()
                                  .map(|(k, v)| (tcx.map.local_def_id(k), v))
                                  .collect()
        };

        let ctxt = DocContext {
            tcx: tcx,
            populated_all_crate_impls: Cell::new(false),
            access_levels: RefCell::new(access_levels),
            external_traits: Default::default(),
            renderinfo: Default::default(),
            ty_substs: Default::default(),
            lt_substs: Default::default(),
            export_map: export_map,
            hir_ty_to_ty: hir_ty_to_ty,
        };
        debug!("crate: {:?}", tcx.map.krate());

        let krate = {
            let mut v = RustdocVisitor::new(&ctxt);
            v.visit(tcx.map.krate());
            v.clean(&ctxt)
        };

        (krate, ctxt.renderinfo.into_inner())
    }), &sess)
}
<|endoftext|>


<commit_before>#[crate_id = "client"];

extern mod http;
use http::client::RequestWriter;
use http::method::Get;
use http::headers::HeaderEnum;
use std::os;
use std::str;
use std::io::Reader;

fn main() {
    format!("{}", Get);
    let args = os::args();
    match args.len() {
        0 => unreachable!(),
        2 => make_and_print_request(args[1]),
        _ => {
            println!("Usage: {} URL", args[0]);
            return;
        },
    };
}

fn make_and_print_request(url: ~str) {
    let request = RequestWriter::new(Get, from_str(url).expect("Invalid URL :-("));

    println!("Request");
    println!("=======");
    println!("");
    println!("URL: {}", request.url.to_str());
    println!("Remote address: {:?}", request.remote_addr);
    println!("Method: {}", request.method);
    println!("Headers:");
    for header in request.headers.iter() {
        println!(" - {}: {}", header.header_name(), header.header_value());
    }

    println!("");
    println!("Response");
    println!("========");
    println!("");
    let mut response = match request.read_response() {
        Ok(response) => response,
        Err(_request) => fail!("This example can progress no further with no response :-("),
    };
    println!("Status: {}", response.status);
    println!("Headers:");
    for header in response.headers.iter() {
        println!(" - {}: {}", header.header_name(), header.header_value());
    }
    println!("Body:");
    let body = response.read_to_end();
    println!(str::from_utf8(body));
}
<commit_msg>Use println-the-function in one place.<commit_after>#[crate_id = "client"];

extern mod http;
use http::client::RequestWriter;
use http::method::Get;
use http::headers::HeaderEnum;
use std::os;
use std::str;
use std::io::{Reader, println};

fn main() {
    format!("{}", Get);
    let args = os::args();
    match args.len() {
        0 => unreachable!(),
        2 => make_and_print_request(args[1]),
        _ => {
            println!("Usage: {} URL", args[0]);
            return;
        },
    };
}

fn make_and_print_request(url: ~str) {
    let request = RequestWriter::new(Get, from_str(url).expect("Invalid URL :-("));

    println!("Request");
    println!("=======");
    println!("");
    println!("URL: {}", request.url.to_str());
    println!("Remote address: {:?}", request.remote_addr);
    println!("Method: {}", request.method);
    println!("Headers:");
    for header in request.headers.iter() {
        println!(" - {}: {}", header.header_name(), header.header_value());
    }

    println!("");
    println!("Response");
    println!("========");
    println!("");
    let mut response = match request.read_response() {
        Ok(response) => response,
        Err(_request) => fail!("This example can progress no further with no response :-("),
    };
    println!("Status: {}", response.status);
    println!("Headers:");
    for header in response.headers.iter() {
        println!(" - {}: {}", header.header_name(), header.header_value());
    }
    println!("Body:");
    let body = response.read_to_end();
    println(str::from_utf8(body));
}
<|endoftext|>


<commit_before>use basenum::BaseFloat;
use builtin::{ cross, dot, normalize };
use traits::GenFloat;
use num;
use mat::mat::{ Matrix3, Matrix4 };
use vec::vec::{ Vector3, Vector4 };

/// Builds a translation 4 * 4 matrix created from a vector of 3 components.
///
/// Uses input matrix `m` and translation vector coordinates `v`.
///
/// # Example
///
/// ```rust
/// # extern crate num;
/// # extern crate glm;
/// # fn main() {
/// use glm::*;
/// use glm::ext::*;
///
/// let matrix = translate(&num::one(), vec3(1., 2., 3.));
/// assert_eq!(matrix[3], vec4(1., 2., 3., 1.));
/// # }
/// ```
#[inline]
pub fn translate<T>(
    m: &Matrix4<T>,
    v: Vector3<T>
) -> Matrix4<T>
where
    T : BaseFloat
{
    Matrix4::new(
        m.c0, m.c1, m.c2,
        m.c0 * v.x + m.c1 * v.y + m.c2 * v.z + m.c3)
}

#[inline]
pub fn perspective<T>(
    fov_y: T,
    aspect: T,
    z_near: T,
    z_far: T
) -> Matrix4<T>
where
    T : BaseFloat
{
    let zero = num::zero::<T>();
    let one = num::one::<T>();
    let two = one + one;
    let q = one / (fov_y / two).tan();
    let a = q / aspect;
    let b = (z_near + z_far) / (z_near - z_far);
    let c = (two * z_near * z_far) / (z_near - z_far);

    Matrix4::new(
        Vector4::new(   a, zero, zero, zero),
        Vector4::new(zero,    q, zero, zero),
        Vector4::new(zero, zero,    b, zero - one),
        Vector4::new(zero, zero,    c, zero)
    )
}

#[inline]
pub fn rotate<T>(
    m: &Matrix4<T>,
    angle: T,
    v: Vector3<T>
) -> Matrix4<T>
where
    T : BaseFloat + GenFloat<T>
{
    let zero = num::zero::<T>();
    let one = num::one::<T>();

    let a = angle;
    let (s, c) = a.sin_cos();
    let axis = normalize(v);
    let temp = axis * (one - c);

    let rotate = Matrix3::new(
        Vector3::new(
            c + temp.x * axis.x,
            temp.x * axis.y + s * axis.z,
            temp.x * axis.z - s * axis.y),
        Vector3::new(
            temp.y * axis.x - s * axis.z,
            c + temp.y * axis.y,
            temp.y * axis.z + s * axis.x),
        Vector3::new(
            temp.z * axis.x + s * axis.y,
            temp.z * axis.y - s * axis.x,
            c + temp.z * axis.z)
        );

    Matrix4::new(
		m.c0 * rotate.c0.x + m.c1 * rotate.c0.y + m.c2 * rotate.c0.z,
		m.c0 * rotate.c1.x + m.c1 * rotate.c1.y + m.c2 * rotate.c1.z,
		m.c0 * rotate.c2.x + m.c1 * rotate.c2.y + m.c2 * rotate.c2.z,
		m.c3
        )
}

#[inline]
pub fn scale<T>(
    m: &Matrix4<T>,
    v: Vector3<T>
) -> Matrix4<T>
where
    T : BaseFloat + GenFloat<T>
{
    Matrix4::new(
        m.c0 * v.x,
        m.c1 * v.y,
        m.c2 * v.z,
        m.c3)
}

#[inline]
pub fn look_at<T>(
    eye: Vector3<T>,
    center: Vector3<T>,
    up: Vector3<T>
) -> Matrix4<T>
where
    T : BaseFloat + GenFloat<T>
{
    let zero = num::zero::<T>();
    let one = num::one::<T>();
    let f = normalize(center - eye);
    let up_n = normalize(up);
    let s = cross(f, up_n);
    let u = cross(s, f);
    Matrix4::new(
        Vector4::new(s.x, u.x,-f.x, zero),
        Vector4::new(s.y, u.y,-f.y, zero),
        Vector4::new(s.z, u.z,-f.z, zero),
        Vector4::new(-dot(s, eye), -dot(u, eye), dot(f, eye), one)
    )
}

#[cfg(test)]
mod test {
    use num;
    use std::f32;
    use vec::vec::{ vec3, vec4 };
    use ext::{ perspective, translate };

    #[test]
    fn test_translate() {
        let v = vec3(1.0, 3.0, 2.0);
        let m = num::one();
        let t = translate(&m, v);
        assert_eq!(t[0], vec4(1., 0., 0., 0.));
        assert_eq!(t[1], vec4(0., 1., 0., 0.));
        assert_eq!(t[2], vec4(0., 0., 1., 0.));
        assert_eq!(t[3], v.extend(1.));
    }

    #[test]
    fn test_perspective() {
        let p = perspective(f32::consts::PI * 2.0 * 45.0 / 360.0, 1920.0 / 1080.0, 0.1, 100.0);
    }
}
<commit_msg>Added RH perspective and look_at and docs.<commit_after>use basenum::BaseFloat;
use builtin::{ cross, dot, normalize };
use traits::GenFloat;
use num;
use mat::mat::{ Matrix3, Matrix4 };
use vec::vec::{ Vector3, Vector4 };

/// Builds a translation 4 * 4 matrix created from a vector of 3 components.
///
/// Uses input matrix `m` and translation vector coordinates `v`.
///
/// # Example
///
/// ```rust
/// # extern crate num;
/// # extern crate glm;
/// # fn main() {
/// use glm::*;
/// use glm::ext::*;
///
/// let matrix = translate(&num::one(), vec3(1., 2., 3.));
/// assert_eq!(matrix[3], vec4(1., 2., 3., 1.));
/// # }
/// ```
#[inline]
pub fn translate<T>(
    m: &Matrix4<T>,
    v: Vector3<T>
) -> Matrix4<T>
where
    T : BaseFloat
{
    Matrix4::new(
        m.c0, m.c1, m.c2,
        m.c0 * v.x + m.c1 * v.y + m.c2 * v.z + m.c3)
}

#[inline]
/// Creates a matrix for a symetric perspective-view frustum based on the default handedness.
///
/// `fov_y` is the field of view angle in the y direction in radians.
/// The `aspect` ratio determines the field of view in the x direction.
/// `near_z` is the distance from the viewer to the near clipping plane (always positive) and
/// `far_z` is the distance from the viewer to the far clipping plane (always positive).
pub fn perspective<T>(
    fov_y: T,
    aspect: T,
    z_near: T,
    z_far: T
) -> Matrix4<T>
where
    T : BaseFloat
{
    // TODO: make this a compile option
    perspective_rh(fov_y, aspect, z_near, z_far)
}

#[inline]
/// Creates a matrix for a right handed, symetric perspective-view frustum.
///
/// `fov_y` is the field of view angle in the y direction in radians.
/// The `aspect` ratio determines the field of view in the x direction.
/// `near_z` is the distance from the viewer to the near clipping plane (always positive) and
/// `far_z` is the distance from the viewer to the far clipping plane (always positive).
pub fn perspective_rh<T>(
    fov_y: T,
    aspect: T,
    z_near: T,
    z_far: T
) -> Matrix4<T>
where
    T : BaseFloat
{
    let zero = num::zero::<T>();
    let one = num::one::<T>();
    let two = one + one;
    let q = one / (fov_y / two).tan();
    let a = q / aspect;
    let b = (z_near + z_far) / (z_near - z_far);
    let c = (two * z_near * z_far) / (z_near - z_far);

    Matrix4::new(
        Vector4::new(   a, zero, zero, zero),
        Vector4::new(zero,    q, zero, zero),
        Vector4::new(zero, zero,    b, zero - one),
        Vector4::new(zero, zero,    c, zero)
    )
}

#[inline]
/// Builds a rotation 4 * 4 matrix created from an axis vector and an angle.
///
/// `m` as the input matrix multiplied by this rotation matrix.
/// `angle` is the rotation angle expressed in radians.
/// Rotation `axis` is recommended to be normalized.
pub fn rotate<T>(
    m: &Matrix4<T>,
    angle: T,
    v: Vector3<T>
) -> Matrix4<T>
where
    T : BaseFloat + GenFloat<T>
{
    let zero = num::zero::<T>();
    let one = num::one::<T>();

    let a = angle;
    let (s, c) = a.sin_cos();
    let axis = normalize(v);
    let temp = axis * (one - c);

    let rotate = Matrix3::new(
        Vector3::new(
            c + temp.x * axis.x,
            temp.x * axis.y + s * axis.z,
            temp.x * axis.z - s * axis.y),
        Vector3::new(
            temp.y * axis.x - s * axis.z,
            c + temp.y * axis.y,
            temp.y * axis.z + s * axis.x),
        Vector3::new(
            temp.z * axis.x + s * axis.y,
            temp.z * axis.y - s * axis.x,
            c + temp.z * axis.z)
        );

    Matrix4::new(
		m.c0 * rotate.c0.x + m.c1 * rotate.c0.y + m.c2 * rotate.c0.z,
		m.c0 * rotate.c1.x + m.c1 * rotate.c1.y + m.c2 * rotate.c1.z,
		m.c0 * rotate.c2.x + m.c1 * rotate.c2.y + m.c2 * rotate.c2.z,
		m.c3
        )
}

#[inline]
/// Builds a scale 4 * 4 matrix created from 3 scalars.
///
/// `m` is the input matrix multiplied by this scale matrix.
/// `v` is the ratio of scaling for each axis.
pub fn scale<T>(
    m: &Matrix4<T>,
    v: Vector3<T>
) -> Matrix4<T>
where
    T : BaseFloat + GenFloat<T>
{
    Matrix4::new(
        m.c0 * v.x,
        m.c1 * v.y,
        m.c2 * v.z,
        m.c3)
}

#[inline]
/// Build a look at view matrix based on the default handedness.
///
/// View matrix is based on the `eye` position of the camera, `center` position where the camera is
/// looking at and a normalized `up` vector, how the camera is oriented. Typically (0, 0, 1)
pub fn look_at<T>(
    eye: Vector3<T>,
    center: Vector3<T>,
    up: Vector3<T>
) -> Matrix4<T>
where
    T : BaseFloat + GenFloat<T>
{
    // TODO: make handedness configurable
    look_at_rh::<T>(eye, center, up)
}

#[inline]
/// Build a right handed look at view matrix.
///
/// View matrix is based on the `eye` position of the camera, `center` position where the camera is
/// looking at and a normalized `up` vector, how the camera is oriented. Typically (0, 0, 1)
pub fn look_at_rh<T>(
    eye: Vector3<T>,
    center: Vector3<T>,
    up: Vector3<T>
) -> Matrix4<T>
where
    T : BaseFloat + GenFloat<T>
{
    let zero = num::zero::<T>();
    let one = num::one::<T>();
    let f = normalize(center - eye);
    let up_n = normalize(up);
    let s = cross(f, up_n);
    let u = cross(s, f);
    Matrix4::new(
        Vector4::new(s.x, u.x,-f.x, zero),
        Vector4::new(s.y, u.y,-f.y, zero),
        Vector4::new(s.z, u.z,-f.z, zero),
        Vector4::new(-dot(s, eye), -dot(u, eye), dot(f, eye), one)
    )
}

#[cfg(test)]
mod test {
    use num;
    use std::f32;
    use vec::vec::{ vec3, vec4 };
    use ext::{ perspective, translate };

    #[test]
    fn test_translate() {
        let v = vec3(1.0, 3.0, 2.0);
        let m = num::one();
        let t = translate(&m, v);
        assert_eq!(t[0], vec4(1., 0., 0., 0.));
        assert_eq!(t[1], vec4(0., 1., 0., 0.));
        assert_eq!(t[2], vec4(0., 0., 1., 0.));
        assert_eq!(t[3], v.extend(1.));
    }

    #[test]
    fn test_perspective() {
        let p = perspective(f32::consts::PI * 2.0 * 45.0 / 360.0, 1920.0 / 1080.0, 0.1, 100.0);
    }
}
<|endoftext|>


<commit_before>use basenum::BaseFloat;
use mat::mat::Matrix4;
use vec::vec::Vector3;

/// Builds a translation 4 * 4 matrix created from a vector of 3 components.
///
/// Uses input matrix `m` and translation vector coordinates `v`.
///
/// # Example
///
/// ```rust
/// # extern crate num;
/// # extern crate glm;
/// # fn main() {
/// use glm::*;
/// use glm::ext::*;
///
/// let matrix = translate(&num::one(), vec3(1., 2., 3.));
/// assert_eq!(matrix[3], vec4(1., 2., 3., 1.));
/// # }
/// ```
#[inline]
pub fn translate
(
    m: &Matrix4
,
    v: Vector3

) -> Matrix4

where
    P : BaseFloat
{
    let mut result = m.clone();
    result[3] = m[0] * v[0] + m[1] * v[1] + m[2] * v[2] + m[3];
    result
}

#[cfg(test)]
mod test {
    use num;
    use vec::vec::{ vec3, vec4 };
    use ext::translate;

    #[test]
    fn test_translate() {
        let v = vec3(1.0, 3.0, 2.0);
        let m = num::one();
        let t = translate(&m, v);
        assert_eq!(t[0], vec4(1., 0., 0., 0.));
        assert_eq!(t[1], vec4(0., 1., 0., 0.));
        assert_eq!(t[2], vec4(0., 0., 1., 0.));
        assert_eq!(t[3], v.extend(1.));
    }
}
<commit_msg>Added rotate, perspective and look_at.<commit_after>use basenum::BaseFloat;
use builtin::{ cross, dot, normalize };
use traits::GenFloat;
use num;
use mat::mat::{ Matrix3, Matrix4 };
use vec::vec::{ Vector3, Vector4 };

/// Builds a translation 4 * 4 matrix created from a vector of 3 components.
///
/// Uses input matrix `m` and translation vector coordinates `v`.
///
/// # Example
///
/// ```rust
/// # extern crate num;
/// # extern crate glm;
/// # fn main() {
/// use glm::*;
/// use glm::ext::*;
///
/// let matrix = translate(&num::one(), vec3(1., 2., 3.));
/// assert_eq!(matrix[3], vec4(1., 2., 3., 1.));
/// # }
/// ```
#[inline]
pub fn translate
(
    m: &Matrix4
,
    v: Vector3

) -> Matrix4

where
    P : BaseFloat
{
    Matrix4::new(
        m.c0, m.c1, m.c2,
        m.c0 * v.x + m.c1 * v.y + m.c2 * v.z + m.c3)
}

#[inline]
pub fn perspective
(
    fov_y: P,
    aspect: P,
    z_near: P,
    z_far: P
) -> Matrix4

where
    P : BaseFloat
{
    let zero = num::zero::
();
    let one = num::one::
();
    let two = one + one;
    let q = one / (fov_y / two).tan();
    let a = q / aspect;
    let b = (z_near + z_far) / (z_near - z_far);
    let c = (two * z_near * z_far) / (z_near - z_far);

    Matrix4::new(
        Vector4::new(   a, zero, zero, zero),
        Vector4::new(zero,    q, zero, zero),
        Vector4::new(zero, zero,    b, zero - one),
        Vector4::new(zero, zero,    c, zero)
    )
}

#[inline]
pub fn rotate
(
    m: Matrix4
,
    angle: P,
    v: Vector3

) -> Matrix4

where
    P : BaseFloat + GenFloat

{
    let zero = num::zero::
();
    let one = num::one::
();

    let a = angle;
    let (s, c) = a.sin_cos();
    let axis = normalize(v);
    let temp = axis * (one - c);

    let rotate = Matrix3::new(
        Vector3::new(
            c + temp.x * axis.x,
            temp.x * axis.y + s * axis.z,
            temp.x * axis.z - s * axis.y),
        Vector3::new(
            temp.y * axis.x - s * axis.z,
            c + temp.y * axis.y,
            temp.y * axis.z + s * axis.x),
        Vector3::new(
            temp.z * axis.x + s * axis.y,
            temp.z * axis.y - s * axis.x,
            c + temp.z * axis.z)
        );

    Matrix4::new(
		m.c0 * rotate.c0.x + m.c1 * rotate.c0.y + m.c2 * rotate.c0.z,
		m.c0 * rotate.c1.x + m.c1 * rotate.c1.y + m.c2 * rotate.c1.z,
		m.c0 * rotate.c2.x + m.c1 * rotate.c2.y + m.c2 * rotate.c2.z,
		m.c3
        )
}

#[inline]
pub fn look_at
(
    eye: Vector3
,
    center: Vector3
,
    up: Vector3

) -> Matrix4

where
    P : BaseFloat + GenFloat

{
    let zero = num::zero::
();
    let one = num::one::
();
    let f = normalize(center - eye);
    let up_n = normalize(up);
    let s = cross(f, up_n);
    let u = cross(s, f);
    Matrix4::new(
        Vector4::new(s.x, u.x,-f.x, zero),
        Vector4::new(s.y, u.y,-f.y, zero),
        Vector4::new(s.z, u.z,-f.z, zero),
        Vector4::new(-dot(s, eye), -dot(u, eye), dot(f, eye), one)
    )
}

#[cfg(test)]
mod test {
    use num;
    use std::f32;
    use vec::vec::{ vec3, vec4 };
    use ext::{ perspective, translate };

    #[test]
    fn test_translate() {
        let v = vec3(1.0, 3.0, 2.0);
        let m = num::one();
        let t = translate(&m, v);
        assert_eq!(t[0], vec4(1., 0., 0., 0.));
        assert_eq!(t[1], vec4(0., 1., 0., 0.));
        assert_eq!(t[2], vec4(0., 0., 1., 0.));
        assert_eq!(t[3], v.extend(1.));
    }

    #[test]
    fn test_perspective() {
        let p = perspective(f32::consts::PI * 2.0 * 45.0 / 360.0, 1920.0 / 1080.0, 0.1, 100.0);
    }
}
<|endoftext|>


<commit_before>//! Functions for finding and labelling connected components of an image.

use image::{
    GenericImage,
    ImageBuffer,
    Luma
};

use definitions::{
    VecBuffer
};

use unionfind::DisjointSetForest;

use std::cmp;
use std::collections::HashMap;

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum Connectivity { Four, Eight }

/// Returns an image of the same size as the input, where each pixel
/// is labelled by the connected foreground component it belongs to,
/// or 0 if it's in the background. Input pixels are treated as belonging
/// to the background if and only if they have value 0.
pub fn connected_components<I>(image: &I, conn: Connectivity)
        -> VecBuffer<Luma<u32>>
    where I: GenericImage<Pixel=Luma<u8>> {

    let (width, height) = image.dimensions();
    let mut out = ImageBuffer::new(width, height);

    // TODO: add macro to abandon early if either dimension is zero
    if width == 0 || height == 0 {
        return out;
    }

    let background = Luma([0u8]);
    let mut forest = DisjointSetForest::new((width * height) as usize);
    let mut adj_labels = [0u32; 4];
    let mut next_label = 1;

    for y in 0..height {
        for x in 0..width {
            out.put_pixel(x, y, Luma([0]));
        }

        for x in 0..width {

            let current = image.get_pixel(x, y);
            if current == background {
                continue;
            }

            let mut num_adj = 0;

            if x > 0 {
                // West
                let pixel = image.get_pixel(x - 1, y);
                if pixel == current {
                    let label = out.get_pixel(x - 1, y)[0];
                    adj_labels[num_adj] = label;
                    num_adj += 1;
                }
            }

            if y > 0 {
                // North
                let pixel = image.get_pixel(x, y - 1);
                if pixel == current {
                    let label = out.get_pixel(x, y - 1)[0];
                    adj_labels[num_adj] = label;
                    num_adj += 1;
                }

                if conn == Connectivity::Eight {
                    if x > 0 {
                        // North West
                        let pixel = image.get_pixel(x - 1, y - 1);
                        if pixel == current {
                            let label = out.get_pixel(x - 1, y - 1)[0];
                            adj_labels[num_adj] = label;
                            num_adj += 1;
                        }
                    }
                    if x < width - 1 {
                        // North East
                        let pixel = image.get_pixel(x + 1, y - 1);
                        if pixel == current {
                            let label = out.get_pixel(x + 1, y - 1)[0];
                            adj_labels[num_adj] = label;
                            num_adj += 1;
                        }
                    }
                }
            }

            if num_adj == 0 {
                out.put_pixel(x, y, Luma([next_label]));
                next_label += 1;
            }
            else {
                let mut min_label = u32::max_value();
                for n in 0..num_adj {
                    min_label = cmp::min(min_label, adj_labels[n]);
                }
                out.put_pixel(x, y, Luma([min_label]));
                for n in 0..num_adj {
                    forest.union(min_label as usize, adj_labels[n] as usize);
                }
            }
        }
    }

    // Make components start at 1
    let mut root_name = 1;
    let mut root_idx: HashMap<usize, usize> = HashMap::new();

    for y in 0..height {
        for x in 0..width {
            if image.get_pixel(x, y) == background {
                continue;
            }

            let label = out.get_pixel(x, y)[0];
            let root = forest.root(label as usize);

            match root_idx.get(&root).map(|x| *x) {
                Some(idx) => {
                    out.put_pixel(x, y, Luma([idx as u32]));
                }
                None => {
                    let idx = root_name;
                    root_idx.insert(root, idx);
                    out.put_pixel(x, y, Luma([idx as u32]));
                    root_name += 1;
                }
            }
        }
    }

    out
}

#[cfg(test)]
mod test {

    use super::{
        connected_components
    };
    use super::Connectivity::{
        Four,
        Eight
    };
    use image::{
        GrayImage,
        ImageBuffer,
        Luma
    };

    #[test]
    fn test_connected_components_four() {
        let image: GrayImage = ImageBuffer::from_raw(4, 4, vec![
            1, 0, 2, 1,
            0, 1, 1, 0,
            0, 0, 0, 0,
            0, 0, 0, 1]).unwrap();

        let expected: ImageBuffer<Luma<u32>, Vec<u32>>
            = ImageBuffer::from_raw(4, 4, vec![
                1, 0, 2, 3,
                0, 4, 4, 0,
                0, 0, 0, 0,
                0, 0, 0, 5]).unwrap();

        let labelled = connected_components(&image, Four);
        assert_pixels_eq!(labelled, expected);
    }

    #[test]
    fn test_connected_components_eight() {
        let image: GrayImage = ImageBuffer::from_raw(4, 4, vec![
            1, 0, 2, 1,
            0, 1, 1, 0,
            0, 0, 0, 0,
            0, 0, 0, 1]).unwrap();

        let expected: ImageBuffer<Luma<u32>, Vec<u32>>
            = ImageBuffer::from_raw(4, 4, vec![
                1, 0, 2, 1,
                0, 1, 1, 0,
                0, 0, 0, 0,
                0, 0, 0, 3]).unwrap();

        let labelled = connected_components(&image, Eight);
        assert_pixels_eq!(labelled, expected);
    }

    // TODO: add benchmark
}
<commit_msg>Add comment<commit_after>//! Functions for finding and labelling connected components of an image.

use image::{
    GenericImage,
    ImageBuffer,
    Luma
};

use definitions::{
    VecBuffer
};

use unionfind::DisjointSetForest;

use std::cmp;
use std::collections::HashMap;

/// Whether we consider the NW, NE, SW, and SE neighbors of
/// a pixel to be connected to it, or just its N, S, E, and W
/// neighbors.
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum Connectivity { Four, Eight }

/// Returns an image of the same size as the input, where each pixel
/// is labelled by the connected foreground component it belongs to,
/// or 0 if it's in the background. Input pixels are treated as belonging
/// to the background if and only if they have value 0.
pub fn connected_components<I>(image: &I, conn: Connectivity)
        -> VecBuffer<Luma<u32>>
    where I: GenericImage<Pixel=Luma<u8>> {

    let (width, height) = image.dimensions();
    let mut out = ImageBuffer::new(width, height);

    // TODO: add macro to abandon early if either dimension is zero
    if width == 0 || height == 0 {
        return out;
    }

    let background = Luma([0u8]);
    let mut forest = DisjointSetForest::new((width * height) as usize);
    let mut adj_labels = [0u32; 4];
    let mut next_label = 1;

    for y in 0..height {
        for x in 0..width {
            out.put_pixel(x, y, Luma([0]));
        }

        for x in 0..width {

            let current = image.get_pixel(x, y);
            if current == background {
                continue;
            }

            let mut num_adj = 0;

            if x > 0 {
                // West
                let pixel = image.get_pixel(x - 1, y);
                if pixel == current {
                    let label = out.get_pixel(x - 1, y)[0];
                    adj_labels[num_adj] = label;
                    num_adj += 1;
                }
            }

            if y > 0 {
                // North
                let pixel = image.get_pixel(x, y - 1);
                if pixel == current {
                    let label = out.get_pixel(x, y - 1)[0];
                    adj_labels[num_adj] = label;
                    num_adj += 1;
                }

                if conn == Connectivity::Eight {
                    if x > 0 {
                        // North West
                        let pixel = image.get_pixel(x - 1, y - 1);
                        if pixel == current {
                            let label = out.get_pixel(x - 1, y - 1)[0];
                            adj_labels[num_adj] = label;
                            num_adj += 1;
                        }
                    }
                    if x < width - 1 {
                        // North East
                        let pixel = image.get_pixel(x + 1, y - 1);
                        if pixel == current {
                            let label = out.get_pixel(x + 1, y - 1)[0];
                            adj_labels[num_adj] = label;
                            num_adj += 1;
                        }
                    }
                }
            }

            if num_adj == 0 {
                out.put_pixel(x, y, Luma([next_label]));
                next_label += 1;
            }
            else {
                let mut min_label = u32::max_value();
                for n in 0..num_adj {
                    min_label = cmp::min(min_label, adj_labels[n]);
                }
                out.put_pixel(x, y, Luma([min_label]));
                for n in 0..num_adj {
                    forest.union(min_label as usize, adj_labels[n] as usize);
                }
            }
        }
    }

    // Make components start at 1
    let mut root_name = 1;
    let mut root_idx: HashMap<usize, usize> = HashMap::new();

    for y in 0..height {
        for x in 0..width {
            if image.get_pixel(x, y) == background {
                continue;
            }

            let label = out.get_pixel(x, y)[0];
            let root = forest.root(label as usize);

            match root_idx.get(&root).map(|x| *x) {
                Some(idx) => {
                    out.put_pixel(x, y, Luma([idx as u32]));
                }
                None => {
                    let idx = root_name;
                    root_idx.insert(root, idx);
                    out.put_pixel(x, y, Luma([idx as u32]));
                    root_name += 1;
                }
            }
        }
    }

    out
}

#[cfg(test)]
mod test {

    use super::{
        connected_components
    };
    use super::Connectivity::{
        Four,
        Eight
    };
    use image::{
        GrayImage,
        ImageBuffer,
        Luma
    };

    #[test]
    fn test_connected_components_four() {
        let image: GrayImage = ImageBuffer::from_raw(4, 4, vec![
            1, 0, 2, 1,
            0, 1, 1, 0,
            0, 0, 0, 0,
            0, 0, 0, 1]).unwrap();

        let expected: ImageBuffer<Luma<u32>, Vec<u32>>
            = ImageBuffer::from_raw(4, 4, vec![
                1, 0, 2, 3,
                0, 4, 4, 0,
                0, 0, 0, 0,
                0, 0, 0, 5]).unwrap();

        let labelled = connected_components(&image, Four);
        assert_pixels_eq!(labelled, expected);
    }

    #[test]
    fn test_connected_components_eight() {
        let image: GrayImage = ImageBuffer::from_raw(4, 4, vec![
            1, 0, 2, 1,
            0, 1, 1, 0,
            0, 0, 0, 0,
            0, 0, 0, 1]).unwrap();

        let expected: ImageBuffer<Luma<u32>, Vec<u32>>
            = ImageBuffer::from_raw(4, 4, vec![
                1, 0, 2, 1,
                0, 1, 1, 0,
                0, 0, 0, 0,
                0, 0, 0, 3]).unwrap();

        let labelled = connected_components(&image, Eight);
        assert_pixels_eq!(labelled, expected);
    }

    // TODO: add benchmark
}
<|endoftext|>


<commit_before>mod renderer_server_process;

pub use renderer_server_process::*;

use std::sync::Arc;

use ipc_channel::ipc::IpcError;
use serde::{Serialize, Deserialize};
use tokio::sync::{mpsc, RwLock, Mutex};
use thiserror::Error;

use crate::ipc_protocol::{ClientConnection, ConnectionError, ClientRequest, ServerResponse};

/// Signals that the IPC connection has been disconnected and therefore the window was probably
/// closed
#[derive(Debug, Clone, Copy, PartialEq, Eq, Error)]
#[error("Window closed. Cannot continue to run turtle commands. Stopping.")]
struct Disconnected;

/// A unique ID used to multiplex responses on the client side
///
/// Treated as an opaque value on the server that is returned back to the client with the response
/// to a request.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ClientId(usize);

/// Spawns the server, and manages the IPC connection
///
/// Messages are sent though IPC and responses are dispatched back to the correct client based on
/// the received client ID.
#[derive(Debug)]
struct ClientDispatcher {
    /// The spawned server process
    ///
    /// When dropped, this will block until the server process has quit
    proc: RendererServerProcess,

    /// The IPC connection to the server process
    conn: Arc<ClientConnection>,

    /// Each `ClientId` indexes into this field
    ///
    /// Using `RwLock` allows sending multiple times concurrently using `read()` and also allows
    /// more clients to be added using `write()`.
    clients: Arc<RwLock<Vec<mpsc::UnboundedSender<Result<ServerResponse, Disconnected>>>>>,
}

impl ClientDispatcher {
    async fn new() -> Result<Self, ConnectionError> {
        let mut proc = RendererServerProcess::spawn().await?;
        let conn = Arc::new(ClientConnection::new(&mut proc).await?);
        let clients = Arc::new(RwLock::new(Vec::<mpsc::UnboundedSender<_>>::new()));

        let task_conn = conn.clone();
        let task_clients = clients.clone();
        tokio::spawn(async move {
            loop {
                let (id, response) = match task_conn.recv().await {
                    Ok((id, response)) => (id, Ok(response)),

                    Err(IpcError::Disconnected) => {
                        // Alert all the clients of the disconnection
                        let clients = task_clients.read().await;
                        for client in &*clients {
                            match client.send(Err(Disconnected)) {
                                Ok(()) => {},
                                // This particular client connection must have gotten dropped
                                Err(_) => {},
                            }
                        }
                        break;
                    },

                    Err(err) => panic!("Error while receiving IPC message: {:?}", err),
                };

                let clients = task_clients.read().await;

                let ClientId(index) = id;
                match clients[index].send(response) {
                    Ok(()) => {},
                    // This particular client connection must have gotten dropped
                    Err(_) => {},
                }
            }
        });

        Ok(Self {proc, conn, clients})
    }

    async fn add_client(&self) -> (ClientId, mpsc::UnboundedReceiver<Result<ServerResponse, Disconnected>>) {
        let mut clients = self.clients.write().await;

        let id = ClientId(clients.len());
        let (sender, receiver) = mpsc::unbounded_channel();
        clients.push(sender);

        (id, receiver)
    }

    async fn send(&self, id: ClientId, req: ClientRequest) -> Result<(), ipc_channel::Error> {
        self.conn.send(id, req).await
    }
}

/// Represents a single connection to the server
#[derive(Debug)]
pub struct RendererClient {
    dispatcher: Arc<ClientDispatcher>,
    id: ClientId,
    receiver: Mutex<mpsc::UnboundedReceiver<Result<ServerResponse, Disconnected>>>,
}

impl RendererClient {
    /// Spawns a new server process and creates a connection to it
    pub async fn new() -> Result<Self, ConnectionError> {
        let dispatcher = Arc::new(ClientDispatcher::new().await?);
        let (id, receiver) = dispatcher.add_client().await;
        let receiver = Mutex::new(receiver);

        Ok(Self {dispatcher, id, receiver})
    }

    /// Creates a new renderer client that can also communicate to the same server
    pub async fn split(&self) -> Self {
        let dispatcher = self.dispatcher.clone();
        let (id, receiver) = dispatcher.add_client().await;
        let receiver = Mutex::new(receiver);

        Self {dispatcher, id, receiver}
    }

    /// Sends a message to the server process
    ///
    /// When possible, prefer using methods from `ProtocolClient` instead of using this directly
    pub async fn send(&self, req: ClientRequest) {
        // The error produced by send is a serialization error, so it signals a bug in this code,
        // not something that should be propagated to be handled elsewhere.
        self.dispatcher.send(self.id, req).await
            .expect("bug: error while sending message through IPC")
    }

    /// Receives a response from the server process
    ///
    /// When possible, prefer using methods from `ProtocolClient` instead of using this directly
    pub async fn recv(&self) -> ServerResponse {
        let mut receiver = self.receiver.lock().await;
        receiver.recv().await
            // Since this struct keeps a ref-counted copy of the senders, they can't have possibly
            // been dropped at this point.
            .expect("bug: client senders should not be dropped yet")
            // This panic causes the program to exit if turtle commands continue after the window
            // closes
            .unwrap_or_else(|err| panic!("IPC response not received: {}", err))
    }
}
<commit_msg>Updated window closed panic message to indicate that it is not an error<commit_after>mod renderer_server_process;

pub use renderer_server_process::*;

use std::sync::Arc;

use ipc_channel::ipc::IpcError;
use serde::{Serialize, Deserialize};
use tokio::sync::{mpsc, RwLock, Mutex};
use thiserror::Error;

use crate::ipc_protocol::{ClientConnection, ConnectionError, ClientRequest, ServerResponse};

/// Signals that the IPC connection has been disconnected and therefore the window was probably
/// closed
#[derive(Debug, Clone, Copy, PartialEq, Eq, Error)]
#[error("Cannot continue to run turtle commands after window is closed. This panic stops the thread, but is not necessarily an error.")]
struct Disconnected;

/// A unique ID used to multiplex responses on the client side
///
/// Treated as an opaque value on the server that is returned back to the client with the response
/// to a request.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ClientId(usize);

/// Spawns the server, and manages the IPC connection
///
/// Messages are sent though IPC and responses are dispatched back to the correct client based on
/// the received client ID.
#[derive(Debug)]
struct ClientDispatcher {
    /// The spawned server process
    ///
    /// When dropped, this will block until the server process has quit
    proc: RendererServerProcess,

    /// The IPC connection to the server process
    conn: Arc<ClientConnection>,

    /// Each `ClientId` indexes into this field
    ///
    /// Using `RwLock` allows sending multiple times concurrently using `read()` and also allows
    /// more clients to be added using `write()`.
    clients: Arc<RwLock<Vec<mpsc::UnboundedSender<Result<ServerResponse, Disconnected>>>>>,
}

impl ClientDispatcher {
    async fn new() -> Result<Self, ConnectionError> {
        let mut proc = RendererServerProcess::spawn().await?;
        let conn = Arc::new(ClientConnection::new(&mut proc).await?);
        let clients = Arc::new(RwLock::new(Vec::<mpsc::UnboundedSender<_>>::new()));

        let task_conn = conn.clone();
        let task_clients = clients.clone();
        tokio::spawn(async move {
            loop {
                let (id, response) = match task_conn.recv().await {
                    Ok((id, response)) => (id, Ok(response)),

                    Err(IpcError::Disconnected) => {
                        // Alert all the clients of the disconnection
                        let clients = task_clients.read().await;
                        for client in &*clients {
                            match client.send(Err(Disconnected)) {
                                Ok(()) => {},
                                // This particular client connection must have gotten dropped
                                Err(_) => {},
                            }
                        }
                        break;
                    },

                    Err(err) => panic!("Error while receiving IPC message: {:?}", err),
                };

                let clients = task_clients.read().await;

                let ClientId(index) = id;
                match clients[index].send(response) {
                    Ok(()) => {},
                    // This particular client connection must have gotten dropped
                    Err(_) => {},
                }
            }
        });

        Ok(Self {proc, conn, clients})
    }

    async fn add_client(&self) -> (ClientId, mpsc::UnboundedReceiver<Result<ServerResponse, Disconnected>>) {
        let mut clients = self.clients.write().await;

        let id = ClientId(clients.len());
        let (sender, receiver) = mpsc::unbounded_channel();
        clients.push(sender);

        (id, receiver)
    }

    async fn send(&self, id: ClientId, req: ClientRequest) -> Result<(), ipc_channel::Error> {
        self.conn.send(id, req).await
    }
}

/// Represents a single connection to the server
#[derive(Debug)]
pub struct RendererClient {
    dispatcher: Arc<ClientDispatcher>,
    id: ClientId,
    receiver: Mutex<mpsc::UnboundedReceiver<Result<ServerResponse, Disconnected>>>,
}

impl RendererClient {
    /// Spawns a new server process and creates a connection to it
    pub async fn new() -> Result<Self, ConnectionError> {
        let dispatcher = Arc::new(ClientDispatcher::new().await?);
        let (id, receiver) = dispatcher.add_client().await;
        let receiver = Mutex::new(receiver);

        Ok(Self {dispatcher, id, receiver})
    }

    /// Creates a new renderer client that can also communicate to the same server
    pub async fn split(&self) -> Self {
        let dispatcher = self.dispatcher.clone();
        let (id, receiver) = dispatcher.add_client().await;
        let receiver = Mutex::new(receiver);

        Self {dispatcher, id, receiver}
    }

    /// Sends a message to the server process
    ///
    /// When possible, prefer using methods from `ProtocolClient` instead of using this directly
    pub async fn send(&self, req: ClientRequest) {
        // The error produced by send is a serialization error, so it signals a bug in this code,
        // not something that should be propagated to be handled elsewhere.
        self.dispatcher.send(self.id, req).await
            .expect("bug: error while sending message through IPC")
    }

    /// Receives a response from the server process
    ///
    /// When possible, prefer using methods from `ProtocolClient` instead of using this directly
    pub async fn recv(&self) -> ServerResponse {
        let mut receiver = self.receiver.lock().await;
        receiver.recv().await
            // Since this struct keeps a ref-counted copy of the senders, they can't have possibly
            // been dropped at this point.
            .expect("bug: client senders should not be dropped yet")
            // This panic causes the program to exit if turtle commands continue after the window
            // closes
            .unwrap_or_else(|err| panic!("IPC response not received: {}", err))
    }
}
<|endoftext|>


<commit_before>mod state;
mod app;
mod access_control;
mod coords;
mod renderer;
mod backend;
mod handlers;
mod start;

cfg_if::cfg_if! {
    if #[cfg(any(feature = "test", test))] {
        mod test_event_loop_notifier;
        use test_event_loop_notifier as event_loop_notifier;

    } else {
        mod event_loop_notifier;
        mod main;
    }
}

pub(crate) use app::TurtleId;
pub(crate) use backend::RendererServer;
pub use renderer::export::ExportError;
pub use start::start;

use std::sync::Arc;

use ipc_channel::ipc::IpcError;
use tokio::sync::{mpsc, oneshot, Mutex};

use crate::ipc_protocol::{ServerConnection, ClientRequest};
use crate::renderer_client::ClientId;
use crate::Event;

use app::App;
use access_control::AccessControl;
use renderer::display_list::DisplayList;
use event_loop_notifier::EventLoopNotifier;

/// Serves requests from the client forever
async fn serve(
    conn: ServerConnection,
    app: Arc<App>,
    display_list: Arc<Mutex<DisplayList>>,
    event_loop: Arc<EventLoopNotifier>,
    events_receiver: mpsc::UnboundedReceiver<Event>,
    mut server_shutdown_receiver: mpsc::Receiver<()>,
) {
    let conn = Arc::new(conn);
    let app_control = Arc::new(AccessControl::new(app).await);
    let events_receiver = Arc::new(Mutex::new(events_receiver));

    loop {
        // This will either receive the next request or end this task
        let (client_id, request) = tokio::select! {
            // If the main thread shuts down successfully, this will receive Some(()).
            // If the main thread panics, this will return None. In either case, this task needs to
            // end immediately.
            _ = server_shutdown_receiver.recv() => break,

            req = conn.recv() => match req {
                Ok(req) => req,
                // Client has disconnected completely, no purpose in continuing this loop
                Err(IpcError::Disconnected) => break,
                Err(err) => panic!("unable to receive request from IPC client: {:?}", err),
            },
        };

        // To preserve the ordering of requests in cases where they can't run concurrently, we use
        // a channel to synchronize that each request
        let (data_req_queued, data_req_queued_receiver) = oneshot::channel();

        // Each incoming request is given its own task configured specifically for each kind of
        // request. Having separate tasks allows requests that can run in parallel to do so.
        tokio::spawn(run_request(
            data_req_queued,
            conn.clone(),
            client_id,
            app_control.clone(),
            display_list.clone(),
            event_loop.clone(),
            events_receiver.clone(),
            request,
        ));

        // Check if we are ready for the next request to be processed
        // Ignoring error because if data_req_queued was dropped, it probably just means that the
        // request didn't need to call AccessControl::get()
        data_req_queued_receiver.await.unwrap_or(());
    }
}

async fn run_request(
    data_req_queued: oneshot::Sender<()>,
    conn: Arc<ServerConnection>,
    client_id: ClientId,
    app_control: Arc<AccessControl>,
    display_list: Arc<Mutex<DisplayList>>,
    event_loop: Arc<EventLoopNotifier>,
    events_receiver: Arc<Mutex<mpsc::UnboundedReceiver<Event>>>,
    request: ClientRequest,
) {
    use ClientRequest::*;
    let res = match request {
        CreateTurtle => {
            handlers::create_turtle(&conn, client_id, &app_control, &event_loop).await
        },

        Export(path, format) => {
            handlers::export_drawings(data_req_queued, &conn, client_id, &app_control, &display_list, &path, format).await
        },

        PollEvent => {
            // NOTE: Technically, because this does not send to `data_req_queued`, it is possible
            // to have several callers of `poll_event` race to get the next event. This appears to
            // be fine though because we don't guarantee the ordering of events if they are polled
            // from multiple threads/tasks. Having events follow the order of requests doesn't
            // really matter if strict ordering isn't necessary.
            handlers::poll_event(&conn, client_id, &events_receiver).await
        },

        DrawingProp(prop) => {
            handlers::drawing_prop(data_req_queued, &conn, client_id, &app_control, prop).await
        },
        SetDrawingProp(prop_value) => {
            handlers::set_drawing_prop(data_req_queued, &app_control, &event_loop, prop_value).await
        },
        ResetDrawingProp(prop) => {
            handlers::reset_drawing_prop(data_req_queued, &app_control, &event_loop, prop).await
        },

        TurtleProp(id, prop) => {
            handlers::turtle_prop(data_req_queued, &conn, client_id, &app_control, id, prop).await
        },
        SetTurtleProp(id, prop_value) => {
            handlers::set_turtle_prop(data_req_queued, &app_control, &display_list, &event_loop, id, prop_value).await
        },
        ResetTurtleProp(id, prop) => {
            handlers::reset_turtle_prop(data_req_queued, &app_control, &display_list, &event_loop, id, prop).await
        },
        ResetTurtle(id) => {
            handlers::reset_turtle(data_req_queued, &app_control, &display_list, &event_loop, id).await
        },

        MoveForward(id, distance) => {
            handlers::move_forward(data_req_queued, &conn, client_id, &app_control, &display_list, &event_loop, id, distance).await
        },
        MoveTo(id, target_pos) => {
            handlers::move_to(data_req_queued, &conn, client_id, &app_control, &display_list, &event_loop, id, target_pos).await
        },
        RotateInPlace(id, angle, direction) => {
            handlers::rotate_in_place(data_req_queued, &conn, client_id, &app_control, &event_loop, id, angle, direction).await
        },

        BeginFill(id) => {
            handlers::begin_fill(data_req_queued, &app_control, &display_list, &event_loop, id).await
        },
        EndFill(id) => {
            handlers::end_fill(data_req_queued, &app_control, id).await
        },

        ClearAll => {
            handlers::clear_all(data_req_queued, &app_control, &display_list, &event_loop).await
        },
        ClearTurtle(id) => {
            handlers::clear_turtle(data_req_queued, &app_control, &display_list, &event_loop, id).await
        },
    };

    use handlers::HandlerError::*;
    match res {
        Ok(()) => {},
        Err(IpcChannelError(err)) => panic!("Error while serializing response: {}", err),
        // Task managing window has ended, this task will end soon too.
        //TODO: This potentially leaves the turtle/drawing state in an inconsistent state. Should
        // we deal with that somehow? Panicking doesn't seem appropriate since this probably isn't
        // an error, but we should definitely stop processing commands and make sure the process
        // ends shortly after.
        Err(EventLoopClosed(_)) => {},
    }
}
<commit_msg>Clarifying documentation in renderer_server<commit_after>mod state;
mod app;
mod access_control;
mod coords;
mod renderer;
mod backend;
mod handlers;
mod start;

cfg_if::cfg_if! {
    if #[cfg(any(feature = "test", test))] {
        mod test_event_loop_notifier;
        use test_event_loop_notifier as event_loop_notifier;

    } else {
        mod event_loop_notifier;
        mod main;
    }
}

pub(crate) use app::TurtleId;
pub(crate) use backend::RendererServer;
pub use renderer::export::ExportError;
pub use start::start;

use std::sync::Arc;

use ipc_channel::ipc::IpcError;
use tokio::sync::{mpsc, oneshot, Mutex};

use crate::ipc_protocol::{ServerConnection, ClientRequest};
use crate::renderer_client::ClientId;
use crate::Event;

use app::App;
use access_control::AccessControl;
use renderer::display_list::DisplayList;
use event_loop_notifier::EventLoopNotifier;

/// Serves requests from the client forever
async fn serve(
    conn: ServerConnection,
    app: Arc<App>,
    display_list: Arc<Mutex<DisplayList>>,
    event_loop: Arc<EventLoopNotifier>,
    events_receiver: mpsc::UnboundedReceiver<Event>,
    mut server_shutdown_receiver: mpsc::Receiver<()>,
) {
    let conn = Arc::new(conn);
    let app_control = Arc::new(AccessControl::new(app).await);
    let events_receiver = Arc::new(Mutex::new(events_receiver));

    loop {
        // This will either receive the next request or end this task
        let (client_id, request) = tokio::select! {
            // If the main thread shuts down successfully, this will receive Some(()). If the main
            // thread panics, this will return None. In either case, this loop needs to stop.
            _ = server_shutdown_receiver.recv() => break,

            req = conn.recv() => match req {
                Ok(req) => req,
                // Client has disconnected completely, no purpose in continuing this loop
                Err(IpcError::Disconnected) => break,
                Err(err) => panic!("unable to receive request from IPC client: {:?}", err),
            },
        };

        // To preserve the ordering of requests in cases where they can't run concurrently, we use
        // a channel to synchronize that each request has finished requesting the data it needs
        // before the next request can be processed at all.
        let (data_req_queued, data_req_queued_receiver) = oneshot::channel();

        // Each incoming request is executed immediately in its own task. This allows requests that
        // can run concurrently to do so. Requests that use an overlapping set of data will run
        // in the order in which they arrived. The ordering is enforced with `data_req_queued`.
        tokio::spawn(run_request(
            data_req_queued,
            conn.clone(),
            client_id,
            app_control.clone(),
            display_list.clone(),
            event_loop.clone(),
            events_receiver.clone(),
            request,
        ));

        // Check if we are ready for the next request to be processed
        //
        // Ignoring error because if data_req_queued was dropped, it probably just means that the
        // request didn't need to call AccessControl::get()
        data_req_queued_receiver.await.unwrap_or(());
    }
}

async fn run_request(
    data_req_queued: oneshot::Sender<()>,
    conn: Arc<ServerConnection>,
    client_id: ClientId,
    app_control: Arc<AccessControl>,
    display_list: Arc<Mutex<DisplayList>>,
    event_loop: Arc<EventLoopNotifier>,
    events_receiver: Arc<Mutex<mpsc::UnboundedReceiver<Event>>>,
    request: ClientRequest,
) {
    use ClientRequest::*;
    let res = match request {
        CreateTurtle => {
            handlers::create_turtle(&conn, client_id, &app_control, &event_loop).await
        },

        Export(path, format) => {
            handlers::export_drawings(data_req_queued, &conn, client_id, &app_control, &display_list, &path, format).await
        },

        PollEvent => {
            // NOTE: Technically, because this does not send to `data_req_queued`, it is possible
            // to have several callers of `poll_event` race to get the next event. This is probably
            // fine though because we don't guarantee the ordering of events if they are polled
            // from multiple threads/tasks. Thus, following the order of requests does not matter
            // in this specific case.
            handlers::poll_event(&conn, client_id, &events_receiver).await
        },

        DrawingProp(prop) => {
            handlers::drawing_prop(data_req_queued, &conn, client_id, &app_control, prop).await
        },
        SetDrawingProp(prop_value) => {
            handlers::set_drawing_prop(data_req_queued, &app_control, &event_loop, prop_value).await
        },
        ResetDrawingProp(prop) => {
            handlers::reset_drawing_prop(data_req_queued, &app_control, &event_loop, prop).await
        },

        TurtleProp(id, prop) => {
            handlers::turtle_prop(data_req_queued, &conn, client_id, &app_control, id, prop).await
        },
        SetTurtleProp(id, prop_value) => {
            handlers::set_turtle_prop(data_req_queued, &app_control, &display_list, &event_loop, id, prop_value).await
        },
        ResetTurtleProp(id, prop) => {
            handlers::reset_turtle_prop(data_req_queued, &app_control, &display_list, &event_loop, id, prop).await
        },
        ResetTurtle(id) => {
            handlers::reset_turtle(data_req_queued, &app_control, &display_list, &event_loop, id).await
        },

        MoveForward(id, distance) => {
            handlers::move_forward(data_req_queued, &conn, client_id, &app_control, &display_list, &event_loop, id, distance).await
        },
        MoveTo(id, target_pos) => {
            handlers::move_to(data_req_queued, &conn, client_id, &app_control, &display_list, &event_loop, id, target_pos).await
        },
        RotateInPlace(id, angle, direction) => {
            handlers::rotate_in_place(data_req_queued, &conn, client_id, &app_control, &event_loop, id, angle, direction).await
        },

        BeginFill(id) => {
            handlers::begin_fill(data_req_queued, &app_control, &display_list, &event_loop, id).await
        },
        EndFill(id) => {
            handlers::end_fill(data_req_queued, &app_control, id).await
        },

        ClearAll => {
            handlers::clear_all(data_req_queued, &app_control, &display_list, &event_loop).await
        },
        ClearTurtle(id) => {
            handlers::clear_turtle(data_req_queued, &app_control, &display_list, &event_loop, id).await
        },
    };

    use handlers::HandlerError::*;
    match res {
        Ok(()) => {},
        Err(IpcChannelError(err)) => panic!("Error while serializing response: {}", err),
        // Task managing window has ended, this task will end soon too.
        //TODO: This potentially leaves the turtle/drawing state in an inconsistent state. Should
        // we deal with that somehow? Panicking doesn't seem appropriate since this probably isn't
        // an error, but we should definitely stop processing commands and make sure the process
        // ends shortly after.
        Err(EventLoopClosed(_)) => {},
    }
}
<|endoftext|>


<commit_before>/*
Copyright ⓒ 2016 Daniel Keep.

Licensed under the MIT license (see LICENSE or <http://opensource.org
/licenses/MIT>) or the Apache License, Version 2.0 (see LICENSE of
<http://www.apache.org/licenses/LICENSE-2.0>), at your option. All
files in the project carrying such notice may not be copied, modified,
or distributed except according to those terms.
*/
/*!
Scanner implementations for standard library (and other "official" crates) types.
*/
mod collections;
mod net;

use ::ScanError;
use ::input::ScanInput;
use ::scanner::ScanFromStr;
use ::scanner::util::StrUtil;

macro_rules! impl_tuple {
    () => {};

    ($head:ident $($tail:ident)*) => {
        impl<'a, $head $(, $tail)*> ::scanner::ScanFromStr<'a> for ($head, $($tail,)*)
        where $head: ::scanner::ScanFromStr<'a>, $($tail: ::scanner::ScanFromStr<'a>,)* {
            type Output = (<$head as ::scanner::ScanFromStr<'a>>::Output, $(<$tail as ::scanner::ScanFromStr<'a>>::Output,)*);
            fn scan_from<I: $crate::input::ScanInput<'a>>(s: I) -> Result<(Self::Output, usize), ::ScanError> {
                #![allow(non_snake_case)]
                use ::scanner::util::StrUtil;
                let s = s.as_str();
                scan!(s;
                    ("(", let $head: $head, $(",", let $tail: $tail,)* [","]?, ")", ..tail)
                    => (($head, $($tail,)*), s.subslice_offset_stable(tail).unwrap())
                )
            }
        }

        impl_tuple! { $($tail)* }
    };
}

#[cfg(not(feature="tuples-16"))]
mod impl_tuples {
    impl_tuple! { T0 T1 T2 T3 }
}

#[cfg(feature="tuples-16")]
mod impl_tuples {
    impl_tuple! { T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15 T16 }
}

impl<'a> ScanFromStr<'a> for () {
    type Output = Self;
    fn scan_from<I: ScanInput<'a>>(s: I) -> Result<(Self::Output, usize), ScanError> {
        let s = s.as_str();
        scan!(s; ("(", ")", ..tail) => ((), s.subslice_offset_stable(tail).unwrap()))
    }
}

macro_rules! impl_array {
    (@as_item $i:item) => { $i };
    (@replace.expr $_tt:tt $sub:expr) => { $sub };

    () => {};

    ($len:tt $e0:ident $($ns:tt $es:ident)*) => {
        impl_array! {
            @as_item
            impl<'a, T> ::scanner::ScanFromStr<'a> for [T; $len] where T: ::scanner::ScanFromStr<'a> {
                type Output = [T::Output; $len];
                fn scan_from<I: $crate::input::ScanInput<'a>>(s: I) -> Result<(Self::Output, usize), ::ScanError> {
                    use ::scanner::util::StrUtil;
                    let s = s.as_str();
                    scan!(s;
                        ("[", let $e0: T, $(",", let $es: T,)* [","]?, "]", ..tail)
                        => ([$e0, $($es,)*], s.subslice_offset_stable(tail).unwrap())
                    )
                }
            }
        }

        impl_array! { $($ns $es)* }
    };
}

#[cfg(not(feature="arrays-32"))]
mod impl_arrays {
    impl_array! {
        8 e8 7 e7 6 e6 5 e5 4 e4 3 e3 2 e2 1 e1
    }
}

#[cfg(feature="arrays-32")]
mod impl_arrays {
    impl_array! {
        32 e32 31 e31
        30 e30 29 e29 28 e28 27 e27 26 e26 25 e25 24 e24 23 e23 22 e22 21 e21
        20 e20 19 e19 18 e18 17 e17 16 e16 15 e15 14 e14 13 e13 12 e12 11 e11
        10 e10 9 e9 8 e8 7 e7 6 e6 5 e5 4 e4 3 e3 2 e2 1 e1
    }
}

impl<'a, T> ScanFromStr<'a> for [T; 0] {
    type Output = Self;
    fn scan_from<I: ScanInput<'a>>(s: I) -> Result<(Self::Output, usize), ScanError> {
        let s = s.as_str();
        scan!(s; ("[", "]", ..tail) => ([], s.subslice_offset_stable(tail).unwrap()))
    }
}

impl<'a, T> ScanFromStr<'a> for Option<T> where T: ScanFromStr<'a> {
    type Output = Option<T::Output>;
    fn scan_from<I: ScanInput<'a>>(s: I) -> Result<(Self::Output, usize), ScanError> {
        scan!( s.to_cursor();
            ("Some", "(", let v: T, ")", ..tail) => (Some(v), tail),
            ("None", ..tail) => (None, tail),
        ).map(|(v, t)| (v, s.as_str().subslice_offset_stable(t).unwrap()))
    }
}

impl<'a, T, E> ScanFromStr<'a> for Result<T, E>
where T: ScanFromStr<'a>, E: ScanFromStr<'a> {
    type Output = Result<T::Output, E::Output>;
    fn scan_from<I: ScanInput<'a>>(s: I) -> Result<(Self::Output, usize), ScanError> {
        scan!( s.to_cursor();
            ("Some", "(", let v: T, ")", ..tail) => (Ok(v), tail),
            ("Err", "(", let v: E, ")", ..tail) => (Err(v), tail),
        ).map(|(v, t)| (v, s.as_str().subslice_offset_stable(t).unwrap()))
    }
}

impl<'a> ScanFromStr<'a> for String {
    type Output = Self;
    fn scan_from<I: ScanInput<'a>>(s: I) -> Result<(Self::Output, usize), ScanError> {
        ::scanner::QuotedString::scan_from(s)
    }
}
<commit_msg>Added scanners for ranges.<commit_after>/*
Copyright ⓒ 2016 Daniel Keep.

Licensed under the MIT license (see LICENSE or <http://opensource.org
/licenses/MIT>) or the Apache License, Version 2.0 (see LICENSE of
<http://www.apache.org/licenses/LICENSE-2.0>), at your option. All
files in the project carrying such notice may not be copied, modified,
or distributed except according to those terms.
*/
/*!
Scanner implementations for standard library (and other "official" crates) types.
*/
mod collections;
mod net;

use std::ops::{Range, RangeFrom, RangeFull, RangeTo};
use ::ScanError;
use ::input::ScanInput;
use ::scanner::ScanFromStr;
use ::scanner::util::StrUtil;

macro_rules! impl_tuple {
    () => {};

    ($head:ident $($tail:ident)*) => {
        impl<'a, $head $(, $tail)*> ::scanner::ScanFromStr<'a> for ($head, $($tail,)*)
        where $head: ::scanner::ScanFromStr<'a>, $($tail: ::scanner::ScanFromStr<'a>,)* {
            type Output = (<$head as ::scanner::ScanFromStr<'a>>::Output, $(<$tail as ::scanner::ScanFromStr<'a>>::Output,)*);
            fn scan_from<I: $crate::input::ScanInput<'a>>(s: I) -> Result<(Self::Output, usize), ::ScanError> {
                #![allow(non_snake_case)]
                use ::scanner::util::StrUtil;
                let s = s.as_str();
                scan!(s;
                    ("(", let $head: $head, $(",", let $tail: $tail,)* [","]?, ")", ..tail)
                    => (($head, $($tail,)*), s.subslice_offset_stable(tail).unwrap())
                )
            }
        }

        impl_tuple! { $($tail)* }
    };
}

#[cfg(not(feature="tuples-16"))]
mod impl_tuples {
    impl_tuple! { T0 T1 T2 T3 }
}

#[cfg(feature="tuples-16")]
mod impl_tuples {
    impl_tuple! { T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15 T16 }
}

impl<'a> ScanFromStr<'a> for () {
    type Output = Self;
    fn scan_from<I: ScanInput<'a>>(s: I) -> Result<(Self::Output, usize), ScanError> {
        let s = s.as_str();
        scan!(s; ("(", ")", ..tail) => ((), s.subslice_offset_stable(tail).unwrap()))
    }
}

macro_rules! impl_array {
    (@as_item $i:item) => { $i };
    (@replace.expr $_tt:tt $sub:expr) => { $sub };

    () => {};

    ($len:tt $e0:ident $($ns:tt $es:ident)*) => {
        impl_array! {
            @as_item
            impl<'a, T> ::scanner::ScanFromStr<'a> for [T; $len] where T: ::scanner::ScanFromStr<'a> {
                type Output = [T::Output; $len];
                fn scan_from<I: $crate::input::ScanInput<'a>>(s: I) -> Result<(Self::Output, usize), ::ScanError> {
                    use ::scanner::util::StrUtil;
                    let s = s.as_str();
                    scan!(s;
                        ("[", let $e0: T, $(",", let $es: T,)* [","]?, "]", ..tail)
                        => ([$e0, $($es,)*], s.subslice_offset_stable(tail).unwrap())
                    )
                }
            }
        }

        impl_array! { $($ns $es)* }
    };
}

#[cfg(not(feature="arrays-32"))]
mod impl_arrays {
    impl_array! {
        8 e8 7 e7 6 e6 5 e5 4 e4 3 e3 2 e2 1 e1
    }
}

#[cfg(feature="arrays-32")]
mod impl_arrays {
    impl_array! {
        32 e32 31 e31
        30 e30 29 e29 28 e28 27 e27 26 e26 25 e25 24 e24 23 e23 22 e22 21 e21
        20 e20 19 e19 18 e18 17 e17 16 e16 15 e15 14 e14 13 e13 12 e12 11 e11
        10 e10 9 e9 8 e8 7 e7 6 e6 5 e5 4 e4 3 e3 2 e2 1 e1
    }
}

impl<'a, T> ScanFromStr<'a> for [T; 0] {
    type Output = Self;
    fn scan_from<I: ScanInput<'a>>(s: I) -> Result<(Self::Output, usize), ScanError> {
        let s = s.as_str();
        scan!(s; ("[", "]", ..tail) => ([], s.subslice_offset_stable(tail).unwrap()))
    }
}

impl<'a, T> ScanFromStr<'a> for Option<T> where T: ScanFromStr<'a> {
    type Output = Option<T::Output>;
    fn scan_from<I: ScanInput<'a>>(s: I) -> Result<(Self::Output, usize), ScanError> {
        scan!( s.to_cursor();
            ("Some", "(", let v: T, ")", ..tail) => (Some(v), tail),
            ("None", ..tail) => (None, tail),
        ).map(|(v, t)| (v, s.as_str().subslice_offset_stable(t).unwrap()))
    }
}

impl<'a, T, E> ScanFromStr<'a> for Result<T, E>
where T: ScanFromStr<'a>, E: ScanFromStr<'a> {
    type Output = Result<T::Output, E::Output>;
    fn scan_from<I: ScanInput<'a>>(s: I) -> Result<(Self::Output, usize), ScanError> {
        scan!( s.to_cursor();
            ("Some", "(", let v: T, ")", ..tail) => (Ok(v), tail),
            ("Err", "(", let v: E, ")", ..tail) => (Err(v), tail),
        ).map(|(v, t)| (v, s.as_str().subslice_offset_stable(t).unwrap()))
    }
}

impl<'a> ScanFromStr<'a> for String {
    type Output = Self;
    fn scan_from<I: ScanInput<'a>>(s: I) -> Result<(Self::Output, usize), ScanError> {
        ::scanner::QuotedString::scan_from(s)
    }
}

scanner! { impl<'a, T> ScanFromStr for Range<T> => Range {
    (let a: T, "..", let b: T, ..tail) => (a..b, tail)
}}

scanner! { impl<'a, T> ScanFromStr for RangeFrom<T> => RangeFrom {
    (let a: T, "..", ..tail) => (a.., tail)
}}

scanner! { impl<'a, T> ScanFromStr for RangeTo<T> => RangeTo {
    ("..", let b: T, ..tail) => (..b, tail)
}}

impl<'a> ScanFromStr<'a> for RangeFull {
    type Output = Self;

    fn scan_from<I: ScanInput<'a>>(s: I) -> Result<(Self::Output, usize), ScanError> {
        use ::input::ScanCursor;
        scan! { s.to_cursor();
            ("..", ^..tail) => (.., tail.offset())
        }
    }
}
<|endoftext|>