<commit_before>use super::TestDatabase;
use crate::db::CratesIoData;
use crate::docbuilder::BuildResult;
use crate::utils::{Dependency, MetadataPackage, Target};
use failure::Error;

#[must_use = "FakeRelease does nothing until you call .create()"]
pub(crate) struct FakeRelease<'a> {
    db: &'a TestDatabase,
    package: MetadataPackage,
    build_result: BuildResult,
    /// name, content
    source_files: Vec<(&'a str, &'a [u8])>,
    /// name, content
    rustdoc_files: Vec<(&'a str, &'a [u8])>,
    doc_targets: Vec<String>,
    default_target: Option<&'a str>,
    cratesio_data: CratesIoData,
    has_docs: bool,
    has_examples: bool,
}

impl<'a> FakeRelease<'a> {
    pub(super) fn new(db: &'a TestDatabase) -> Self {
        FakeRelease {
            db,
            package: MetadataPackage {
                id: "fake-package-id".into(),
                name: "fake-package".into(),
                version: "1.0.0".into(),
                license: Some("MIT".into()),
                repository: Some("https://git.example.com".into()),
                homepage: Some("https://www.example.com".into()),
                description: Some("Fake package".into()),
                documentation: Some("https://docs.example.com".into()),
                dependencies: vec![Dependency {
                    name: "fake-dependency".into(),
                    req: "^1.0.0".into(),
                    kind: None,
                }],
                targets: vec![Target::dummy_lib("fake_package".into(), None)],
                readme: None,
                keywords: vec!["fake".into(), "package".into()],
                authors: vec!["Fake Person <fake@example.com>".into()],
            },
            build_result: BuildResult {
                rustc_version: "rustc 2.0.0-nightly (000000000 1970-01-01)".into(),
                docsrs_version: "docs.rs 1.0.0 (000000000 1970-01-01)".into(),
                build_log: "It works!".into(),
                successful: true,
            },
            source_files: Vec::new(),
            rustdoc_files: Vec::new(),
            doc_targets: Vec::new(),
            default_target: None,
            cratesio_data: CratesIoData {
                release_time: time::get_time(),
                yanked: false,
                downloads: 0,
                owners: Vec::new(),
            },
            has_docs: true,
            has_examples: false,
        }
    }

    pub(crate) fn name(mut self, new: &str) -> Self {
        self.package.name = new.into();
        self.package.id = format!("{}-id", new);
        self.package.targets[0].name = new.into();
        self
    }

    pub(crate) fn version(mut self, new: &str) -> Self {
        self.package.version = new.into();
        self
    }

    pub(crate) fn repo(mut self, repo: impl Into<String>) -> Self {
        self.package.repository = Some(repo.into());
        self
    }

    pub(crate) fn build_result_successful(mut self, new: bool) -> Self {
        self.build_result.successful = new;
        self
    }

    pub(crate) fn cratesio_data_yanked(mut self, new: bool) -> Self {
        self.cratesio_data.yanked = new;
        self
    }

    pub(crate) fn rustdoc_file(mut self, path: &'a str, data: &'a [u8]) -> Self {
        self.rustdoc_files.push((path, data));
        self
    }

    pub(crate) fn source_file(mut self, path: &'a str, data: &'a [u8]) -> Self {
        self.source_files.push((path, data));
        self
    }

    pub(crate) fn default_target(mut self, target: &'a str) -> Self {
        self = self.add_target(target);
        self.default_target = Some(target);
        self
    }

    pub(crate) fn add_target(mut self, target: &str) -> Self {
        self.doc_targets.push(target.into());
        self
    }

    pub(crate) fn binary(mut self, bin: bool) -> Self {
        self.has_docs = !bin;
        if bin {
            for target in self.package.targets.iter_mut() {
                target.crate_types = vec!["bin".into()];
            }
        }
        self
    }

    pub(crate) fn add_platform<S: Into<String>>(mut self, platform: S) -> Self {
        let platform = platform.into();
        let name = self.package.targets[0].name.clone();
        let target = Target::dummy_lib(name, Some(platform.clone()));
        self.package.targets.push(target);
        self.doc_targets.push(platform);
        self
    }

    pub(crate) fn create(self) -> Result<i32, Error> {
        use std::fs;
        use std::path::Path;

        let tempdir = tempdir::TempDir::new("docs.rs-fake")?;
        let package = self.package;
        let db = self.db;

        let upload_files = |prefix: &str, files: &[(&str, &[u8])], target: Option<&str>| {
            let mut path_prefix = tempdir.path().join(prefix);
            if let Some(target) = target {
                path_prefix.push(target);
            }
            fs::create_dir(&path_prefix)?;

            for (path, data) in files {
                // allow `src/main.rs`
                if let Some(parent) = Path::new(path).parent() {
                    fs::create_dir_all(path_prefix.join(parent))?;
                }
                let file = path_prefix.join(&path);
                log::debug!("writing file {}", file.display());
                fs::write(file, data)?;
            }

            let prefix = format!(
                "{}/{}/{}/{}",
                prefix,
                package.name,
                package.version,
                target.unwrap_or("")
            );
            log::debug!("adding directory {} from {}", prefix, path_prefix.display());
            crate::db::add_path_into_database(&db.conn(), &prefix, path_prefix)
        };

        let index = [&package.name, "index.html"].join("/");
        let mut rustdoc_files = self.rustdoc_files;
        if package.is_library() && !rustdoc_files.iter().any(|(path, _)| path == &index) {
            rustdoc_files.push((&index, b"default index content"));
        }
        for (source_path, data) in &self.source_files {
            if source_path.starts_with("src/") {
                let updated = ["src", &package.name, &source_path[4..]].join("/");
                rustdoc_files.push((Box::leak(Box::new(updated)), data));
            }
        }
        let rustdoc_meta = upload_files("rustdoc", &rustdoc_files, None)?;
        log::debug!("added rustdoc files {}", rustdoc_meta);
        let source_meta = upload_files("source", &self.source_files, None)?;
        log::debug!("added source files {}", source_meta);

        for target in &package.targets[1..] {
            let platform = target.src_path.as_ref().unwrap();
            upload_files("rustdoc", &rustdoc_files, Some(platform))?;
            log::debug!("added platform files for {}", platform);
        }

        let release_id = crate::db::add_package_into_database(
            &db.conn(),
            &package,
            tempdir.path(),
            &self.build_result,
            self.default_target.unwrap_or("x86_64-unknown-linux-gnu"),
            Some(source_meta),
            self.doc_targets,
            &self.cratesio_data,
            self.has_docs,
            self.has_examples,
        )?;
        crate::db::add_build_into_database(&db.conn(), release_id, &self.build_result)?;

        Ok(release_id)
    }
}
<commit_msg>Make fake release more realistic on failure<commit_after>use super::TestDatabase;
use crate::db::CratesIoData;
use crate::docbuilder::BuildResult;
use crate::utils::{Dependency, MetadataPackage, Target};
use failure::Error;

#[must_use = "FakeRelease does nothing until you call .create()"]
pub(crate) struct FakeRelease<'a> {
    db: &'a TestDatabase,
    package: MetadataPackage,
    build_result: BuildResult,
    /// name, content
    source_files: Vec<(&'a str, &'a [u8])>,
    /// name, content
    rustdoc_files: Vec<(&'a str, &'a [u8])>,
    doc_targets: Vec<String>,
    default_target: Option<&'a str>,
    cratesio_data: CratesIoData,
    has_docs: bool,
    has_examples: bool,
}

impl<'a> FakeRelease<'a> {
    pub(super) fn new(db: &'a TestDatabase) -> Self {
        FakeRelease {
            db,
            package: MetadataPackage {
                id: "fake-package-id".into(),
                name: "fake-package".into(),
                version: "1.0.0".into(),
                license: Some("MIT".into()),
                repository: Some("https://git.example.com".into()),
                homepage: Some("https://www.example.com".into()),
                description: Some("Fake package".into()),
                documentation: Some("https://docs.example.com".into()),
                dependencies: vec![Dependency {
                    name: "fake-dependency".into(),
                    req: "^1.0.0".into(),
                    kind: None,
                }],
                targets: vec![Target::dummy_lib("fake_package".into(), None)],
                readme: None,
                keywords: vec!["fake".into(), "package".into()],
                authors: vec!["Fake Person <fake@example.com>".into()],
            },
            build_result: BuildResult {
                rustc_version: "rustc 2.0.0-nightly (000000000 1970-01-01)".into(),
                docsrs_version: "docs.rs 1.0.0 (000000000 1970-01-01)".into(),
                build_log: "It works!".into(),
                successful: true,
            },
            source_files: Vec::new(),
            rustdoc_files: Vec::new(),
            doc_targets: Vec::new(),
            default_target: None,
            cratesio_data: CratesIoData {
                release_time: time::get_time(),
                yanked: false,
                downloads: 0,
                owners: Vec::new(),
            },
            has_docs: true,
            has_examples: false,
        }
    }

    pub(crate) fn name(mut self, new: &str) -> Self {
        self.package.name = new.into();
        self.package.id = format!("{}-id", new);
        self.package.targets[0].name = new.into();
        self
    }

    pub(crate) fn version(mut self, new: &str) -> Self {
        self.package.version = new.into();
        self
    }

    pub(crate) fn repo(mut self, repo: impl Into<String>) -> Self {
        self.package.repository = Some(repo.into());
        self
    }

    pub(crate) fn build_result_successful(mut self, new: bool) -> Self {
        self.build_result.successful = new;
        self
    }

    pub(crate) fn cratesio_data_yanked(mut self, new: bool) -> Self {
        self.cratesio_data.yanked = new;
        self
    }

    pub(crate) fn rustdoc_file(mut self, path: &'a str, data: &'a [u8]) -> Self {
        self.rustdoc_files.push((path, data));
        self
    }

    pub(crate) fn source_file(mut self, path: &'a str, data: &'a [u8]) -> Self {
        self.source_files.push((path, data));
        self
    }

    pub(crate) fn default_target(mut self, target: &'a str) -> Self {
        self = self.add_target(target);
        self.default_target = Some(target);
        self
    }

    pub(crate) fn add_target(mut self, target: &str) -> Self {
        self.doc_targets.push(target.into());
        self
    }

    pub(crate) fn binary(mut self, bin: bool) -> Self {
        self.has_docs = !bin;
        if bin {
            for target in self.package.targets.iter_mut() {
                target.crate_types = vec!["bin".into()];
            }
        }
        self
    }

    pub(crate) fn add_platform<S: Into<String>>(mut self, platform: S) -> Self {
        let platform = platform.into();
        let name = self.package.targets[0].name.clone();
        let target = Target::dummy_lib(name, Some(platform.clone()));
        self.package.targets.push(target);
        self.doc_targets.push(platform);
        self
    }

    pub(crate) fn create(self) -> Result<i32, Error> {
        use std::fs;
        use std::path::Path;

        let tempdir = tempdir::TempDir::new("docs.rs-fake")?;
        let package = self.package;
        let db = self.db;

        let mut source_meta = None;
        if self.build_result.successful {
            let upload_files = |prefix: &str, files: &[(&str, &[u8])], target: Option<&str>| {
                let mut path_prefix = tempdir.path().join(prefix);
                if let Some(target) = target {
                    path_prefix.push(target);
                }
                fs::create_dir(&path_prefix)?;

                for (path, data) in files {
                    // allow `src/main.rs`
                    if let Some(parent) = Path::new(path).parent() {
                        fs::create_dir_all(path_prefix.join(parent))?;
                    }
                    let file = path_prefix.join(&path);
                    log::debug!("writing file {}", file.display());
                    fs::write(file, data)?;
                }

                let prefix = format!(
                    "{}/{}/{}/{}",
                    prefix,
                    package.name,
                    package.version,
                    target.unwrap_or("")
                );
                log::debug!("adding directory {} from {}", prefix, path_prefix.display());
                crate::db::add_path_into_database(&db.conn(), &prefix, path_prefix)
            };

            let index = [&package.name, "index.html"].join("/");
            let mut rustdoc_files = self.rustdoc_files;
            if package.is_library() && !rustdoc_files.iter().any(|(path, _)| path == &index) {
                rustdoc_files.push((&index, b"default index content"));
            }
            for (source_path, data) in &self.source_files {
                if source_path.starts_with("src/") {
                    let updated = ["src", &package.name, &source_path[4..]].join("/");
                    rustdoc_files.push((Box::leak(Box::new(updated)), data));
                }
            }
            let rustdoc_meta = upload_files("rustdoc", &rustdoc_files, None)?;
            log::debug!("added rustdoc files {}", rustdoc_meta);
            source_meta = Some(upload_files("source", &self.source_files, None)?);
            log::debug!("added source files {}", source_meta.as_ref().unwrap());

            for target in &package.targets[1..] {
                let platform = target.src_path.as_ref().unwrap();
                upload_files("rustdoc", &rustdoc_files, Some(platform))?;
                log::debug!("added platform files for {}", platform);
            }
        }

        let release_id = crate::db::add_package_into_database(
            &db.conn(),
            &package,
            tempdir.path(),
            &self.build_result,
            self.default_target.unwrap_or("x86_64-unknown-linux-gnu"),
            source_meta,
            self.doc_targets,
            &self.cratesio_data,
            self.has_docs,
            self.has_examples,
        )?;
        crate::db::add_build_into_database(&db.conn(), release_id, &self.build_result)?;

        Ok(release_id)
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::prelude::*;
fn main(){
	use std::io::prelude::*;
	use std::fs::File;
	let mut f = File::open("input.txt").unwrap();
	let mut s = String::new();
	f.read_to_string(&mut s);
	let mut output = 0;
  for ch in s.chars(){
    match ch{
      '(' => output += 1,
      ')' => output -= 1,
      _ => output += 0
      }
  }
  println!("{}",output);
}
<commit_msg>Update problem1.rs<commit_after>use std::fs::File;
use std::io::prelude::*;
fn main(){
	let mut f = File::open("input.txt").unwrap();
	let mut s = String::new();
	f.read_to_string(&mut s);
	let mut output = 0;
  for ch in s.chars(){
    match ch{
      '(' => output += 1,
      ')' => output -= 1,
      _ => output += 0
      }
  }
  println!("{}",output);
}
<|endoftext|>


<commit_before>// Copyright 2015 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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 ipc::{self, IpcOneShotServer, IpcReceiver, IpcReceiverSet, IpcSender, IpcSharedMemory};
use ipc::{OpaqueIpcSender};
use router::ROUTER;

use libc;
use std::iter;
use std::sync::mpsc::{self, Sender};
use std::thread;

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
struct Person {
    name: String,
    age: u32,
}

#[derive(Clone, Serialize, Deserialize)]
struct PersonAndSender {
    person: Person,
    sender: IpcSender<Person>,
}

#[derive(Clone, Serialize, Deserialize)]
struct PersonAndOpaqueSender {
    person: Person,
    sender: OpaqueIpcSender,
}

#[derive(Serialize, Deserialize)]
struct PersonAndReceiver {
    person: Person,
    receiver: IpcReceiver<Person>,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
struct PersonAndSharedMemory {
    person: Person,
    shared_memory: IpcSharedMemory,
}

#[test]
fn simple() {
    let person = Person {
        name: "Patrick Walton".to_owned(),
        age: 29,
    };
    let (tx, rx) = ipc::channel().unwrap();
    tx.send(person.clone()).unwrap();
    let received_person = rx.recv().unwrap();
    assert_eq!(person, received_person);
}

#[test]
fn embedded_senders() {
    let person = Person {
        name: "Patrick Walton".to_owned(),
        age: 29,
    };
    let (sub_tx, sub_rx) = ipc::channel().unwrap();
    let person_and_sender = PersonAndSender {
        person: person.clone(),
        sender: sub_tx,
    };
    let (super_tx, super_rx) = ipc::channel().unwrap();
    super_tx.send(person_and_sender).unwrap();
    let received_person_and_sender = super_rx.recv().unwrap();
    assert_eq!(received_person_and_sender.person, person);
    received_person_and_sender.sender.send(person.clone()).unwrap();
    let received_person = sub_rx.recv().unwrap();
    assert_eq!(received_person, person);
}

#[test]
fn embedded_receivers() {
    let person = Person {
        name: "Patrick Walton".to_owned(),
        age: 29,
    };
    let (sub_tx, sub_rx) = ipc::channel().unwrap();
    let person_and_receiver = PersonAndReceiver {
        person: person.clone(),
        receiver: sub_rx,
    };
    let (super_tx, super_rx) = ipc::channel().unwrap();
    super_tx.send(person_and_receiver).unwrap();
    let received_person_and_receiver = super_rx.recv().unwrap();
    assert_eq!(received_person_and_receiver.person, person);
    sub_tx.send(person.clone()).unwrap();
    let received_person = received_person_and_receiver.receiver.recv().unwrap();
    assert_eq!(received_person, person);
}

#[test]
fn select() {
    let (tx0, rx0) = ipc::channel().unwrap();
    let (tx1, rx1) = ipc::channel().unwrap();
    let mut rx_set = IpcReceiverSet::new().unwrap();
    let rx0_id = rx_set.add(rx0).unwrap();
    let rx1_id = rx_set.add(rx1).unwrap();

    let person = Person {
        name: "Patrick Walton".to_owned(),
        age: 29,
    };
    tx0.send(person.clone()).unwrap();
    let (received_id, received_data) =
        rx_set.select().unwrap().into_iter().next().unwrap().unwrap();
    let received_person: Person = received_data.to().unwrap();
    assert_eq!(received_id, rx0_id);
    assert_eq!(received_person, person);

    tx1.send(person.clone()).unwrap();
    let (received_id, received_data) =
        rx_set.select().unwrap().into_iter().next().unwrap().unwrap();
    let received_person: Person = received_data.to().unwrap();
    assert_eq!(received_id, rx1_id);
    assert_eq!(received_person, person);

    tx0.send(person.clone()).unwrap();
    tx1.send(person.clone()).unwrap();
    let (mut received0, mut received1) = (false, false);
    while !received0 || !received1 {
        for result in rx_set.select().unwrap().into_iter() {
            let (received_id, received_data) = result.unwrap();
            let received_person: Person = received_data.to().unwrap();
            assert_eq!(received_person, person);
            assert!(received_id == rx0_id || received_id == rx1_id);
            if received_id == rx0_id {
                assert!(!received0);
                received0 = true;
            } else if received_id == rx1_id {
                assert!(!received1);
                received1 = true;
            }
        }
    }
}

#[test]
fn cross_process_embedded_senders() {
    let person = Person {
        name: "Patrick Walton".to_owned(),
        age: 29,
    };
    let (server0, server0_name) = IpcOneShotServer::new().unwrap();
    let (server2, server2_name) = IpcOneShotServer::new().unwrap();
    unsafe {
        if libc::fork() == 0 {
            let (tx1, rx1): (IpcSender<Person>, IpcReceiver<Person>) = ipc::channel().unwrap();
            let tx0 = IpcSender::connect(server0_name).unwrap();
            tx0.send(tx1).unwrap();
            rx1.recv().unwrap();
            let tx2: IpcSender<Person> = IpcSender::connect(server2_name).unwrap();
            tx2.send(person.clone()).unwrap();
            libc::exit(0);
        }
    }
    let (_, tx1): (_, IpcSender<Person>) = server0.accept().unwrap();
    tx1.send(person.clone()).unwrap();
    let (_, received_person): (_, Person) = server2.accept().unwrap();
    assert_eq!(received_person, person);
}

#[test]
fn router_simple() {
    let person = Person {
        name: "Patrick Walton".to_owned(),
        age: 29,
    };
    let (tx, rx) = ipc::channel().unwrap();
    tx.send(person.clone()).unwrap();

    let (callback_fired_sender, callback_fired_receiver) = mpsc::channel::<Person>();
    ROUTER.add_route(rx.to_opaque(), Box::new(move |person| {
        callback_fired_sender.send(person.to().unwrap()).unwrap()
    }));
    let received_person = callback_fired_receiver.recv().unwrap();
    assert_eq!(received_person, person);
}

#[test]
fn router_routing_to_new_mpsc_receiver() {
    let person = Person {
        name: "Patrick Walton".to_owned(),
        age: 29,
    };
    let (tx, rx) = ipc::channel().unwrap();
    tx.send(person.clone()).unwrap();

    let mpsc_receiver = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(rx);
    let received_person = mpsc_receiver.recv().unwrap();
    assert_eq!(received_person, person);
}

#[test]
fn router_multiplexing() {
    let person = Person {
        name: "Patrick Walton".to_owned(),
        age: 29,
    };
    let (tx0, rx0) = ipc::channel().unwrap();
    tx0.send(person.clone()).unwrap();
    let (tx1, rx1) = ipc::channel().unwrap();
    tx1.send(person.clone()).unwrap();

    let mpsc_rx_0 = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(rx0);
    let mpsc_rx_1 = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(rx1);
    let received_person_0 = mpsc_rx_0.recv().unwrap();
    let received_person_1 = mpsc_rx_1.recv().unwrap();
    assert_eq!(received_person_0, person);
    assert_eq!(received_person_1, person);
}

#[test]
fn router_multithreaded_multiplexing() {
    let person = Person {
        name: "Patrick Walton".to_owned(),
        age: 29,
    };

    let person_for_thread = person.clone();
    let (tx0, rx0) = ipc::channel().unwrap();
    thread::spawn(move || tx0.send(person_for_thread).unwrap());
    let person_for_thread = person.clone();
    let (tx1, rx1) = ipc::channel().unwrap();
    thread::spawn(move || tx1.send(person_for_thread).unwrap());

    let mpsc_rx_0 = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(rx0);
    let mpsc_rx_1 = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(rx1);
    let received_person_0 = mpsc_rx_0.recv().unwrap();
    let received_person_1 = mpsc_rx_1.recv().unwrap();
    assert_eq!(received_person_0, person);
    assert_eq!(received_person_1, person);
}

#[test]
fn router_drops_callbacks_on_sender_shutdown() {
    struct Dropper {
        sender: Sender<i32>,
    }

    impl Drop for Dropper {
        fn drop(&mut self) {
            self.sender.send(42).unwrap()
        }
    }

    let (tx0, rx0) = ipc::channel::<()>().unwrap();
    let (drop_tx, drop_rx) = mpsc::channel();
    let dropper = Dropper {
        sender: drop_tx,
    };

    ROUTER.add_route(rx0.to_opaque(), Box::new(move |_| drop(&dropper)));
    drop(tx0);
    assert_eq!(drop_rx.recv(), Ok(42));
}

#[test]
fn router_drops_callbacks_on_cloned_sender_shutdown() {
    struct Dropper {
        sender: Sender<i32>,
    }

    impl Drop for Dropper {
        fn drop(&mut self) {
            self.sender.send(42).unwrap()
        }
    }

    let (tx0, rx0) = ipc::channel::<()>().unwrap();
    let (drop_tx, drop_rx) = mpsc::channel();
    let dropper = Dropper {
        sender: drop_tx,
    };

    ROUTER.add_route(rx0.to_opaque(), Box::new(move |_| drop(&dropper)));
    let txs = vec![tx0.clone(), tx0.clone(), tx0.clone()];
    drop(txs);
    drop(tx0);
    assert_eq!(drop_rx.recv(), Ok(42));
}

#[test]
fn router_big_data() {
    let person = Person {
        name: "Patrick Walton".to_owned(),
        age: 29,
    };
    let people: Vec<_> = iter::repeat(person).take(64 * 1024).collect();
    let (tx, rx) = ipc::channel().unwrap();
    let people_for_subthread = people.clone();
    let thread = thread::spawn(move || {
        tx.send(people_for_subthread).unwrap();
    });

    let (callback_fired_sender, callback_fired_receiver) = mpsc::channel::<Vec<Person>>();
    ROUTER.add_route(rx.to_opaque(), Box::new(move |people| {
        callback_fired_sender.send(people.to().unwrap()).unwrap()
    }));
    let received_people = callback_fired_receiver.recv().unwrap();
    assert_eq!(received_people, people);
    thread.join().unwrap();
}

#[test]
fn shared_memory() {
    let person = Person {
        name: "Patrick Walton".to_owned(),
        age: 29,
    };
    let person_and_shared_memory = PersonAndSharedMemory {
        person: person,
        shared_memory: IpcSharedMemory::from_byte(0xba, 1024 * 1024),
    };
    let (tx, rx) = ipc::channel().unwrap();
    tx.send(person_and_shared_memory.clone()).unwrap();
    let received_person_and_shared_memory = rx.recv().unwrap();
    assert_eq!(received_person_and_shared_memory, person_and_shared_memory);
    assert!(person_and_shared_memory.shared_memory.iter().all(|byte| *byte == 0xba));
    assert!(received_person_and_shared_memory.shared_memory.iter().all(|byte| *byte == 0xba));
}

#[test]
fn opaque_sender() {
    let person = Person {
        name: "Patrick Walton".to_owned(),
        age: 29,
    };
    let (tx, rx) = ipc::channel().unwrap();
    let opaque_tx = tx.to_opaque();
    let tx: IpcSender<Person> = opaque_tx.to();
    tx.send(person.clone()).unwrap();
    let received_person = rx.recv().unwrap();
    assert_eq!(person, received_person);
}

#[test]
fn embedded_opaque_senders() {
    let person = Person {
        name: "Patrick Walton".to_owned(),
        age: 29,
    };
    let (sub_tx, sub_rx) = ipc::channel::<Person>().unwrap();
    let person_and_sender = PersonAndOpaqueSender {
        person: person.clone(),
        sender: sub_tx.to_opaque(),
    };
    let (super_tx, super_rx) = ipc::channel().unwrap();
    super_tx.send(person_and_sender).unwrap();
    let received_person_and_sender = super_rx.recv().unwrap();
    assert_eq!(received_person_and_sender.person, person);
    received_person_and_sender.sender.to::<Person>().send(person.clone()).unwrap();
    let received_person = sub_rx.recv().unwrap();
    assert_eq!(received_person, person);
}

#[test]
fn try_recv() {
    let person = Person {
        name: "Patrick Walton".to_owned(),
        age: 29,
    };
    let (tx, rx) = ipc::channel().unwrap();
    assert!(rx.try_recv().is_err());
    tx.send(person.clone()).unwrap();
    let received_person = rx.try_recv().unwrap();
    assert_eq!(person, received_person);
    assert!(rx.try_recv().is_err());
}

<commit_msg>Test that sending senders over senders works properly when there are multiple paths to one of those senders in the object graph.<commit_after>// Copyright 2015 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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 ipc::{self, IpcOneShotServer, IpcReceiver, IpcReceiverSet, IpcSender, IpcSharedMemory};
use ipc::{OpaqueIpcSender};
use router::ROUTER;
use libc;
use std::iter;
use std::sync::Arc;
use std::sync::mpsc::{self, Sender};
use std::thread;

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
struct Person {
    name: String,
    age: u32,
}

#[derive(Clone, Serialize, Deserialize)]
struct PersonAndSender {
    person: Person,
    sender: IpcSender<Person>,
}

#[derive(Clone, Serialize, Deserialize)]
struct PersonAndOpaqueSender {
    person: Person,
    sender: OpaqueIpcSender,
}

#[derive(Serialize, Deserialize)]
struct PersonAndReceiver {
    person: Person,
    receiver: IpcReceiver<Person>,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
struct PersonAndSharedMemory {
    person: Person,
    shared_memory: IpcSharedMemory,
}

#[test]
fn simple() {
    let person = Person {
        name: "Patrick Walton".to_owned(),
        age: 29,
    };
    let (tx, rx) = ipc::channel().unwrap();
    tx.send(person.clone()).unwrap();
    let received_person = rx.recv().unwrap();
    assert_eq!(person, received_person);
}

#[test]
fn embedded_senders() {
    let person = Person {
        name: "Patrick Walton".to_owned(),
        age: 29,
    };
    let (sub_tx, sub_rx) = ipc::channel().unwrap();
    let person_and_sender = PersonAndSender {
        person: person.clone(),
        sender: sub_tx,
    };
    let (super_tx, super_rx) = ipc::channel().unwrap();
    super_tx.send(person_and_sender).unwrap();
    let received_person_and_sender = super_rx.recv().unwrap();
    assert_eq!(received_person_and_sender.person, person);
    received_person_and_sender.sender.send(person.clone()).unwrap();
    let received_person = sub_rx.recv().unwrap();
    assert_eq!(received_person, person);
}

#[test]
fn embedded_receivers() {
    let person = Person {
        name: "Patrick Walton".to_owned(),
        age: 29,
    };
    let (sub_tx, sub_rx) = ipc::channel().unwrap();
    let person_and_receiver = PersonAndReceiver {
        person: person.clone(),
        receiver: sub_rx,
    };
    let (super_tx, super_rx) = ipc::channel().unwrap();
    super_tx.send(person_and_receiver).unwrap();
    let received_person_and_receiver = super_rx.recv().unwrap();
    assert_eq!(received_person_and_receiver.person, person);
    sub_tx.send(person.clone()).unwrap();
    let received_person = received_person_and_receiver.receiver.recv().unwrap();
    assert_eq!(received_person, person);
}

#[test]
fn select() {
    let (tx0, rx0) = ipc::channel().unwrap();
    let (tx1, rx1) = ipc::channel().unwrap();
    let mut rx_set = IpcReceiverSet::new().unwrap();
    let rx0_id = rx_set.add(rx0).unwrap();
    let rx1_id = rx_set.add(rx1).unwrap();

    let person = Person {
        name: "Patrick Walton".to_owned(),
        age: 29,
    };
    tx0.send(person.clone()).unwrap();
    let (received_id, received_data) =
        rx_set.select().unwrap().into_iter().next().unwrap().unwrap();
    let received_person: Person = received_data.to().unwrap();
    assert_eq!(received_id, rx0_id);
    assert_eq!(received_person, person);

    tx1.send(person.clone()).unwrap();
    let (received_id, received_data) =
        rx_set.select().unwrap().into_iter().next().unwrap().unwrap();
    let received_person: Person = received_data.to().unwrap();
    assert_eq!(received_id, rx1_id);
    assert_eq!(received_person, person);

    tx0.send(person.clone()).unwrap();
    tx1.send(person.clone()).unwrap();
    let (mut received0, mut received1) = (false, false);
    while !received0 || !received1 {
        for result in rx_set.select().unwrap().into_iter() {
            let (received_id, received_data) = result.unwrap();
            let received_person: Person = received_data.to().unwrap();
            assert_eq!(received_person, person);
            assert!(received_id == rx0_id || received_id == rx1_id);
            if received_id == rx0_id {
                assert!(!received0);
                received0 = true;
            } else if received_id == rx1_id {
                assert!(!received1);
                received1 = true;
            }
        }
    }
}

#[test]
fn cross_process_embedded_senders() {
    let person = Person {
        name: "Patrick Walton".to_owned(),
        age: 29,
    };
    let (server0, server0_name) = IpcOneShotServer::new().unwrap();
    let (server2, server2_name) = IpcOneShotServer::new().unwrap();
    unsafe {
        if libc::fork() == 0 {
            let (tx1, rx1): (IpcSender<Person>, IpcReceiver<Person>) = ipc::channel().unwrap();
            let tx0 = IpcSender::connect(server0_name).unwrap();
            tx0.send(tx1).unwrap();
            rx1.recv().unwrap();
            let tx2: IpcSender<Person> = IpcSender::connect(server2_name).unwrap();
            tx2.send(person.clone()).unwrap();
            libc::exit(0);
        }
    }
    let (_, tx1): (_, IpcSender<Person>) = server0.accept().unwrap();
    tx1.send(person.clone()).unwrap();
    let (_, received_person): (_, Person) = server2.accept().unwrap();
    assert_eq!(received_person, person);
}

#[test]
fn router_simple() {
    let person = Person {
        name: "Patrick Walton".to_owned(),
        age: 29,
    };
    let (tx, rx) = ipc::channel().unwrap();
    tx.send(person.clone()).unwrap();

    let (callback_fired_sender, callback_fired_receiver) = mpsc::channel::<Person>();
    ROUTER.add_route(rx.to_opaque(), Box::new(move |person| {
        callback_fired_sender.send(person.to().unwrap()).unwrap()
    }));
    let received_person = callback_fired_receiver.recv().unwrap();
    assert_eq!(received_person, person);
}

#[test]
fn router_routing_to_new_mpsc_receiver() {
    let person = Person {
        name: "Patrick Walton".to_owned(),
        age: 29,
    };
    let (tx, rx) = ipc::channel().unwrap();
    tx.send(person.clone()).unwrap();

    let mpsc_receiver = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(rx);
    let received_person = mpsc_receiver.recv().unwrap();
    assert_eq!(received_person, person);
}

#[test]
fn router_multiplexing() {
    let person = Person {
        name: "Patrick Walton".to_owned(),
        age: 29,
    };
    let (tx0, rx0) = ipc::channel().unwrap();
    tx0.send(person.clone()).unwrap();
    let (tx1, rx1) = ipc::channel().unwrap();
    tx1.send(person.clone()).unwrap();

    let mpsc_rx_0 = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(rx0);
    let mpsc_rx_1 = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(rx1);
    let received_person_0 = mpsc_rx_0.recv().unwrap();
    let received_person_1 = mpsc_rx_1.recv().unwrap();
    assert_eq!(received_person_0, person);
    assert_eq!(received_person_1, person);
}

#[test]
fn router_multithreaded_multiplexing() {
    let person = Person {
        name: "Patrick Walton".to_owned(),
        age: 29,
    };

    let person_for_thread = person.clone();
    let (tx0, rx0) = ipc::channel().unwrap();
    thread::spawn(move || tx0.send(person_for_thread).unwrap());
    let person_for_thread = person.clone();
    let (tx1, rx1) = ipc::channel().unwrap();
    thread::spawn(move || tx1.send(person_for_thread).unwrap());

    let mpsc_rx_0 = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(rx0);
    let mpsc_rx_1 = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(rx1);
    let received_person_0 = mpsc_rx_0.recv().unwrap();
    let received_person_1 = mpsc_rx_1.recv().unwrap();
    assert_eq!(received_person_0, person);
    assert_eq!(received_person_1, person);
}

#[test]
fn router_drops_callbacks_on_sender_shutdown() {
    struct Dropper {
        sender: Sender<i32>,
    }

    impl Drop for Dropper {
        fn drop(&mut self) {
            self.sender.send(42).unwrap()
        }
    }

    let (tx0, rx0) = ipc::channel::<()>().unwrap();
    let (drop_tx, drop_rx) = mpsc::channel();
    let dropper = Dropper {
        sender: drop_tx,
    };

    ROUTER.add_route(rx0.to_opaque(), Box::new(move |_| drop(&dropper)));
    drop(tx0);
    assert_eq!(drop_rx.recv(), Ok(42));
}

#[test]
fn router_drops_callbacks_on_cloned_sender_shutdown() {
    struct Dropper {
        sender: Sender<i32>,
    }

    impl Drop for Dropper {
        fn drop(&mut self) {
            self.sender.send(42).unwrap()
        }
    }

    let (tx0, rx0) = ipc::channel::<()>().unwrap();
    let (drop_tx, drop_rx) = mpsc::channel();
    let dropper = Dropper {
        sender: drop_tx,
    };

    ROUTER.add_route(rx0.to_opaque(), Box::new(move |_| drop(&dropper)));
    let txs = vec![tx0.clone(), tx0.clone(), tx0.clone()];
    drop(txs);
    drop(tx0);
    assert_eq!(drop_rx.recv(), Ok(42));
}

#[test]
fn router_big_data() {
    let person = Person {
        name: "Patrick Walton".to_owned(),
        age: 29,
    };
    let people: Vec<_> = iter::repeat(person).take(64 * 1024).collect();
    let (tx, rx) = ipc::channel().unwrap();
    let people_for_subthread = people.clone();
    let thread = thread::spawn(move || {
        tx.send(people_for_subthread).unwrap();
    });

    let (callback_fired_sender, callback_fired_receiver) = mpsc::channel::<Vec<Person>>();
    ROUTER.add_route(rx.to_opaque(), Box::new(move |people| {
        callback_fired_sender.send(people.to().unwrap()).unwrap()
    }));
    let received_people = callback_fired_receiver.recv().unwrap();
    assert_eq!(received_people, people);
    thread.join().unwrap();
}

#[test]
fn shared_memory() {
    let person = Person {
        name: "Patrick Walton".to_owned(),
        age: 29,
    };
    let person_and_shared_memory = PersonAndSharedMemory {
        person: person,
        shared_memory: IpcSharedMemory::from_byte(0xba, 1024 * 1024),
    };
    let (tx, rx) = ipc::channel().unwrap();
    tx.send(person_and_shared_memory.clone()).unwrap();
    let received_person_and_shared_memory = rx.recv().unwrap();
    assert_eq!(received_person_and_shared_memory, person_and_shared_memory);
    assert!(person_and_shared_memory.shared_memory.iter().all(|byte| *byte == 0xba));
    assert!(received_person_and_shared_memory.shared_memory.iter().all(|byte| *byte == 0xba));
}

#[test]
fn opaque_sender() {
    let person = Person {
        name: "Patrick Walton".to_owned(),
        age: 29,
    };
    let (tx, rx) = ipc::channel().unwrap();
    let opaque_tx = tx.to_opaque();
    let tx: IpcSender<Person> = opaque_tx.to();
    tx.send(person.clone()).unwrap();
    let received_person = rx.recv().unwrap();
    assert_eq!(person, received_person);
}

#[test]
fn embedded_opaque_senders() {
    let person = Person {
        name: "Patrick Walton".to_owned(),
        age: 29,
    };
    let (sub_tx, sub_rx) = ipc::channel::<Person>().unwrap();
    let person_and_sender = PersonAndOpaqueSender {
        person: person.clone(),
        sender: sub_tx.to_opaque(),
    };
    let (super_tx, super_rx) = ipc::channel().unwrap();
    super_tx.send(person_and_sender).unwrap();
    let received_person_and_sender = super_rx.recv().unwrap();
    assert_eq!(received_person_and_sender.person, person);
    received_person_and_sender.sender.to::<Person>().send(person.clone()).unwrap();
    let received_person = sub_rx.recv().unwrap();
    assert_eq!(received_person, person);
}

#[test]
fn try_recv() {
    let person = Person {
        name: "Patrick Walton".to_owned(),
        age: 29,
    };
    let (tx, rx) = ipc::channel().unwrap();
    assert!(rx.try_recv().is_err());
    tx.send(person.clone()).unwrap();
    let received_person = rx.try_recv().unwrap();
    assert_eq!(person, received_person);
    assert!(rx.try_recv().is_err());
}

#[test]
fn multiple_paths_to_a_sender() {
    let person = Person {
        name: "Patrick Walton".to_owned(),
        age: 29,
    };
    let (sub_tx, sub_rx) = ipc::channel().unwrap();
    let person_and_sender = Arc::new(PersonAndSender {
        person: person.clone(),
        sender: sub_tx,
    });
    let send_data = vec![
        person_and_sender.clone(),
        person_and_sender.clone(),
        person_and_sender.clone()
    ];
    let (super_tx, super_rx) = ipc::channel().unwrap();
    super_tx.send(send_data).unwrap();
    let received_data = super_rx.recv().unwrap();
    assert_eq!(received_data[0].person, person);
    assert_eq!(received_data[1].person, person);
    assert_eq!(received_data[2].person, person);
    received_data[0].sender.send(person.clone()).unwrap();
    let received_person = sub_rx.recv().unwrap();
    assert_eq!(received_person, person);
    received_data[1].sender.send(person.clone()).unwrap();
    let received_person = sub_rx.recv().unwrap();
    assert_eq!(received_person, person);
}

<|endoftext|>


<commit_before>#![feature(slicing_syntax, macro_rules)]
#![allow(unused_must_use)]

extern crate getopts;

use std::io::{stdin, stderr, BufferedWriter};
use std::io::stdio::{stdout_raw};
use std::os::{args, set_exit_status};
use std::{uint, str};
use getopts::{getopts, optopt, optflag, usage};

use Alignment::{Left, Right, Centered};

struct DynVec<T> {
    vec: Vec<T>,
    default: T,
}

impl<T: Copy+Clone> DynVec<T> {
    fn new(default: T) -> DynVec<T> {
        DynVec { vec: Vec::new(), default: default }
    }

    fn get(&self, i: uint) -> T {
        if i < self.vec.len() {
            self.vec[i]
        } else {
            self.default
        }
    }

    fn set(&mut self, index: uint, v: T) {
        let l = self.vec.len();
        if index >= l {
            self.vec.grow(index - l + 1u, self.default);
        }
        self.vec[index] = v
    }

    fn push(&mut self, v: T) {
        self.default = v;
        self.vec.push(v);
    }
}

#[deriving(Copy, Clone)]
enum Alignment {
    Left,
    Right,
    Centered,
}

struct Opts {
    str_delim: char,
    out_sep:   Vec<u8>,
    until:     uint,
    unicode:   bool,
    align:     DynVec<Alignment>,
    max_width: DynVec<uint>,
}

macro_rules! err {
    ($fmt:expr $($arg:tt)*) => {{
        set_exit_status(1);
        writeln!(&mut stderr(), $fmt $($arg)*);
        return Err(());
    }}
}

fn parse_opts() -> Result<Opts, ()> {
    let args = args();
    let prog_name = &args[0];

    let opts = [
        optopt("o", "", "set the output separator", "output separator"),
        optopt("s", "", "set the string delimiter", "string delimiter"),
        optopt("u", "", "set the maximum column", "until"),
        optflag("U", "", "read as UTF8 and use unicode width"),
        optflag("h", "", "print this help menu"),
    ];
    let matches = match getopts(args.tail(), &opts) {
        Ok(m) => m,
        Err(f) => {
            println!("{}", f);
            set_exit_status(1);
            return Err(());
        }
    };
    if matches.opt_present("h") {
        print!("{}", usage(prog_name[], &opts));
        return Err(());
    }
    let unicode = matches.opt_present("U");
    let out_sep = match matches.opt_str("o") {
        Some(s) => s.into_bytes(),
        None => " ".to_string().into_bytes(),
    };
    let str_delim = match matches.opt_str("s") {
        Some(s) => {
            match s.len() {
                0 => 0u8 as char,
                _ => s.as_bytes()[0] as char,
            }
        },
        None => '"',
    };
    let until = match matches.opt_str("u") {
        Some(s) => match s.parse() {
            Some(u) => u,
            None => err!("-u argument has to be a number"),
        },
        None => uint::MAX,
    };
    let mut align = DynVec::new(Left);
    let mut max_width = DynVec::new(0u);
    if matches.free.len() > 0 {
        let mut fmt = matches.free[0][];
        while fmt.len() > 0 {
            let non_digit = match fmt.as_bytes().iter()
                                  .position(|&c| c < b'0' || c > b'9') {
                Some(i) => i,
                _ => err!("Invalid format sequence"),
            };
            if non_digit > 0 {
                match fmt[0..non_digit].parse() {
                    Some(i) => max_width.push(i),
                    _ => err!("Invalid format sequence"),
                }
            } else {
                max_width.push(0);
            }
            match fmt.as_bytes()[non_digit] {
                b'<' => align.push(Left),
                b'>' => align.push(Right),
                b'=' => align.push(Centered),
                _ => err!("Invalid format sequence"),
            }
            fmt = fmt[non_digit+1..];
        }
        max_width.push(0);
    }
    Ok(Opts {
        str_delim: str_delim,
        out_sep:   out_sep,
        until:     until,
        unicode:   unicode,
        align:     align,
        max_width: max_width
    })
}

struct Words {
    line: Vec<u8>,
    words: Vec<(uint, uint)>,
}

impl Words {
    fn new(line: Vec<u8>, str_delim: char, until: uint) -> Words {
        let mut words = Vec::new();
        let mut pos = 0;
        loop {
            pos += match line[pos..].iter().position(|&c| !(c as char).is_whitespace()) {
                Some(i) => i,
                None => break,
            };
            if words.len() == until {
                let end = match line[pos..].iter().position(|&c| c == b'\n') {
                    Some(e) => pos + e,
                    None => line.len(),
                };
                words.push((pos, end));
                break;
            }
            let start = pos;
            let mut esc = false;
            let mut string = false;
            for (i, &c) in line[start..].iter().enumerate() {
                if !esc && c == str_delim as u8 {
                    string = !string;
                }
                esc = !esc && c == b'\\';
                if c == b'\n' || (!string && (c == b' ' || c == b'\t')) {
                    pos += i;
                    break;
                }
            }
            words.push((start, pos));
        }
        Words { line: line, words: words }
    }

    fn iter<'a>(&'a self) -> WordIter<'a> {
        WordIter {
            pos: 0,
            line: &self.line,
            words: &self.words,
        }
    }
}

struct WordIter<'a> {
    pos: uint,
    line: &'a Vec<u8>,
    words: &'a Vec<(uint, uint)>,
}

impl<'a> Iterator<&'a [u8]> for WordIter<'a> {
    fn next(&mut self) -> Option<&'a [u8]> {
        if self.pos < self.words.len() {
            let (start, end) = self.words[self.pos];
            self.pos += 1;
            Some(self.line[start..end])
        } else {
            None
        }
    }
}

fn is_indent(c: u8) -> bool {
    c == b' ' || c == b'\t'
}

fn unsafe_byte_unicode_width(s: &[u8]) -> uint {
    unsafe { str::from_utf8_unchecked(s).width(false) }
}

fn read_as_bytes(opts: &mut Opts) -> (Option<Vec<u8>>, Vec<Words>) {
    let mut stdin = stdin();
    let mut indent: Option<Vec<u8>> = None;
    let mut lines = Vec::new();
    loop {
        let line = match stdin.read_until(b'\n') {
            Ok(l) => l,
            Err(..) => break,
        };
        if indent.is_none() {
            let tmp = line.iter().map(|c| *c).take_while(|c| is_indent(*c)).collect();
            indent = Some(tmp);
        }
        let line = Words::new(line, opts.str_delim, opts.until);
        for (i, word) in line.iter().enumerate() {
            if word.len() > opts.max_width.get(i) {
                opts.max_width.set(i, word.len());
            }
        }
        lines.push(line);
    }
    (indent, lines)
}

fn read_as_unicode(opts: &mut Opts) -> (Option<Vec<u8>>, Vec<Words>) {
    let mut stdin = stdin();
    let mut indent: Option<Vec<u8>> = None;
    let mut lines = Vec::new();
    loop {
        // Unicode validation up here
        let line = match stdin.read_line() {
            Ok(l) => l.into_bytes(),
            Err(..) => break,
        };
        if indent.is_none() {
            let tmp = line.iter().map(|c| *c).take_while(|c| is_indent(*c)).collect();
            indent = Some(tmp);
        }
        let line = Words::new(line, opts.str_delim, opts.until);
        for (i, word) in line.iter().enumerate() {
            let width = unsafe_byte_unicode_width(word);
            if width > opts.max_width.get(i) {
                opts.max_width.set(i, width);
            }
        }
        lines.push(line);
    }
    (indent, lines)
}

fn main() {
    let mut opts = match parse_opts() {
        Ok(o) => o,
        Err(..) => return,
    };

    let (indent, lines) = if opts.unicode {
        read_as_unicode(&mut opts)
    } else {
        read_as_bytes(&mut opts)
    };
    if lines.len() == 0 {
        return;
    }
    let indent = indent.unwrap();
    let padding = {
        let max_max_width = *opts.max_width.vec.iter().max().unwrap_or(&0);
        Vec::from_elem(max_max_width, b' ')
    };

    let mut stdout = BufferedWriter::new(stdout_raw());
    for line in lines.iter() {
        if line.words.len() > 0 {
            stdout.write(indent[]);
        }
        let mut words = line.iter().enumerate().peekable();
        while let Some((i, word)) = words.next() {
            let pad = opts.max_width.get(i) - if opts.unicode {
                unsafe_byte_unicode_width(word)
            } else {
                word.len()
            };
            match opts.align.get(i) {
                Left => {
                    stdout.write(word);
                    if words.peek().is_some() {
                        stdout.write(padding[0..pad]);
                    }
                },
                Right => {
                    stdout.write(padding[0..pad]);
                    stdout.write(word);
                },
                Centered => {
                    stdout.write(padding[0..pad/2]);
                    stdout.write(word);
                    if words.peek().is_some() {
                        stdout.write(padding[0..pad-pad/2]);
                    }
                },
            }
            if words.peek().is_some() {
                stdout.write(opts.out_sep[]);
            }
        }
        stdout.write_str("\n");
    }
}
<commit_msg>more while let<commit_after>#![feature(slicing_syntax, macro_rules)]
#![allow(unused_must_use)]

extern crate getopts;

use std::io::{stdin, stderr, BufferedWriter};
use std::io::stdio::{stdout_raw};
use std::os::{args, set_exit_status};
use std::{uint, str};
use getopts::{getopts, optopt, optflag, usage};

use Alignment::{Left, Right, Centered};

struct DynVec<T> {
    vec: Vec<T>,
    default: T,
}

impl<T: Copy+Clone> DynVec<T> {
    fn new(default: T) -> DynVec<T> {
        DynVec { vec: Vec::new(), default: default }
    }

    fn get(&self, i: uint) -> T {
        if i < self.vec.len() {
            self.vec[i]
        } else {
            self.default
        }
    }

    fn set(&mut self, index: uint, v: T) {
        let l = self.vec.len();
        if index >= l {
            self.vec.grow(index - l + 1u, self.default);
        }
        self.vec[index] = v
    }

    fn push(&mut self, v: T) {
        self.default = v;
        self.vec.push(v);
    }
}

#[deriving(Copy, Clone)]
enum Alignment {
    Left,
    Right,
    Centered,
}

struct Opts {
    str_delim: char,
    out_sep:   Vec<u8>,
    until:     uint,
    unicode:   bool,
    align:     DynVec<Alignment>,
    max_width: DynVec<uint>,
}

macro_rules! err {
    ($fmt:expr $($arg:tt)*) => {{
        set_exit_status(1);
        writeln!(&mut stderr(), $fmt $($arg)*);
        return Err(());
    }}
}

fn parse_opts() -> Result<Opts, ()> {
    let args = args();
    let prog_name = &args[0];

    let opts = [
        optopt("o", "", "set the output separator", "output separator"),
        optopt("s", "", "set the string delimiter", "string delimiter"),
        optopt("u", "", "set the maximum column", "until"),
        optflag("U", "", "read as UTF8 and use unicode width"),
        optflag("h", "", "print this help menu"),
    ];
    let matches = match getopts(args.tail(), &opts) {
        Ok(m) => m,
        Err(f) => {
            println!("{}", f);
            set_exit_status(1);
            return Err(());
        }
    };
    if matches.opt_present("h") {
        print!("{}", usage(prog_name[], &opts));
        return Err(());
    }
    let unicode = matches.opt_present("U");
    let out_sep = match matches.opt_str("o") {
        Some(s) => s.into_bytes(),
        None => " ".to_string().into_bytes(),
    };
    let str_delim = match matches.opt_str("s") {
        Some(s) => {
            match s.len() {
                0 => 0u8 as char,
                _ => s.as_bytes()[0] as char,
            }
        },
        None => '"',
    };
    let until = match matches.opt_str("u") {
        Some(s) => match s.parse() {
            Some(u) => u,
            None => err!("-u argument has to be a number"),
        },
        None => uint::MAX,
    };
    let mut align = DynVec::new(Left);
    let mut max_width = DynVec::new(0u);
    if matches.free.len() > 0 {
        let mut fmt = matches.free[0][];
        while fmt.len() > 0 {
            let non_digit = match fmt.as_bytes().iter()
                                  .position(|&c| c < b'0' || c > b'9') {
                Some(i) => i,
                _ => err!("Invalid format sequence"),
            };
            if non_digit > 0 {
                match fmt[0..non_digit].parse() {
                    Some(i) => max_width.push(i),
                    _ => err!("Invalid format sequence"),
                }
            } else {
                max_width.push(0);
            }
            match fmt.as_bytes()[non_digit] {
                b'<' => align.push(Left),
                b'>' => align.push(Right),
                b'=' => align.push(Centered),
                _ => err!("Invalid format sequence"),
            }
            fmt = fmt[non_digit+1..];
        }
        max_width.push(0);
    }
    Ok(Opts {
        str_delim: str_delim,
        out_sep:   out_sep,
        until:     until,
        unicode:   unicode,
        align:     align,
        max_width: max_width
    })
}

struct Words {
    line: Vec<u8>,
    words: Vec<(uint, uint)>,
}

impl Words {
    fn new(line: Vec<u8>, str_delim: char, until: uint) -> Words {
        let mut words = Vec::new();
        let mut pos = 0;
        loop {
            pos += match line[pos..].iter().position(|&c| !(c as char).is_whitespace()) {
                Some(i) => i,
                None => break,
            };
            if words.len() == until {
                let end = match line[pos..].iter().position(|&c| c == b'\n') {
                    Some(e) => pos + e,
                    None => line.len(),
                };
                words.push((pos, end));
                break;
            }
            let start = pos;
            let mut esc = false;
            let mut string = false;
            for (i, &c) in line[start..].iter().enumerate() {
                if !esc && c == str_delim as u8 {
                    string = !string;
                }
                esc = !esc && c == b'\\';
                if c == b'\n' || (!string && (c == b' ' || c == b'\t')) {
                    pos += i;
                    break;
                }
            }
            words.push((start, pos));
        }
        Words { line: line, words: words }
    }

    fn iter<'a>(&'a self) -> WordIter<'a> {
        WordIter {
            pos: 0,
            line: &self.line,
            words: &self.words,
        }
    }
}

struct WordIter<'a> {
    pos: uint,
    line: &'a Vec<u8>,
    words: &'a Vec<(uint, uint)>,
}

impl<'a> Iterator<&'a [u8]> for WordIter<'a> {
    fn next(&mut self) -> Option<&'a [u8]> {
        if self.pos < self.words.len() {
            let (start, end) = self.words[self.pos];
            self.pos += 1;
            Some(self.line[start..end])
        } else {
            None
        }
    }
}

fn is_indent(c: u8) -> bool {
    c == b' ' || c == b'\t'
}

fn unsafe_byte_unicode_width(s: &[u8]) -> uint {
    unsafe { str::from_utf8_unchecked(s).width(false) }
}

fn read_as_bytes(opts: &mut Opts) -> (Option<Vec<u8>>, Vec<Words>) {
    let mut stdin = stdin();
    let mut indent: Option<Vec<u8>> = None;
    let mut lines = Vec::new();
    while let Ok(line) = stdin.read_until(b'\n') {
        if indent.is_none() {
            let tmp = line.iter().map(|c| *c).take_while(|c| is_indent(*c)).collect();
            indent = Some(tmp);
        }
        let line = Words::new(line, opts.str_delim, opts.until);
        for (i, word) in line.iter().enumerate() {
            if word.len() > opts.max_width.get(i) {
                opts.max_width.set(i, word.len());
            }
        }
        lines.push(line);
    }
    (indent, lines)
}

fn read_as_unicode(opts: &mut Opts) -> (Option<Vec<u8>>, Vec<Words>) {
    let mut stdin = stdin();
    let mut indent: Option<Vec<u8>> = None;
    let mut lines = Vec::new();
    while let Ok(line) = stdin.read_line() { // Unicode validation up here
        let line = line.into_bytes();
        if indent.is_none() {
            let tmp = line.iter().map(|c| *c).take_while(|c| is_indent(*c)).collect();
            indent = Some(tmp);
        }
        let line = Words::new(line, opts.str_delim, opts.until);
        for (i, word) in line.iter().enumerate() {
            let width = unsafe_byte_unicode_width(word);
            if width > opts.max_width.get(i) {
                opts.max_width.set(i, width);
            }
        }
        lines.push(line);
    }
    (indent, lines)
}

fn main() {
    let mut opts = match parse_opts() {
        Ok(o) => o,
        Err(..) => return,
    };

    let (indent, lines) = if opts.unicode {
        read_as_unicode(&mut opts)
    } else {
        read_as_bytes(&mut opts)
    };
    if lines.len() == 0 {
        return;
    }
    let indent = indent.unwrap();
    let padding = {
        let max_max_width = *opts.max_width.vec.iter().max().unwrap_or(&0);
        Vec::from_elem(max_max_width, b' ')
    };

    let mut stdout = BufferedWriter::new(stdout_raw());
    for line in lines.iter() {
        if line.words.len() > 0 {
            stdout.write(indent[]);
        }
        let mut words = line.iter().enumerate().peekable();
        while let Some((i, word)) = words.next() {
            let pad = opts.max_width.get(i) - if opts.unicode {
                unsafe_byte_unicode_width(word)
            } else {
                word.len()
            };
            match opts.align.get(i) {
                Left => {
                    stdout.write(word);
                    if words.peek().is_some() {
                        stdout.write(padding[0..pad]);
                    }
                },
                Right => {
                    stdout.write(padding[0..pad]);
                    stdout.write(word);
                },
                Centered => {
                    stdout.write(padding[0..pad/2]);
                    stdout.write(word);
                    if words.peek().is_some() {
                        stdout.write(padding[0..pad-pad/2]);
                    }
                },
            }
            if words.peek().is_some() {
                stdout.write(opts.out_sep[]);
            }
        }
        stdout.write_str("\n");
    }
}
<|endoftext|>


<commit_before>use std::net::url::Url;
use url_from_str = std::net::url::from_str;
use std::cell::Cell;
use util::{DataStream, VoidPtrLike};
use values::*;
use types::*;
use units::*;
use color::{Color, rgb};
use select::{SelectCtx, SelectHandler};
use stylesheet::Stylesheet;
use computed::ComputedStyle;
use complete::CompleteSelectResults;

fn test_url() -> Url {
    result::unwrap(url_from_str("http://foo.com"))
}

fn style_stream(style: &str) -> DataStream {
    let style = Cell(style.to_str());
    |move style| if !style.is_empty() {
        Some(str::to_bytes(style.take()))
    } else {
        None
    }
}

enum TestNode = @NodeData;

struct NodeData {
    name: ~str,
    children: ~[TestNode],
    mut parent: Option<TestNode>
}

impl TestNode: VoidPtrLike {
    static fn from_void_ptr(node: *libc::c_void) -> TestNode {
        assert node.is_not_null();
        TestNode(unsafe {
            let box = cast::reinterpret_cast(&node);
            cast::bump_box_refcount(box);
            box
        })
    }

    fn to_void_ptr(&self) -> *libc::c_void {
        unsafe { cast::reinterpret_cast(&(*self)) }
    }
}

struct TestHandler {
    bogus: int
}

impl TestHandler {
    static fn new() -> TestHandler {
        TestHandler {
            bogus: 0
        }
    }
}

impl TestHandler: SelectHandler<TestNode> {
    fn node_name(node: &TestNode) -> ~str { copy (*node).name }
    fn named_parent_node(node: &TestNode, name: &str) -> Option<TestNode> {
        match (**node).parent {
            Some(parent) => {
                if name == (**parent).name {
                    Some(parent)
                } else {
                    None
                }
            }
            None => None
        }
    }
    fn parent_node(node: &TestNode) -> Option<TestNode> { (**node).parent }
    fn named_ancestor_node(node: &TestNode) -> Option<TestNode> { fail ~"TODO" }
    fn node_is_root(node: &TestNode) -> bool { self.parent_node(node).is_none() }
}

fn single_div_test(style: &str, f: &fn(&ComputedStyle)) {
    let sheet = Stylesheet::new(test_url(), style_stream(style));
    let mut select_ctx = SelectCtx::new();
    let handler = &TestHandler::new();
    select_ctx.append_sheet(move sheet, OriginAuthor);
    let dom = &TestNode(@NodeData {
        name: ~"div",
        children: ~[],
        parent: None
    });
    let style = select_ctx.select_style(dom, handler);
    let computed = style.computed_style();
    f(&computed);
}

#[test]
fn test_background_color_simple() {
    let style = "div { background-color: #123456; }";
    do single_div_test(style) |computed| {
        let color = computed.background_color();
        assert color == Specified(rgb(0x12, 0x34, 0x56));
    }
}

#[test]
fn test_border_top_width_px() {
    let style = "div { border-top-width: 10px; }";
    do single_div_test(style) |computed| {
        let width = computed.border_top_width();
        assert width == Specified(CSSBorderWidthLength(Px(10.0)));
    }
}

#[test]
fn test_border_right_width_px() {
    let style = "div { border-right-width: 10px; }";
    do single_div_test(style) |computed| {
        let width = computed.border_right_width();
        assert width == Specified(CSSBorderWidthLength(Px(10.0)));
    }
}

#[test]
fn test_border_bottom_width_px() {
    let style = "div { border-bottom-width: 10px; }";
    do single_div_test(style) |computed| {
        let width = computed.border_bottom_width();
        assert width == Specified(CSSBorderWidthLength(Px(10.0)));
    }
}

#[test]
fn test_border_left_width_px() {
    let style = "div { border-left-width: 10px; }";
    do single_div_test(style) |computed| {
        let width = computed.border_left_width();
        assert width == Specified(CSSBorderWidthLength(Px(10.0)));
    }
}

#[test]
fn test_border_width_px() {
    let style = "div { border-width: 10px; }";
    do single_div_test(style) |computed| {
        let width = computed.border_top_width();
        assert width == Specified(CSSBorderWidthLength(Px(10.0)));
        let width = computed.border_right_width();
        assert width == Specified(CSSBorderWidthLength(Px(10.0)));
        let width = computed.border_bottom_width();
        assert width == Specified(CSSBorderWidthLength(Px(10.0)));
        let width = computed.border_left_width();
        assert width == Specified(CSSBorderWidthLength(Px(10.0)));
    }
}

#[test]
fn test_border_color() {
    let style = "div {\
                 border-top-color: red;\
                 border-right-color: green;\
                 border-bottom-color: blue;\
                 border-left-color: yellow;\
                 }";
    do single_div_test(style) |computed| {
        let top_color = computed.border_top_color();
        let right_color = computed.border_right_color();
        let bottom_color = computed.border_bottom_color();
        let left_color = computed.border_left_color();
        assert top_color == Specified(rgb(255, 0, 0));
        assert right_color == Specified(rgb(0, 128, 0));
        assert bottom_color == Specified(rgb(0, 0, 255));
        assert left_color == Specified(rgb(255, 255, 0));
    }
}

#[test]
fn test_border_color_shorthand() {
    let style = "div {\
                 border-color: red;\
                 }";
    do single_div_test(style) |computed| {
        let top_color = computed.border_top_color();
        let right_color = computed.border_right_color();
        let bottom_color = computed.border_bottom_color();
        let left_color = computed.border_left_color();
        assert top_color == Specified(rgb(255, 0, 0));
        assert right_color == Specified(rgb(255, 0, 0));
        assert bottom_color == Specified(rgb(255, 0, 0));
        assert left_color == Specified(rgb(255, 0, 0));
    }
}

#[test]
fn test_margin() {
    let style = "div {\
                 margin-top: 10px;\
                 margin-right: 20px;\
                 margin-bottom: 30px;\
                 margin-left: auto;\
                 }";
    do single_div_test(style) |computed| {
        assert computed.margin_top() == Specified(CSSMarginLength(Px(10.0)));
        assert computed.margin_right() == Specified(CSSMarginLength(Px(20.0)));
        assert computed.margin_bottom() == Specified(CSSMarginLength(Px(30.0)));
        assert computed.margin_left() == Specified(CSSMarginAuto);
    }
}

#[test]
fn test_display() {
    let style = "div { display: none; }";
    do single_div_test(style) |computed| {
        assert computed.display(false) == Specified(CSSDisplayNone);
    }
}

#[test]
fn test_float() {
    let style = "div { float: right; }";
    do single_div_test(style) |computed| {
        assert computed.float() == Specified(CSSFloatRight);
    }
}

#[test]
fn test_position() {
    let style = "div { position: static; }";
    do single_div_test(style) |computed| {
        assert computed.position() == Specified(CSSPositionStatic);
    }
    let style = "div { position: relative; }";
    do single_div_test(style) |computed| {
        assert computed.position() == Specified(CSSPositionRelative);
    }
    let style = "div { position: absolute; }";
    do single_div_test(style) |computed| {
        assert computed.position() == Specified(CSSPositionAbsolute);
    }
    let style = "div { position: fixed; }";
    do single_div_test(style) |computed| {
        assert computed.position() == Specified(CSSPositionFixed);
    }
}

#[test]
fn test_width() {
    let style = "div { width: 10px; }";
    do single_div_test(style) |computed| {
        assert computed.width() == Specified(CSSWidthLength(Px(10.0)));
    }
}

#[test]
fn test_height() {
    let style = "div { height: 10px; }";
    do single_div_test(style) |computed| {
        assert computed.height() == Specified(CSSHeightLength(Px(10.0)));
    }
}

#[test]
fn test_font_family_generic() {
    use units::Fantasy;

    let style = "div { font-family: fantasy; }";
    do single_div_test(style) |computed| {
        let fam = computed.font_family();
        let spec = Specified(~[CSSFontFamilyGenericFamily(Fantasy)]);
        assert fam.eq(&spec);
    }
}

#[test]
fn test_font_family_specific() {
    let style = "div { font-family: Wombat, Jones; }";
    do single_div_test(style) |computed| {
        assert computed.font_family() == Specified(~[
            CSSFontFamilyFamilyName(~"Wombat"),
            CSSFontFamilyFamilyName(~"Jones")
        ]);
    }
}

#[test]
fn test_font_size() {
    let style = "div { font-size: 10pt; }";
    do single_div_test(style) |computed| {
        assert computed.font_size() == Specified(CSSFontSizeLength(Pt(10.0)));
    }
    let style = "div { font-size: 10%; }";
    do single_div_test(style) |computed| {
        assert computed.font_size() == Specified(CSSFontSizePercentage(10.0));
    }
    let style = "div { font-size: small; }";
    do single_div_test(style) |computed| {
        assert computed.font_size() == Specified(CSSFontSizeAbsoluteSize(Small));
    }
    let style = "div { font-size: smaller; }";
    do single_div_test(style) |computed| {
        assert computed.font_size() == Specified(CSSFontSizeRelativeSize(Smaller));
    }
}

#[test]
fn test_font_style() {
    let style = "div { font-style: oblique; }";
    do single_div_test(style) |computed| {
        assert computed.font_style() == Specified(CSSFontStyleOblique);
    }
}

fn child_test(style: &str, f: &fn(&ComputedStyle)) {
    let sheet = Stylesheet::new(test_url(), style_stream(style));
    let mut select_ctx = SelectCtx::new();
    let handler = &TestHandler::new();
    select_ctx.append_sheet(move sheet, OriginAuthor);
    let child = TestNode(@NodeData {
        name: ~"span",
        children: ~[],
        parent: None
    });
    let parent = TestNode(@NodeData {
        name: ~"div",
        children: ~[child],
        parent: None
    });
    child.parent = Some(parent);
    let style = select_ctx.select_style(&child, handler);
    let computed = style.computed_style();
    f(&computed);
}

#[test]
fn test_child() {
    let style = "div > span { border-left-width: 10px; }";
    do child_test(style) |computed| {
        let width = computed.border_left_width();
        assert width == Specified(CSSBorderWidthLength(Px(10.0)));
    }
}

#[test]
fn test_not_child() {
    let style = "div > not_span { border-left-width: 10px; }";
    do child_test(style) |computed| {
        let width = computed.border_left_width();
        assert width != Specified(CSSBorderWidthLength(Px(10.0)));
    }
}

#[test]
#[ignore]
fn test_descendant() {
    let style = "div span { border-left-width: 10px; }";
    do child_test(style) |computed| {
        let width = computed.border_left_width();
        assert width == Specified(CSSBorderWidthLength(Px(10.0)));
    }
}

#[test]
fn test_compose() {
    let style = "div { background-color: blue; }\
                 span { background-color: inherit; }";

    let sheet = Stylesheet::new(test_url(), style_stream(style));
    let mut select_ctx = SelectCtx::new();
    let handler = &TestHandler::new();
    select_ctx.append_sheet(move sheet, OriginAuthor);
    let child = TestNode(@NodeData {
        name: ~"span",
        children: ~[],
        parent: None
    });
    let parent = TestNode(@NodeData {
        name: ~"div",
        children: ~[child],
        parent: None
    });
    child.parent = Some(parent);
    let parent_results = select_ctx.select_style(&parent, handler);
    let child_results = select_ctx.select_style(&child, handler);

    let complete_parent_results = CompleteSelectResults::new_root(move parent_results);
    let complete_child_results = CompleteSelectResults::new_from_parent(&complete_parent_results, move child_results);

    let computed = complete_child_results.computed_style();

    assert computed.background_color() == color::css_colors::blue();
}
<commit_msg>Fix test bustage.<commit_after>use std::net::url::Url;
use url_from_str = std::net::url::from_str;
use std::cell::Cell;
use util::{DataStream, VoidPtrLike};
use values::*;
use types::*;
use units::*;
use color::{Color, rgb};
use select::{SelectCtx, SelectHandler};
use stylesheet::Stylesheet;
use computed::ComputedStyle;
use complete::CompleteSelectResults;

fn test_url() -> Url {
    result::unwrap(url_from_str("http://foo.com"))
}

fn style_stream(style: &str) -> DataStream {
    let style = Cell(style.to_str());
    |move style| if !style.is_empty() {
        Some(str::to_bytes(style.take()))
    } else {
        None
    }
}

enum TestNode = @NodeData;

struct NodeData {
    name: ~str,
    children: ~[TestNode],
    mut parent: Option<TestNode>
}

impl TestNode: VoidPtrLike {
    static fn from_void_ptr(node: *libc::c_void) -> TestNode {
        assert node.is_not_null();
        TestNode(unsafe {
            let box = cast::reinterpret_cast(&node);
            cast::bump_box_refcount(box);
            box
        })
    }

    fn to_void_ptr(&self) -> *libc::c_void {
        unsafe { cast::reinterpret_cast(&(*self)) }
    }
}

struct TestHandler {
    bogus: int
}

impl TestHandler {
    static fn new() -> TestHandler {
        TestHandler {
            bogus: 0
        }
    }
}

impl TestHandler: SelectHandler<TestNode> {
    fn node_name(node: &TestNode) -> ~str { copy (*node).name }
    fn named_parent_node(node: &TestNode, name: &str) -> Option<TestNode> {
        match (**node).parent {
            Some(parent) => {
                if name == (**parent).name {
                    Some(parent)
                } else {
                    None
                }
            }
            None => None
        }
    }
    fn parent_node(node: &TestNode) -> Option<TestNode> { (**node).parent }
    fn named_ancestor_node(node: &TestNode, name: &str) -> Option<TestNode> { fail ~"TODO" }
    fn node_is_root(node: &TestNode) -> bool { self.parent_node(node).is_none() }
}

fn single_div_test(style: &str, f: &fn(&ComputedStyle)) {
    let sheet = Stylesheet::new(test_url(), style_stream(style));
    let mut select_ctx = SelectCtx::new();
    let handler = &TestHandler::new();
    select_ctx.append_sheet(move sheet, OriginAuthor);
    let dom = &TestNode(@NodeData {
        name: ~"div",
        children: ~[],
        parent: None
    });
    let style = select_ctx.select_style(dom, handler);
    let computed = style.computed_style();
    f(&computed);
}

#[test]
fn test_background_color_simple() {
    let style = "div { background-color: #123456; }";
    do single_div_test(style) |computed| {
        let color = computed.background_color();
        assert color == Specified(rgb(0x12, 0x34, 0x56));
    }
}

#[test]
fn test_border_top_width_px() {
    let style = "div { border-top-width: 10px; }";
    do single_div_test(style) |computed| {
        let width = computed.border_top_width();
        assert width == Specified(CSSBorderWidthLength(Px(10.0)));
    }
}

#[test]
fn test_border_right_width_px() {
    let style = "div { border-right-width: 10px; }";
    do single_div_test(style) |computed| {
        let width = computed.border_right_width();
        assert width == Specified(CSSBorderWidthLength(Px(10.0)));
    }
}

#[test]
fn test_border_bottom_width_px() {
    let style = "div { border-bottom-width: 10px; }";
    do single_div_test(style) |computed| {
        let width = computed.border_bottom_width();
        assert width == Specified(CSSBorderWidthLength(Px(10.0)));
    }
}

#[test]
fn test_border_left_width_px() {
    let style = "div { border-left-width: 10px; }";
    do single_div_test(style) |computed| {
        let width = computed.border_left_width();
        assert width == Specified(CSSBorderWidthLength(Px(10.0)));
    }
}

#[test]
fn test_border_width_px() {
    let style = "div { border-width: 10px; }";
    do single_div_test(style) |computed| {
        let width = computed.border_top_width();
        assert width == Specified(CSSBorderWidthLength(Px(10.0)));
        let width = computed.border_right_width();
        assert width == Specified(CSSBorderWidthLength(Px(10.0)));
        let width = computed.border_bottom_width();
        assert width == Specified(CSSBorderWidthLength(Px(10.0)));
        let width = computed.border_left_width();
        assert width == Specified(CSSBorderWidthLength(Px(10.0)));
    }
}

#[test]
fn test_border_color() {
    let style = "div {\
                 border-top-color: red;\
                 border-right-color: green;\
                 border-bottom-color: blue;\
                 border-left-color: yellow;\
                 }";
    do single_div_test(style) |computed| {
        let top_color = computed.border_top_color();
        let right_color = computed.border_right_color();
        let bottom_color = computed.border_bottom_color();
        let left_color = computed.border_left_color();
        assert top_color == Specified(rgb(255, 0, 0));
        assert right_color == Specified(rgb(0, 128, 0));
        assert bottom_color == Specified(rgb(0, 0, 255));
        assert left_color == Specified(rgb(255, 255, 0));
    }
}

#[test]
fn test_border_color_shorthand() {
    let style = "div {\
                 border-color: red;\
                 }";
    do single_div_test(style) |computed| {
        let top_color = computed.border_top_color();
        let right_color = computed.border_right_color();
        let bottom_color = computed.border_bottom_color();
        let left_color = computed.border_left_color();
        assert top_color == Specified(rgb(255, 0, 0));
        assert right_color == Specified(rgb(255, 0, 0));
        assert bottom_color == Specified(rgb(255, 0, 0));
        assert left_color == Specified(rgb(255, 0, 0));
    }
}

#[test]
fn test_margin() {
    let style = "div {\
                 margin-top: 10px;\
                 margin-right: 20px;\
                 margin-bottom: 30px;\
                 margin-left: auto;\
                 }";
    do single_div_test(style) |computed| {
        assert computed.margin_top() == Specified(CSSMarginLength(Px(10.0)));
        assert computed.margin_right() == Specified(CSSMarginLength(Px(20.0)));
        assert computed.margin_bottom() == Specified(CSSMarginLength(Px(30.0)));
        assert computed.margin_left() == Specified(CSSMarginAuto);
    }
}

#[test]
fn test_display() {
    let style = "div { display: none; }";
    do single_div_test(style) |computed| {
        assert computed.display(false) == Specified(CSSDisplayNone);
    }
}

#[test]
fn test_float() {
    let style = "div { float: right; }";
    do single_div_test(style) |computed| {
        assert computed.float() == Specified(CSSFloatRight);
    }
}

#[test]
fn test_position() {
    let style = "div { position: static; }";
    do single_div_test(style) |computed| {
        assert computed.position() == Specified(CSSPositionStatic);
    }
    let style = "div { position: relative; }";
    do single_div_test(style) |computed| {
        assert computed.position() == Specified(CSSPositionRelative);
    }
    let style = "div { position: absolute; }";
    do single_div_test(style) |computed| {
        assert computed.position() == Specified(CSSPositionAbsolute);
    }
    let style = "div { position: fixed; }";
    do single_div_test(style) |computed| {
        assert computed.position() == Specified(CSSPositionFixed);
    }
}

#[test]
fn test_width() {
    let style = "div { width: 10px; }";
    do single_div_test(style) |computed| {
        assert computed.width() == Specified(CSSWidthLength(Px(10.0)));
    }
}

#[test]
fn test_height() {
    let style = "div { height: 10px; }";
    do single_div_test(style) |computed| {
        assert computed.height() == Specified(CSSHeightLength(Px(10.0)));
    }
}

#[test]
fn test_font_family_generic() {
    use units::Fantasy;

    let style = "div { font-family: fantasy; }";
    do single_div_test(style) |computed| {
        let fam = computed.font_family();
        let spec = Specified(~[CSSFontFamilyGenericFamily(Fantasy)]);
        assert fam.eq(&spec);
    }
}

#[test]
fn test_font_family_specific() {
    let style = "div { font-family: Wombat, Jones; }";
    do single_div_test(style) |computed| {
        assert computed.font_family() == Specified(~[
            CSSFontFamilyFamilyName(~"Wombat"),
            CSSFontFamilyFamilyName(~"Jones")
        ]);
    }
}

#[test]
fn test_font_size() {
    let style = "div { font-size: 10pt; }";
    do single_div_test(style) |computed| {
        assert computed.font_size() == Specified(CSSFontSizeLength(Pt(10.0)));
    }
    let style = "div { font-size: 10%; }";
    do single_div_test(style) |computed| {
        assert computed.font_size() == Specified(CSSFontSizePercentage(10.0));
    }
    let style = "div { font-size: small; }";
    do single_div_test(style) |computed| {
        assert computed.font_size() == Specified(CSSFontSizeAbsoluteSize(Small));
    }
    let style = "div { font-size: smaller; }";
    do single_div_test(style) |computed| {
        assert computed.font_size() == Specified(CSSFontSizeRelativeSize(Smaller));
    }
}

#[test]
fn test_font_style() {
    let style = "div { font-style: oblique; }";
    do single_div_test(style) |computed| {
        assert computed.font_style() == Specified(CSSFontStyleOblique);
    }
}

fn child_test(style: &str, f: &fn(&ComputedStyle)) {
    let sheet = Stylesheet::new(test_url(), style_stream(style));
    let mut select_ctx = SelectCtx::new();
    let handler = &TestHandler::new();
    select_ctx.append_sheet(move sheet, OriginAuthor);
    let child = TestNode(@NodeData {
        name: ~"span",
        children: ~[],
        parent: None
    });
    let parent = TestNode(@NodeData {
        name: ~"div",
        children: ~[child],
        parent: None
    });
    child.parent = Some(parent);
    let style = select_ctx.select_style(&child, handler);
    let computed = style.computed_style();
    f(&computed);
}

#[test]
fn test_child() {
    let style = "div > span { border-left-width: 10px; }";
    do child_test(style) |computed| {
        let width = computed.border_left_width();
        assert width == Specified(CSSBorderWidthLength(Px(10.0)));
    }
}

#[test]
fn test_not_child() {
    let style = "div > not_span { border-left-width: 10px; }";
    do child_test(style) |computed| {
        let width = computed.border_left_width();
        assert width != Specified(CSSBorderWidthLength(Px(10.0)));
    }
}

#[test]
#[ignore]
fn test_descendant() {
    let style = "div span { border-left-width: 10px; }";
    do child_test(style) |computed| {
        let width = computed.border_left_width();
        assert width == Specified(CSSBorderWidthLength(Px(10.0)));
    }
}

#[test]
fn test_compose() {
    let style = "div { background-color: blue; }\
                 span { background-color: inherit; }";

    let sheet = Stylesheet::new(test_url(), style_stream(style));
    let mut select_ctx = SelectCtx::new();
    let handler = &TestHandler::new();
    select_ctx.append_sheet(move sheet, OriginAuthor);
    let child = TestNode(@NodeData {
        name: ~"span",
        children: ~[],
        parent: None
    });
    let parent = TestNode(@NodeData {
        name: ~"div",
        children: ~[child],
        parent: None
    });
    child.parent = Some(parent);
    let parent_results = select_ctx.select_style(&parent, handler);
    let child_results = select_ctx.select_style(&child, handler);

    let complete_parent_results = CompleteSelectResults::new_root(move parent_results);
    let complete_child_results = CompleteSelectResults::new_from_parent(&complete_parent_results, move child_results);

    let computed = complete_child_results.computed_style();

    assert computed.background_color() == color::css_colors::blue();
}
<|endoftext|>


<commit_before>/// A TOML [1] configuration file parser
///
/// [1]: https://github.com/mojombo/toml

use std::io::mem::MemReader;
use std::io::File;
use std::hashmap::HashMap;

fn read_char_opt(rd: &mut MemReader) -> Option<char> {
  match rd.read_byte() {
    Some(b) => Some(b as char),
    None => None
  }
}

#[deriving(ToStr)]
enum Value {
    True,
    False,
    Unsigned(u64),
    Integer(i64),
    Float(f64),
    String(~str),
    Array(~[Value]),
    Datetime, // XXX
    Map(HashMap<~str, Value>) // XXX: This is no value
}

trait Visitor {
    fn section(&mut self, name: ~str, is_array: bool) -> bool;
    fn pair(&mut self, key: ~str, val: Value) -> bool;
}

struct TOMLVisitor {
    root: HashMap<~str, Value>,
    current_section: ~str,
    section_is_array: bool
}

impl TOMLVisitor {
    fn new() -> TOMLVisitor {
        TOMLVisitor { root: HashMap::new(), current_section: ~"", section_is_array: false }
    }
    fn get_root<'a>(&'a self) -> &'a HashMap<~str, Value> {
        return &self.root;
    }
}

impl Visitor for TOMLVisitor {
    fn section(&mut self, name: ~str, is_array: bool) -> bool {
        debug!("Section: {} (is_array={})", name, is_array);
        self.section_is_array = is_array;
        self.current_section = name;
        return true
    }
    fn pair(&mut self, key: ~str, val: Value) -> bool {
        debug!("Pair: {} {:s}", key, val.to_str());
        let mut m = self.root.find_or_insert(self.current_section.clone(), Map(HashMap::new())); // XXX: remove clone
        match *m {
            Map(ref mut map) => {
                let ok = map.insert(key, val);
                return ok
            }
            _ => { return false }
        }
    }
}

// parse values recursivly
fn parse_value(rd: &mut MemReader, current_char: Option<char>) -> (Option<Value>, Option<char>) {
    let mut current_char = skip_whitespaces(rd, current_char);

    if current_char.is_none() { return (None, current_char) }
    let ch = current_char.unwrap();
    match ch {
        '0' .. '9' => {
            let (num, ch) = read_token(rd, current_char, |ch| {
                match ch {
                    '0' .. '9' => true,
                    _ => false
                }
            });
            match from_str(num) {
              Some(n) => return (Some(Unsigned(n)), ch),
              None => return (None, ch)
            }
        }
        't' => {
            current_char = read_char_opt(rd);
            if current_char != Some('r') { return (None, current_char) }
            current_char = read_char_opt(rd);
            if current_char != Some('u') { return (None, current_char) }
            current_char = read_char_opt(rd);
            if current_char != Some('e') { return (None, current_char) }
            current_char = read_char_opt(rd);

            return (Some(True), current_char)
        }
        'f' => {
            current_char = read_char_opt(rd);
            if current_char != Some('a') { return (None, current_char) }
            current_char = read_char_opt(rd);
            if current_char != Some('l') { return (None, current_char) }
            current_char = read_char_opt(rd);
            if current_char != Some('s') { return (None, current_char) }
            current_char = read_char_opt(rd);
            if current_char != Some('e') { return (None, current_char) }
            current_char = read_char_opt(rd);

            return (Some(False), current_char)
        }
        '"' => {
            current_char = read_char_opt(rd);
            let (str, ch) = read_token(rd, current_char, |ch| {
                match ch {
                    '"' => false,
                    _ => true
                }
            });
            current_char = ch;

            if current_char != Some('"') { return (None, current_char) }
            current_char = read_char_opt(rd);
            return (Some(String(str)), current_char)
        }
        _ => { return (None, current_char) }
    }
}

fn read_token(rd: &mut MemReader, current_char: Option<char>, f: |char| -> bool) -> (~str, Option<char>) {
    let mut current_char = current_char;
    let mut token = ~"";
    loop {
        match current_char {
            Some(ch) => {
                if f(ch) { token.push_char(ch) }
                else { break }
            }
            None => { break }
        }
        current_char = read_char_opt(rd); // advance
    }

    return (token, current_char);
}

fn parse_section_identifier(rd: &mut MemReader, current_char: Option<char>) -> (~str, Option<char>) {
    read_token(rd, current_char, |ch| {
        match ch {
            'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '.' | '_' => true,
            _ => false
        }
    })
}

fn skip_whitespaces(rd: &mut MemReader, current_char: Option<char>) -> Option<char> {
    let mut current_char = current_char;
    loop {
        match current_char {
            Some(' ') | Some('\t') | Some('\r') | Some('\n') => {
                current_char = read_char_opt(rd); // advance
            }
            _ => { break }
        }
    }
    return current_char;
}

fn parse<V: Visitor>(rd: &mut MemReader, visitor: &mut V) -> bool {
    let mut current_char: Option<char> = read_char_opt(rd);

    loop {
        if current_char.is_none() { return true }
        let ch = current_char.unwrap();
        match ch {
            // ignore whitespace
            '\r' | '\n' | ' ' | '\t' => { }

            // comment
            '#' => {
                // skip to end of line
                loop {
                    current_char = read_char_opt(rd);
                    match current_char {
                        Some('\n') => { break }
                        None => { return true }
                        _ => { /* skip */ }
                    }
                }
            }

            // section
            '[' => {
                current_char = read_char_opt(rd); // advance
                let mut double_section = false;
                match current_char {
                    Some('[') => {
                        double_section = true;
                        current_char = read_char_opt(rd); // advance
                    }
                    _ => {}
                }

                let (section_name, ch) = parse_section_identifier(rd, current_char);
                current_char = ch;

                match current_char {
                    Some(']') => { /* ok */ }
                    _ => { return false }
                }

                if double_section {
                    current_char = read_char_opt(rd); // advance
                    if current_char != Some(']') { return false }
                }

                visitor.section(section_name, double_section);
            }

            // identifier
            'a' .. 'z' | 'A' .. 'Z' | '_' => {

                let (ident, ch) = read_token(rd, current_char, |ch| {
                    match ch {
                        'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '_' => true,
                        _ => false
                    }
                });

                current_char = ch;
                current_char = skip_whitespaces(rd, current_char);

                // assign wanted
                if current_char != Some('=') { return false }

                current_char = read_char_opt(rd); // advance
                let (val, ch) = parse_value(rd, current_char);
                current_char = ch;
                match val {
                  Some(v) => { visitor.pair(ident, v); }
                  None => { return false; }
                }
                continue; // do not advance!
            }

            _ => { return false }
        } /* end match */
        current_char = read_char_opt(rd); // advance
    }

    assert!(false);
}

fn main() {
  let contents = File::open(&Path::new(std::os::args()[1])).read_to_end();
  let mut rd = MemReader::new(contents);
  let mut visitor = TOMLVisitor::new();
  parse(&mut rd, &mut visitor);
  println!("{:s}", visitor.get_root().to_str());
}
<commit_msg>Use mutable parser state<commit_after>/// A TOML [1] configuration file parser
///
/// [1]: https://github.com/mojombo/toml

use std::io::mem::MemReader;
use std::io::File;
use std::hashmap::HashMap;

#[deriving(ToStr)]
enum Value {
    True,
    False,
    Unsigned(u64),
    Integer(i64),
    Float(f64),
    String(~str),
    Array(~[Value]),
    Datetime, // XXX
    Map(HashMap<~str, Value>) // XXX: This is no value
}

trait Visitor {
    fn section(&mut self, name: ~str, is_array: bool) -> bool;
    fn pair(&mut self, key: ~str, val: Value) -> bool;
}

struct TOMLVisitor {
    root: HashMap<~str, Value>,
    current_section: ~str,
    section_is_array: bool
}

impl TOMLVisitor {
    fn new() -> TOMLVisitor {
        TOMLVisitor { root: HashMap::new(), current_section: ~"", section_is_array: false }
    }
    fn get_root<'a>(&'a self) -> &'a HashMap<~str, Value> {
        return &self.root;
    }
}

impl Visitor for TOMLVisitor {
    fn section(&mut self, name: ~str, is_array: bool) -> bool {
        debug!("Section: {} (is_array={})", name, is_array);
        self.section_is_array = is_array;
        self.current_section = name;
        return true
    }
    fn pair(&mut self, key: ~str, val: Value) -> bool {
        debug!("Pair: {} {:s}", key, val.to_str());
        let mut m = self.root.find_or_insert(self.current_section.clone(), Map(HashMap::new())); // XXX: remove clone
        match *m {
            Map(ref mut map) => {
                let ok = map.insert(key, val);
                return ok
            }
            _ => { return false }
        }
    }
}

fn read_char_opt(rd: &mut MemReader) -> Option<char> {
  match rd.read_byte() {
    Some(b) => Some(b as char),
    None => None
  }
}

struct Parser<'a> {
    rd: &'a mut MemReader,
    current_char: Option<char>
}

impl<'a> Parser<'a> {
    fn new(rd: &'a mut MemReader) -> Parser<'a> {
        let ch = read_char_opt(rd);
        Parser { rd: rd, current_char: ch }
    }

    fn advance(&mut self) {
      self.current_char = read_char_opt(self.rd);
    }

    fn ch(&self) -> Option<char> {
        return self.current_char;
    }

    fn eos(&self) -> bool {
        return self.current_char.is_none();
    }

    fn advance_if(&mut self, c: char) -> bool {
        match self.ch() {
            Some(c) => {
               self.advance();
               true
            }
            _ => {
                false
            }
        }
    }

// parse values recursivly
fn parse_value(&mut self) -> Option<Value> {
    self.skip_whitespaces();

    if self.eos() { return None }
    match self.ch().unwrap() {
        '0' .. '9' => {
            let num = self.read_token(|ch| {
                match ch {
                    '0' .. '9' => true,
                    _ => false
                }
            });
            match from_str(num) {
              Some(n) => return Some(Unsigned(n)),
              None => return None
            }
        }
        't' => {
            self.advance();
            if self.advance_if('r') &&
               self.advance_if('u') &&
               self.advance_if('e') {
                return Some(True)
            } else {
                return None
            }
        }
        'f' => {
            self.advance();
            if self.advance_if('a') &&
               self.advance_if('l') &&
               self.advance_if('s') &&
               self.advance_if('e') {
                return Some(True)
            } else {
                return None
            }
        }
        '"' => {
            self.advance();
            let str = self.read_token(|ch| {
                match ch {
                    '"' => false,
                    _ => true
                }
            });
            if self.advance_if('"') {
                return Some(String(str))
            } else {
                return None
            }
        }
        _ => { return None }
    }
}

fn read_token(&mut self, f: |char| -> bool) -> ~str {
    let mut token = ~"";
    loop {
        match self.ch() {
            Some(ch) => {
                if f(ch) { token.push_char(ch) }
                else { break }
            }
            None => { break }
        }
        self.advance();
    }

    return token;
}

fn parse_section_identifier(&mut self) -> ~str {
    self.read_token(|ch| {
        match ch {
            'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '.' | '_' => true,
            _ => false
        }
    })
}

fn skip_whitespaces(&mut self) {
    loop {
        match self.ch() {
            Some(' ') | Some('\t') | Some('\r') | Some('\n') => {
                self.advance();
            }
            _ => { break }
        }
    }
}

fn parse<V: Visitor>(&mut self, visitor: &mut V) -> bool {
    loop {
        if self.eos() { return true }
        match self.ch().unwrap() {
            // ignore whitespace
            '\r' | '\n' | ' ' | '\t' => {
                self.advance();
            }

            // comment
            '#' => {
                // skip to end of line
                loop {
                    self.advance();
                    match self.ch() {
                        Some('\n') => { break }
                        None => { return true }
                        _ => { /* skip */ }
                    }
                }
                self.advance();
            }

            // section
            '[' => {
                self.advance();
                let mut double_section = false;
                match self.ch() {
                    Some('[') => {
                        double_section = true;
                        self.advance();
                    }
                    _ => {}
                }

                let section_name = self.parse_section_identifier();

                if !self.advance_if(']') { return false }
                if double_section {
                    if !self.advance_if(']') { return false }
                }

                visitor.section(section_name, double_section);
            }

            // identifier
            'a' .. 'z' | 'A' .. 'Z' | '_' => {

                let ident = self.read_token(|ch| {
                    match ch {
                        'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '_' => true,
                        _ => false
                    }
                });

                self.skip_whitespaces();

                if !self.advance_if('=') { return false } // assign wanted

                match self.parse_value() {
                    Some(val) => { visitor.pair(ident, val); }
                    None => { return false; }
                }
                // do not advance!
            }

            _ => { return false }
        } /* end match */
    }

    assert!(false);
}
}

fn main() {
  let contents = File::open(&Path::new(std::os::args()[1])).read_to_end();
  let mut visitor = TOMLVisitor::new();
  let mut rd = MemReader::new(contents);
  let mut parser = Parser::new(&mut rd);
  parser.parse(&mut visitor);
  println!("{:s}", visitor.get_root().to_str());
}
<|endoftext|>