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

use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::BlobBinding::BlobMethods;
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::Bindings::FileReaderBinding::{self, FileReaderConstants, FileReaderMethods};
use dom::bindings::error::{Error, ErrorResult, Fallible};
use dom::bindings::global::{GlobalField, GlobalRef};
use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, MutNullableHeap, Root};
use dom::bindings::refcounted::Trusted;
use dom::bindings::reflector::{Reflectable, reflect_dom_object};
use dom::blob::Blob;
use dom::domexception::{DOMErrorName, DOMException};
use dom::event::{Event, EventBubbles, EventCancelable};
use dom::eventtarget::EventTarget;
use dom::progressevent::ProgressEvent;
use encoding::all::UTF_8;
use encoding::label::encoding_from_whatwg_label;
use encoding::types::{DecoderTrap, EncodingRef};
use hyper::mime::{Attr, Mime};
use rustc_serialize::base64::{CharacterSet, Config, Newline, ToBase64};
use script_task::ScriptTaskEventCategory::FileRead;
use script_task::{CommonScriptMsg, Runnable, ScriptChan, ScriptPort};
use std::cell::Cell;
use std::sync::mpsc;
use std::sync::mpsc::Receiver;
use util::str::DOMString;
use util::task::spawn_named;

#[derive(PartialEq, Clone, Copy, JSTraceable, HeapSizeOf)]
pub enum FileReaderFunction {
    ReadAsText,
    ReadAsDataUrl,
}

pub type TrustedFileReader = Trusted<FileReader>;

#[derive(Clone, HeapSizeOf)]
pub struct ReadMetaData {
    pub blobtype: DOMString,
    pub label: Option<DOMString>,
    pub function: FileReaderFunction
}

impl ReadMetaData {
    pub fn new(blobtype: DOMString,
               label: Option<DOMString>, function: FileReaderFunction) -> ReadMetaData {
        ReadMetaData {
            blobtype: blobtype,
            label: label,
            function: function,
        }
    }
}

#[derive(PartialEq, Clone, Copy, JSTraceable, HeapSizeOf)]
pub struct GenerationId(u32);

#[repr(u16)]
#[derive(Copy, Clone, Debug, PartialEq, JSTraceable, HeapSizeOf)]
pub enum FileReaderReadyState {
    Empty = FileReaderConstants::EMPTY,
    Loading = FileReaderConstants::LOADING,
    Done = FileReaderConstants::DONE,
}

#[dom_struct]
pub struct FileReader {
    eventtarget: EventTarget,
    global: GlobalField,
    ready_state: Cell<FileReaderReadyState>,
    error: MutNullableHeap<JS<DOMException>>,
    result: DOMRefCell<Option<DOMString>>,
    generation_id: Cell<GenerationId>,
}

impl FileReader {
    pub fn new_inherited(global: GlobalRef) -> FileReader {
        FileReader {
            eventtarget: EventTarget::new_inherited(),//?
            global: GlobalField::from_rooted(&global),
            ready_state: Cell::new(FileReaderReadyState::Empty),
            error: MutNullableHeap::new(None),
            result: DOMRefCell::new(None),
            generation_id: Cell::new(GenerationId(0)),
        }
    }

    pub fn new(global: GlobalRef) -> Root<FileReader> {
        reflect_dom_object(box FileReader::new_inherited(global),
                           global, FileReaderBinding::Wrap)
    }

    pub fn Constructor(global: GlobalRef) -> Fallible<Root<FileReader>> {
        Ok(FileReader::new(global))
    }

    //https://w3c.github.io/FileAPI/#dfn-error-steps
    pub fn process_read_error(filereader: TrustedFileReader, gen_id: GenerationId, error: DOMErrorName) {
        let fr = filereader.root();

        macro_rules! return_on_abort(
            () => (
                if gen_id != fr.generation_id.get() {
                    return
                }
            );
        );

        return_on_abort!();
        // Step 1
        fr.change_ready_state(FileReaderReadyState::Done);
        *fr.result.borrow_mut() = None;

        let global = fr.global.root();
        let exception = DOMException::new(global.r(), error);
        fr.error.set(Some(&exception));

        fr.dispatch_progress_event("error".to_owned(), 0, None);
        return_on_abort!();
        // Step 3
        fr.dispatch_progress_event("loadend".to_owned(), 0, None);
        return_on_abort!();
        // Step 4
        fr.terminate_ongoing_reading();
    }

    // https://w3c.github.io/FileAPI/#dfn-readAsText
    pub fn process_read_data(filereader: TrustedFileReader, gen_id: GenerationId) {
        let fr = filereader.root();

        macro_rules! return_on_abort(
            () => (
                if gen_id != fr.generation_id.get() {
                    return
                }
            );
        );
        return_on_abort!();
        //FIXME Step 7 send current progress
        fr.dispatch_progress_event("progress".to_owned(), 0, None);
    }

    // https://w3c.github.io/FileAPI/#dfn-readAsText
    pub fn process_read(filereader: TrustedFileReader, gen_id: GenerationId) {
        let fr = filereader.root();

        macro_rules! return_on_abort(
            () => (
                if gen_id != fr.generation_id.get() {
                    return
                }
            );
        );
        return_on_abort!();
        // Step 6
        fr.dispatch_progress_event("loadstart".to_owned(), 0, None);
    }

    // https://w3c.github.io/FileAPI/#dfn-readAsText
    pub fn process_read_eof(filereader: TrustedFileReader, gen_id: GenerationId,
                            data: ReadMetaData, blob_contents: Vec<u8>) {
        let fr = filereader.root();

        macro_rules! return_on_abort(
            () => (
                if gen_id != fr.generation_id.get() {
                    return
                }
            );
        );

        return_on_abort!();
        // Step 8.1
        fr.change_ready_state(FileReaderReadyState::Done);
        // Step 8.2
        let output = match data.function {
            FileReaderFunction::ReadAsDataUrl =>
                FileReader::perform_readasdataurl(data, blob_contents),
            FileReaderFunction::ReadAsText =>
                FileReader::perform_readastext(data, blob_contents),
        };

        *fr.result.borrow_mut() = Some(output);

        // Step 8.3
        fr.dispatch_progress_event("load".to_owned(), 0, None);
        return_on_abort!();
        // Step 8.4
        if fr.ready_state.get() != FileReaderReadyState::Loading {
            fr.dispatch_progress_event("loadend".to_owned(), 0, None);
        }
        return_on_abort!();
        // Step 9
        fr.terminate_ongoing_reading();
    }

    // https://w3c.github.io/FileAPI/#dfn-readAsText
    fn perform_readastext(data: ReadMetaData, blob_contents: Vec<u8>)
        -> DOMString {

        let blob_label = &data.label;
        let blob_type = &data.blobtype;
        let blob_bytes = &blob_contents[..];

        //https://w3c.github.io/FileAPI/#encoding-determination
        // Steps 1 & 2 & 3
        let mut encoding = blob_label.as_ref()
            .map(|string| &**string)
            .and_then(encoding_from_whatwg_label);

        // Step 4 & 5
        encoding = encoding.or_else(|| {
            let resultmime = blob_type.parse::<Mime>().ok();
            resultmime.and_then(|Mime(_, _, ref parameters)| {
                parameters.iter()
                    .find(|&&(ref k, _)| &Attr::Charset == k)
                    .and_then(|&(_, ref v)| encoding_from_whatwg_label(&v.to_string()))
            })
        });

        // Step 6
        let enc = encoding.unwrap_or(UTF_8 as EncodingRef);

        let convert = blob_bytes;
        // Step 7
        let output = enc.decode(convert, DecoderTrap::Replace).unwrap();
        DOMString(output)
    }

    //https://w3c.github.io/FileAPI/#dfn-readAsDataURL
    fn perform_readasdataurl(data: ReadMetaData, blob_contents: Vec<u8>)
        -> DOMString {
        let config = Config {
            char_set: CharacterSet::UrlSafe,
            newline: Newline::LF,
            pad: true,
            line_length: None
        };
        let base64 = blob_contents.to_base64(config);

        let output = if data.blobtype.is_empty() {
            format!("data:base64,{}", base64)
        } else {
            format!("data:{};base64,{}", data.blobtype, base64)
        };

        DOMString(output)
    }
}

impl FileReaderMethods for FileReader {
    // https://w3c.github.io/FileAPI/#dfn-onloadstart
    event_handler!(loadstart, GetOnloadstart, SetOnloadstart);

    // https://w3c.github.io/FileAPI/#dfn-onprogress
    event_handler!(progress, GetOnprogress, SetOnprogress);

    // https://w3c.github.io/FileAPI/#dfn-onload
    event_handler!(load, GetOnload, SetOnload);

    // https://w3c.github.io/FileAPI/#dfn-onabort
    event_handler!(abort, GetOnabort, SetOnabort);

    // https://w3c.github.io/FileAPI/#dfn-onerror
    event_handler!(error, GetOnerror, SetOnerror);

    // https://w3c.github.io/FileAPI/#dfn-onloadend
    event_handler!(loadend, GetOnloadend, SetOnloadend);

    //TODO https://w3c.github.io/FileAPI/#dfn-readAsArrayBuffer
    // https://w3c.github.io/FileAPI/#dfn-readAsDataURL
    fn ReadAsDataURL(&self, blob: &Blob) -> ErrorResult {
        self.read(FileReaderFunction::ReadAsDataUrl, blob, None)
    }

    // https://w3c.github.io/FileAPI/#dfn-readAsText
    fn ReadAsText(&self, blob: &Blob, label: Option<DOMString>) -> ErrorResult {
        self.read(FileReaderFunction::ReadAsText, blob, label)
    }

    // https://w3c.github.io/FileAPI/#dfn-abort
    fn Abort(&self) {
        // Step 2
        if self.ready_state.get() == FileReaderReadyState::Loading {
            self.change_ready_state(FileReaderReadyState::Done);
        }
        // Steps 1 & 3
        *self.result.borrow_mut() = None;

        let global = self.global.root();
        let exception = DOMException::new(global.r(), DOMErrorName::AbortError);
        self.error.set(Some(&exception));

        self.terminate_ongoing_reading();
        // Steps 5 & 6
        self.dispatch_progress_event("abort".to_owned(), 0, None);
        self.dispatch_progress_event("loadend".to_owned(), 0, None);
    }

    // https://w3c.github.io/FileAPI/#dfn-error
    fn GetError(&self) -> Option<Root<DOMException>> {
        self.error.get()
    }

    // https://w3c.github.io/FileAPI/#dfn-result
    fn GetResult(&self) -> Option<DOMString> {
        self.result.borrow().clone()
    }

    // https://w3c.github.io/FileAPI/#dfn-readyState
    fn ReadyState(&self) -> u16 {
        self.ready_state.get() as u16
    }
}

impl FileReader {
    fn dispatch_progress_event(&self, type_: String, loaded: u64, total: Option<u64>) {

        let global = self.global.root();
        let progressevent = ProgressEvent::new(global.r(),
            DOMString(type_), EventBubbles::DoesNotBubble, EventCancelable::NotCancelable,
            total.is_some(), loaded, total.unwrap_or(0));
        progressevent.upcast::<Event>().fire(self.upcast());
    }

    fn terminate_ongoing_reading(&self) {
        let GenerationId(prev_id) = self.generation_id.get();
        self.generation_id.set(GenerationId(prev_id + 1));
    }

    fn read(&self, function: FileReaderFunction, blob: &Blob, label: Option<DOMString>) -> ErrorResult {
        let root = self.global.root();
        let global = root.r();
        // Step 1
        if self.ready_state.get() == FileReaderReadyState::Loading {
            return Err(Error::InvalidState);
        }
        // Step 2
        if blob.IsClosed() {
            let global = self.global.root();
            let exception = DOMException::new(global.r(), DOMErrorName::InvalidStateError);
            self.error.set(Some(&exception));

            self.dispatch_progress_event("error".to_owned(), 0, None);
            return Ok(());
        }

        // Step 3
        self.change_ready_state(FileReaderReadyState::Loading);

        // Step 4
        let (send, bytes) = mpsc::channel();
        blob.read_out_buffer(send);
        let type_ = blob.Type();

        let load_data = ReadMetaData::new(type_, label, function);

        let fr = Trusted::new(global.get_cx(), self, global.script_chan());
        let gen_id = self.generation_id.get();

        let script_chan = global.script_chan();

        spawn_named("file reader async operation".to_owned(), move || {
            perform_annotated_read_operation(gen_id, load_data, bytes, fr, script_chan)
        });
        Ok(())
    }

    fn change_ready_state(&self, state: FileReaderReadyState) {
        self.ready_state.set(state);
    }
}

#[derive(Clone)]
pub enum FileReaderEvent {
    ProcessRead(TrustedFileReader, GenerationId),
    ProcessReadData(TrustedFileReader, GenerationId, DOMString),
    ProcessReadError(TrustedFileReader, GenerationId, DOMErrorName),
    ProcessReadEOF(TrustedFileReader, GenerationId, ReadMetaData, Vec<u8>)
}

impl Runnable for FileReaderEvent {
    fn handler(self: Box<FileReaderEvent>) {
        let file_reader_event = *self;
        match file_reader_event {
            FileReaderEvent::ProcessRead(filereader, gen_id) => {
                FileReader::process_read(filereader, gen_id);
            },
            FileReaderEvent::ProcessReadData(filereader, gen_id, _) => {
                FileReader::process_read_data(filereader, gen_id);
            },
            FileReaderEvent::ProcessReadError(filereader, gen_id, error) => {
                FileReader::process_read_error(filereader, gen_id, error);
            },
            FileReaderEvent::ProcessReadEOF(filereader, gen_id, data, blob_contents) => {
                FileReader::process_read_eof(filereader, gen_id, data, blob_contents);
            }
        }
    }
}

// https://w3c.github.io/FileAPI/#task-read-operation
fn perform_annotated_read_operation(gen_id: GenerationId, data: ReadMetaData, blob_contents: Receiver<Vec<u8>>,
    filereader: TrustedFileReader, script_chan: Box<ScriptChan + Send>) {
    let chan = &script_chan;
    // Step 4
    let task = box FileReaderEvent::ProcessRead(filereader.clone(), gen_id);
    chan.send(CommonScriptMsg::RunnableMsg(FileRead, task)).unwrap();

    let task = box FileReaderEvent::ProcessReadData(filereader.clone(),
        gen_id, DOMString::new());
    chan.send(CommonScriptMsg::RunnableMsg(FileRead, task)).unwrap();

    let bytes = match blob_contents.recv() {
        Ok(bytes) => bytes,
        Err(_) => {
            let task = box FileReaderEvent::ProcessReadError(filereader,
                gen_id, DOMErrorName::NotFoundError);
            chan.send(CommonScriptMsg::RunnableMsg(FileRead, task)).unwrap();
            return;
        }
    };

    let task = box FileReaderEvent::ProcessReadEOF(filereader, gen_id, data, bytes);
    chan.send(CommonScriptMsg::RunnableMsg(FileRead, task)).unwrap();
}
<commit_msg>Replaced DOMString by String in filereader.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::BlobBinding::BlobMethods;
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::Bindings::FileReaderBinding::{self, FileReaderConstants, FileReaderMethods};
use dom::bindings::error::{Error, ErrorResult, Fallible};
use dom::bindings::global::{GlobalField, GlobalRef};
use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, MutNullableHeap, Root};
use dom::bindings::refcounted::Trusted;
use dom::bindings::reflector::{Reflectable, reflect_dom_object};
use dom::blob::Blob;
use dom::domexception::{DOMErrorName, DOMException};
use dom::event::{Event, EventBubbles, EventCancelable};
use dom::eventtarget::EventTarget;
use dom::progressevent::ProgressEvent;
use encoding::all::UTF_8;
use encoding::label::encoding_from_whatwg_label;
use encoding::types::{DecoderTrap, EncodingRef};
use hyper::mime::{Attr, Mime};
use rustc_serialize::base64::{CharacterSet, Config, Newline, ToBase64};
use script_task::ScriptTaskEventCategory::FileRead;
use script_task::{CommonScriptMsg, Runnable, ScriptChan, ScriptPort};
use std::cell::Cell;
use std::sync::mpsc;
use std::sync::mpsc::Receiver;
use util::str::DOMString;
use util::task::spawn_named;

#[derive(PartialEq, Clone, Copy, JSTraceable, HeapSizeOf)]
pub enum FileReaderFunction {
    ReadAsText,
    ReadAsDataUrl,
}

pub type TrustedFileReader = Trusted<FileReader>;

#[derive(Clone, HeapSizeOf)]
pub struct ReadMetaData {
    pub blobtype: String,
    pub label: Option<String>,
    pub function: FileReaderFunction
}

impl ReadMetaData {
    pub fn new(blobtype: String,
               label: Option<String>, function: FileReaderFunction) -> ReadMetaData {
        ReadMetaData {
            blobtype: blobtype,
            label: label,
            function: function,
        }
    }
}

#[derive(PartialEq, Clone, Copy, JSTraceable, HeapSizeOf)]
pub struct GenerationId(u32);

#[repr(u16)]
#[derive(Copy, Clone, Debug, PartialEq, JSTraceable, HeapSizeOf)]
pub enum FileReaderReadyState {
    Empty = FileReaderConstants::EMPTY,
    Loading = FileReaderConstants::LOADING,
    Done = FileReaderConstants::DONE,
}

#[dom_struct]
pub struct FileReader {
    eventtarget: EventTarget,
    global: GlobalField,
    ready_state: Cell<FileReaderReadyState>,
    error: MutNullableHeap<JS<DOMException>>,
    result: DOMRefCell<Option<DOMString>>,
    generation_id: Cell<GenerationId>,
}

impl FileReader {
    pub fn new_inherited(global: GlobalRef) -> FileReader {
        FileReader {
            eventtarget: EventTarget::new_inherited(),//?
            global: GlobalField::from_rooted(&global),
            ready_state: Cell::new(FileReaderReadyState::Empty),
            error: MutNullableHeap::new(None),
            result: DOMRefCell::new(None),
            generation_id: Cell::new(GenerationId(0)),
        }
    }

    pub fn new(global: GlobalRef) -> Root<FileReader> {
        reflect_dom_object(box FileReader::new_inherited(global),
                           global, FileReaderBinding::Wrap)
    }

    pub fn Constructor(global: GlobalRef) -> Fallible<Root<FileReader>> {
        Ok(FileReader::new(global))
    }

    //https://w3c.github.io/FileAPI/#dfn-error-steps
    pub fn process_read_error(filereader: TrustedFileReader, gen_id: GenerationId, error: DOMErrorName) {
        let fr = filereader.root();

        macro_rules! return_on_abort(
            () => (
                if gen_id != fr.generation_id.get() {
                    return
                }
            );
        );

        return_on_abort!();
        // Step 1
        fr.change_ready_state(FileReaderReadyState::Done);
        *fr.result.borrow_mut() = None;

        let global = fr.global.root();
        let exception = DOMException::new(global.r(), error);
        fr.error.set(Some(&exception));

        fr.dispatch_progress_event("error".to_owned(), 0, None);
        return_on_abort!();
        // Step 3
        fr.dispatch_progress_event("loadend".to_owned(), 0, None);
        return_on_abort!();
        // Step 4
        fr.terminate_ongoing_reading();
    }

    // https://w3c.github.io/FileAPI/#dfn-readAsText
    pub fn process_read_data(filereader: TrustedFileReader, gen_id: GenerationId) {
        let fr = filereader.root();

        macro_rules! return_on_abort(
            () => (
                if gen_id != fr.generation_id.get() {
                    return
                }
            );
        );
        return_on_abort!();
        //FIXME Step 7 send current progress
        fr.dispatch_progress_event("progress".to_owned(), 0, None);
    }

    // https://w3c.github.io/FileAPI/#dfn-readAsText
    pub fn process_read(filereader: TrustedFileReader, gen_id: GenerationId) {
        let fr = filereader.root();

        macro_rules! return_on_abort(
            () => (
                if gen_id != fr.generation_id.get() {
                    return
                }
            );
        );
        return_on_abort!();
        // Step 6
        fr.dispatch_progress_event("loadstart".to_owned(), 0, None);
    }

    // https://w3c.github.io/FileAPI/#dfn-readAsText
    pub fn process_read_eof(filereader: TrustedFileReader, gen_id: GenerationId,
                            data: ReadMetaData, blob_contents: Vec<u8>) {
        let fr = filereader.root();

        macro_rules! return_on_abort(
            () => (
                if gen_id != fr.generation_id.get() {
                    return
                }
            );
        );

        return_on_abort!();
        // Step 8.1
        fr.change_ready_state(FileReaderReadyState::Done);
        // Step 8.2
        let output = match data.function {
            FileReaderFunction::ReadAsDataUrl =>
                FileReader::perform_readasdataurl(data, blob_contents),
            FileReaderFunction::ReadAsText =>
                FileReader::perform_readastext(data, blob_contents),
        };

        *fr.result.borrow_mut() = Some(output);

        // Step 8.3
        fr.dispatch_progress_event("load".to_owned(), 0, None);
        return_on_abort!();
        // Step 8.4
        if fr.ready_state.get() != FileReaderReadyState::Loading {
            fr.dispatch_progress_event("loadend".to_owned(), 0, None);
        }
        return_on_abort!();
        // Step 9
        fr.terminate_ongoing_reading();
    }

    // https://w3c.github.io/FileAPI/#dfn-readAsText
    fn perform_readastext(data: ReadMetaData, blob_contents: Vec<u8>)
        -> DOMString {

        let blob_label = &data.label;
        let blob_type = &data.blobtype;
        let blob_bytes = &blob_contents[..];

        //https://w3c.github.io/FileAPI/#encoding-determination
        // Steps 1 & 2 & 3
        let mut encoding = blob_label.as_ref()
            .map(|string| &**string)
            .and_then(encoding_from_whatwg_label);

        // Step 4 & 5
        encoding = encoding.or_else(|| {
            let resultmime = blob_type.parse::<Mime>().ok();
            resultmime.and_then(|Mime(_, _, ref parameters)| {
                parameters.iter()
                    .find(|&&(ref k, _)| &Attr::Charset == k)
                    .and_then(|&(_, ref v)| encoding_from_whatwg_label(&v.to_string()))
            })
        });

        // Step 6
        let enc = encoding.unwrap_or(UTF_8 as EncodingRef);

        let convert = blob_bytes;
        // Step 7
        let output = enc.decode(convert, DecoderTrap::Replace).unwrap();
        DOMString(output)
    }

    //https://w3c.github.io/FileAPI/#dfn-readAsDataURL
    fn perform_readasdataurl(data: ReadMetaData, blob_contents: Vec<u8>)
        -> DOMString {
        let config = Config {
            char_set: CharacterSet::UrlSafe,
            newline: Newline::LF,
            pad: true,
            line_length: None
        };
        let base64 = blob_contents.to_base64(config);

        let output = if data.blobtype.is_empty() {
            format!("data:base64,{}", base64)
        } else {
            format!("data:{};base64,{}", data.blobtype, base64)
        };

        DOMString(output)
    }
}

impl FileReaderMethods for FileReader {
    // https://w3c.github.io/FileAPI/#dfn-onloadstart
    event_handler!(loadstart, GetOnloadstart, SetOnloadstart);

    // https://w3c.github.io/FileAPI/#dfn-onprogress
    event_handler!(progress, GetOnprogress, SetOnprogress);

    // https://w3c.github.io/FileAPI/#dfn-onload
    event_handler!(load, GetOnload, SetOnload);

    // https://w3c.github.io/FileAPI/#dfn-onabort
    event_handler!(abort, GetOnabort, SetOnabort);

    // https://w3c.github.io/FileAPI/#dfn-onerror
    event_handler!(error, GetOnerror, SetOnerror);

    // https://w3c.github.io/FileAPI/#dfn-onloadend
    event_handler!(loadend, GetOnloadend, SetOnloadend);

    //TODO https://w3c.github.io/FileAPI/#dfn-readAsArrayBuffer
    // https://w3c.github.io/FileAPI/#dfn-readAsDataURL
    fn ReadAsDataURL(&self, blob: &Blob) -> ErrorResult {
        self.read(FileReaderFunction::ReadAsDataUrl, blob, None)
    }

    // https://w3c.github.io/FileAPI/#dfn-readAsText
    fn ReadAsText(&self, blob: &Blob, label: Option<DOMString>) -> ErrorResult {
        self.read(FileReaderFunction::ReadAsText, blob, label)
    }

    // https://w3c.github.io/FileAPI/#dfn-abort
    fn Abort(&self) {
        // Step 2
        if self.ready_state.get() == FileReaderReadyState::Loading {
            self.change_ready_state(FileReaderReadyState::Done);
        }
        // Steps 1 & 3
        *self.result.borrow_mut() = None;

        let global = self.global.root();
        let exception = DOMException::new(global.r(), DOMErrorName::AbortError);
        self.error.set(Some(&exception));

        self.terminate_ongoing_reading();
        // Steps 5 & 6
        self.dispatch_progress_event("abort".to_owned(), 0, None);
        self.dispatch_progress_event("loadend".to_owned(), 0, None);
    }

    // https://w3c.github.io/FileAPI/#dfn-error
    fn GetError(&self) -> Option<Root<DOMException>> {
        self.error.get()
    }

    // https://w3c.github.io/FileAPI/#dfn-result
    fn GetResult(&self) -> Option<DOMString> {
        self.result.borrow().clone()
    }

    // https://w3c.github.io/FileAPI/#dfn-readyState
    fn ReadyState(&self) -> u16 {
        self.ready_state.get() as u16
    }
}

impl FileReader {
    fn dispatch_progress_event(&self, type_: String, loaded: u64, total: Option<u64>) {

        let global = self.global.root();
        let progressevent = ProgressEvent::new(global.r(),
            DOMString(type_), EventBubbles::DoesNotBubble, EventCancelable::NotCancelable,
            total.is_some(), loaded, total.unwrap_or(0));
        progressevent.upcast::<Event>().fire(self.upcast());
    }

    fn terminate_ongoing_reading(&self) {
        let GenerationId(prev_id) = self.generation_id.get();
        self.generation_id.set(GenerationId(prev_id + 1));
    }

    fn read(&self, function: FileReaderFunction, blob: &Blob, label: Option<DOMString>) -> ErrorResult {
        let root = self.global.root();
        let global = root.r();
        // Step 1
        if self.ready_state.get() == FileReaderReadyState::Loading {
            return Err(Error::InvalidState);
        }
        // Step 2
        if blob.IsClosed() {
            let global = self.global.root();
            let exception = DOMException::new(global.r(), DOMErrorName::InvalidStateError);
            self.error.set(Some(&exception));

            self.dispatch_progress_event("error".to_owned(), 0, None);
            return Ok(());
        }

        // Step 3
        self.change_ready_state(FileReaderReadyState::Loading);

        // Step 4
        let (send, bytes) = mpsc::channel();
        blob.read_out_buffer(send);
        let type_ = blob.Type();

        let load_data = ReadMetaData::new(String::from(type_), label.map(String::from), function);

        let fr = Trusted::new(global.get_cx(), self, global.script_chan());
        let gen_id = self.generation_id.get();

        let script_chan = global.script_chan();

        spawn_named("file reader async operation".to_owned(), move || {
            perform_annotated_read_operation(gen_id, load_data, bytes, fr, script_chan)
        });
        Ok(())
    }

    fn change_ready_state(&self, state: FileReaderReadyState) {
        self.ready_state.set(state);
    }
}

#[derive(Clone)]
pub enum FileReaderEvent {
    ProcessRead(TrustedFileReader, GenerationId),
    ProcessReadData(TrustedFileReader, GenerationId),
    ProcessReadError(TrustedFileReader, GenerationId, DOMErrorName),
    ProcessReadEOF(TrustedFileReader, GenerationId, ReadMetaData, Vec<u8>)
}

impl Runnable for FileReaderEvent {
    fn handler(self: Box<FileReaderEvent>) {
        let file_reader_event = *self;
        match file_reader_event {
            FileReaderEvent::ProcessRead(filereader, gen_id) => {
                FileReader::process_read(filereader, gen_id);
            },
            FileReaderEvent::ProcessReadData(filereader, gen_id) => {
                FileReader::process_read_data(filereader, gen_id);
            },
            FileReaderEvent::ProcessReadError(filereader, gen_id, error) => {
                FileReader::process_read_error(filereader, gen_id, error);
            },
            FileReaderEvent::ProcessReadEOF(filereader, gen_id, data, blob_contents) => {
                FileReader::process_read_eof(filereader, gen_id, data, blob_contents);
            }
        }
    }
}

// https://w3c.github.io/FileAPI/#task-read-operation
fn perform_annotated_read_operation(gen_id: GenerationId, data: ReadMetaData, blob_contents: Receiver<Vec<u8>>,
    filereader: TrustedFileReader, script_chan: Box<ScriptChan + Send>) {
    let chan = &script_chan;
    // Step 4
    let task = box FileReaderEvent::ProcessRead(filereader.clone(), gen_id);
    chan.send(CommonScriptMsg::RunnableMsg(FileRead, task)).unwrap();

    let task = box FileReaderEvent::ProcessReadData(filereader.clone(), gen_id);
    chan.send(CommonScriptMsg::RunnableMsg(FileRead, task)).unwrap();

    let bytes = match blob_contents.recv() {
        Ok(bytes) => bytes,
        Err(_) => {
            let task = box FileReaderEvent::ProcessReadError(filereader,
                gen_id, DOMErrorName::NotFoundError);
            chan.send(CommonScriptMsg::RunnableMsg(FileRead, task)).unwrap();
            return;
        }
    };

    let task = box FileReaderEvent::ProcessReadEOF(filereader, gen_id, data, bytes);
    chan.send(CommonScriptMsg::RunnableMsg(FileRead, task)).unwrap();
}
<|endoftext|>


<commit_before>use std::{vec, iterator};
use std::ascii::to_ascii_lower;
use cssparser::*;
use stylesheets::NamespaceMap;

pub struct Selector {
    compound_selectors: CompoundSelector,
    pseudo_element: Option<PseudoElement>,
//    specificity: u32,
}

pub enum PseudoElement {
    Before,
    After,
    FirstLine,
    FirstLetter,
}

pub struct CompoundSelector {
    simple_selectors: ~[SimpleSelector],
    next: Option<(~CompoundSelector, Combinator)>,  // c.next is left of c
}

pub enum Combinator {
    Child,  //  >
    Descendant,  // space
    NextSibling,  // +
    LaterSibling,  // ~
}

pub enum SimpleSelector {
    IDSelector(~str),
    ClassSelector(~str),
    LocalNameSelector{lowercase_name: ~str, cased_name: ~str},
    NamespaceSelector(~str),

    // Attribute selectors
    AttrExists(AttrSelector),  // [foo]
    AttrEqual(AttrSelector, ~str),  // [foo=bar]
    AttrIncludes(AttrSelector, ~str),  // [foo~=bar]
    AttrDashMatch(AttrSelector, ~str),  // [foo|=bar]
    AttrPrefixMatch(AttrSelector, ~str),  // [foo^=bar]
    AttrSubstringMatch(AttrSelector, ~str),  // [foo*=bar]
    AttrSuffixMatch(AttrSelector, ~str),  // [foo$=bar]

    // Pseudo-classes
    Empty,
    Root,
    Lang(~str),
//    NthChild(u32, u32),
//    NthLastChild(u32, u32),
//    NthOfType(u32, u32),
//    NthLastOfType(u32, u32),
    Negation(~[SimpleSelector]),
    // ...
}

pub struct AttrSelector {
    lowercase_name: ~str,
    cased_name: ~str,
    namespace: Option<~str>,
}

type Iter = iterator::PeekableIterator<ComponentValue, vec::ConsumeIterator<ComponentValue>>;

// None means invalid selector
pub fn parse_selector_list(input: ~[ComponentValue], namespaces: &NamespaceMap)
                           -> Option<~[Selector]> {
    let iter = &mut input.consume_iter().peekable();
    let first = match parse_selector(iter, namespaces) {
        None => return None,
        Some(result) => result
    };
    let mut results = ~[first];

    loop {
        skip_whitespace(iter);
        match iter.peek() {
            None => break,  // EOF
            Some(&Comma) => (),
            _ => return None,
        }
        match parse_selector(iter, namespaces) {
            Some(selector) => results.push(selector),
            None => return None,
        }
    }
    Some(results)
}

// None means invalid selector
fn parse_selector(iter: &mut Iter, namespaces: &NamespaceMap)
                  -> Option<Selector> {
    let (first, pseudo_element) = match parse_simple_selectors(iter, namespaces) {
        None => return None,
        Some(result) => result
    };
    let mut compound = CompoundSelector{ simple_selectors: first, next: None };
    let mut pseudo_element = pseudo_element;

    while pseudo_element.is_none() {
        let any_whitespace = skip_whitespace(iter);
        let combinator = match iter.peek() {
            None => break,  // EOF
            Some(&Delim('>')) => { iter.next(); Child },
            Some(&Delim('+')) => { iter.next(); NextSibling },
            Some(&Delim('~')) => { iter.next(); LaterSibling },
            Some(_) => {
                if any_whitespace { Descendant }
                else { return None }
            }
        };
        match parse_simple_selectors(iter, namespaces) {
            None => return None,
            Some((simple_selectors, pseudo)) => {
                compound = CompoundSelector {
                    simple_selectors: simple_selectors,
                    next: Some((~compound, combinator))
                };
                pseudo_element = pseudo;
            }
        }
    }
    let selector = Selector{
        compound_selectors: compound,
        pseudo_element: pseudo_element,
    };
    Some(selector)
}

// None means invalid selector
fn parse_simple_selectors(iter: &mut Iter, namespaces: &NamespaceMap)
                           -> Option<(~[SimpleSelector], Option<PseudoElement>)> {
    let mut empty = true;
    let mut simple_selectors = match parse_type_selector(iter, namespaces) {
        None => return None,  // invalid selector
        Some(None) => ~[],
        Some(Some(s)) => { empty = false; s }
    };

    let mut pseudo_element = None;
    loop {
        match parse_one_simple_selector(iter, namespaces, /* inside_negation = */ false) {
            None => return None, // invalid selector
            Some(None) => break,
            Some(Some(Left(s))) => simple_selectors.push(s),
            Some(Some(Right(p))) => { pseudo_element = Some(p); break },
        }
    }
    if empty { None }  // An empty selector is invalid
    else { Some((simple_selectors, pseudo_element)) }
}

// None means invalid selector
// Some(None) means no type selector
// Some(Some([...])) is a type selector. Might be empty for *|*
fn parse_type_selector(iter: &mut Iter, namespaces: &NamespaceMap)
                       -> Option<Option<~[SimpleSelector]>> {
    skip_whitespace(iter);
    match parse_qualified_name(iter, /* allow_universal = */ true, namespaces) {
        None => None,  // invalid selector
        Some(None) => Some(None),
        Some(Some((namespace, local_name))) => {
            let mut simple_selectors = ~[];
            match namespace {
                Some(url) => simple_selectors.push(NamespaceSelector(url)),
                None => (),
            }
            match local_name {
                Some(name) => simple_selectors.push(LocalNameSelector{
                    lowercase_name: to_ascii_lower(name),
                    cased_name: name,
                }),
                None => (),
            }
            Some(Some(simple_selectors))
        }
    }
}

// Parse a simple selector other than a type selector
fn parse_one_simple_selector(iter: &mut Iter, namespaces: &NamespaceMap, inside_negation: bool)
                         -> Option<Option<Either<SimpleSelector, PseudoElement>>> {
    match iter.peek() {
        Some(&IDHash(_)) => match iter.next() {
            Some(IDHash(id)) => Some(Some(Left(IDSelector(id)))),
            _ => fail!("Implementation error, this should not happen."),
        },
        Some(&Delim('.')) => {
            iter.next();
            match iter.next() {
                Some(Ident(class)) => Some(Some(Left(ClassSelector(class)))),
                _ => None,  // invalid selector
            }
        }
        Some(&SquareBracketBlock(_)) => match iter.next() {
            Some(SquareBracketBlock(content))
            => match parse_attribute_selector(content, namespaces) {
                None => None,
                Some(simple_selector) => Some(Some(Left(simple_selector))),
            },
            _ => fail!("Implementation error, this should not happen."),
        },
        Some(&Delim(':')) => {
            iter.next();
            match iter.next() {
                Some(Ident(name)) => match parse_simple_pseudo_class(name) {
                    None => None,
                    Some(result) => Some(Some(result)),
                },
                Some(Function(name, arguments)) => match parse_functional_pseudo_class(
                        name, arguments, namespaces, inside_negation) {
                    None => None,
                    Some(simple_selector) => Some(Some(Left(simple_selector))),
                },
                Some(Delim(':')) => {
                    match iter.next() {
                        Some(Ident(name)) => match parse_pseudo_element(name) {
                            Some(pseudo_element) => Some(Some(Right(pseudo_element))),
                            _ => None,
                        },
                        _ => None,
                    }
                }
                _ => None,
            }
        }
        _ => Some(None),
    }
}

// None means invalid selector
// Some(None) means not a qualified name
// Some(Some((None, None)) means *|*
// Some(Some((Some(url), None)) means prefix|*
// Some(Some((None, Some(name)) means *|name
// Some(Some((Some(url), Some(name))) means prefix|name
// ... or equivalent
fn parse_qualified_name(iter: &mut Iter, allow_universal: bool, namespaces: &NamespaceMap)
                       -> Option<Option<(Option<~str>, Option<~str>)>> {
    #[inline]
    fn default_namespace(namespaces: &NamespaceMap, local_name: Option<~str>)
                         -> Option<Option<(Option<~str>, Option<~str>)>> {
        match namespaces.default {
            None => Some(Some((None, local_name))),
            Some(ref url) => Some(Some((Some(url.to_owned()), local_name))),
        }
    }

    #[inline]
    fn explicit_namespace(iter: &mut Iter, allow_universal: bool, namespace_url: Option<~str>)
                         -> Option<Option<(Option<~str>, Option<~str>)>> {
        assert!(iter.next() == Some(Delim('|')));
        match iter.peek() {
            Some(&Delim('*')) if allow_universal => {
                iter.next();
                Some(Some((namespace_url, None)))
            },
            Some(&Ident(_)) => {
                let local_name = get_next_ident(iter);
                Some(Some((namespace_url, Some(local_name))))
            },
            _ => None,  // invalid selector
        }
    }

    match iter.peek() {
        Some(&Ident(_)) => {
            let value = get_next_ident(iter);
            match iter.peek() {
                Some(&Delim('|')) => default_namespace(namespaces, Some(value)),
                _ => {
                    let namespace_url = match namespaces.prefix_map.find(&value) {
                        None => return None,  // Undeclared namespace prefix: invalid selector
                        Some(ref url) => url.to_owned(),
                    };
                    explicit_namespace(iter, allow_universal, Some(namespace_url))
                },
            }
        },
        Some(&Delim('*')) => {
            iter.next();  // Consume '*'
            match iter.peek() {
                Some(&Delim('|')) => {
                    if allow_universal { default_namespace(namespaces, None) }
                    else { None }
                },
                _ => explicit_namespace(iter, allow_universal, None),
            }
        },
        Some(&Delim('|')) => explicit_namespace(iter, allow_universal, Some(~"")),
        _ => return None,
    }
}

fn parse_attribute_selector(content: ~[ComponentValue], namespaces: &NamespaceMap)
                            -> Option<SimpleSelector> {
    let iter = &mut content.consume_iter().peekable();
    let attr = match parse_qualified_name(iter, /* allow_universal = */ false, namespaces) {
        None => return None,  // invalid selector
        Some(None) => return None,
        Some(Some((_, None))) => fail!("Implementation error, this should not happen."),
        Some(Some((namespace, Some(local_name)))) => AttrSelector {
            namespace: namespace,
            lowercase_name: to_ascii_lower(local_name),
            cased_name: local_name,
        },
    };
    skip_whitespace(iter);
    macro_rules! get_value( () => {{
        skip_whitespace(iter);
        match iter.next() {
            Some(Ident(value)) | Some(String(value)) => value,
            _ => return None,
        }
    }};)
    let result = match iter.next() {
        None => AttrExists(attr),  // [foo]
        Some(Delim('=')) => AttrEqual(attr, get_value!()),  // [foo=bar]
        Some(IncludeMatch) => AttrIncludes(attr, get_value!()),  // [foo~=bar]
        Some(DashMatch) => AttrDashMatch(attr, get_value!()),  // [foo|=bar]
        Some(PrefixMatch) => AttrPrefixMatch(attr, get_value!()),  // [foo^=bar]
        Some(SubstringMatch) => AttrSubstringMatch(attr, get_value!()),  // [foo*=bar]
        Some(SuffixMatch) => AttrSuffixMatch(attr, get_value!()),  // [foo$=bar]
        _ => return None
    };
    skip_whitespace(iter);
    if iter.next().is_none() { Some(result) } else { None }
}

fn parse_simple_pseudo_class(name: ~str) -> Option<Either<SimpleSelector, PseudoElement>> {
    let lower_name: &str = to_ascii_lower(name);
    match lower_name {
        "root" => Some(Left(Root)),
        "empty" => Some(Left(Empty)),

        // Supported CSS 2.1 pseudo-elements only.
        "before" => Some(Right(Before)),
        "after" => Some(Right(After)),
        "first-line" => Some(Right(FirstLine)),
        "first-letter" => Some(Right(FirstLetter)),
        _ => None
    }
}

fn parse_functional_pseudo_class(name: ~str, arguments: ~[ComponentValue],
                                 namespaces: &NamespaceMap, inside_negation: bool)
                                 -> Option<SimpleSelector> {
    let lower_name: &str = to_ascii_lower(name);
    match lower_name {
        "lang" => parse_lang(arguments),
        "not" => if inside_negation { None } else { parse_negation(arguments, namespaces) },
        _ => None
    }
}

fn parse_pseudo_element(name: ~str) -> Option<PseudoElement> {
    let lower_name: &str = to_ascii_lower(name);
    match lower_name {
        // All supported pseudo-elements
        "before" => Some(Before),
        "after" => Some(After),
        "first-line" => Some(FirstLine),
        "first-letter" => Some(FirstLetter),
        _ => None
    }
}

fn parse_lang(arguments: ~[ComponentValue]) -> Option<SimpleSelector> {
    let mut iter = arguments.consume_skip_whitespace();
    match iter.next() {
        Some(Ident(value)) => {
            if "" == value || iter.next().is_some() { None }
            else { Some(Lang(value)) }
        },
        _ => None,
    }
}

// Level 3: Parse ONE simple_selector
fn parse_negation(arguments: ~[ComponentValue], namespaces: &NamespaceMap)
                  -> Option<SimpleSelector> {
    let iter = &mut arguments.consume_iter().peekable();
    Some(Negation(match parse_type_selector(iter, namespaces) {
        None => return None,  // invalid selector
        Some(Some(s)) => s,
        Some(None) => {
            match parse_one_simple_selector(iter, namespaces, /* inside_negation = */ true) {
                Some(Some(Left(s))) => ~[s],
                _ => return None
            }
        },
    }))
}

/// Assuming the next token is an ident, consume it and return its value
#[inline]
fn get_next_ident(iter: &mut Iter) -> ~str {
    match iter.next() {
        Some(Ident(value)) => value,
        _ => fail!("Implementation error, this should not happen."),
    }
}

#[inline]
fn skip_whitespace(iter: &mut Iter) -> bool {
    let mut any_whitespace = false;
    loop {
        if iter.peek() != Some(&WhiteSpace) { return any_whitespace }
        any_whitespace = true;
        iter.next();
    }
}
<commit_msg>Add selector specificity.<commit_after>use std::{vec, iterator};
use std::ascii::to_ascii_lower;
use cssparser::*;
use stylesheets::NamespaceMap;

pub struct Selector {
    compound_selectors: CompoundSelector,
    pseudo_element: Option<PseudoElement>,
    specificity: u32,
}

pub static STYLE_ATTRIBUTE_SPECIFICITY: u32 = 1 << 31;

pub enum PseudoElement {
    Before,
    After,
    FirstLine,
    FirstLetter,
}

pub struct CompoundSelector {
    simple_selectors: ~[SimpleSelector],
    next: Option<(~CompoundSelector, Combinator)>,  // c.next is left of c
}

pub enum Combinator {
    Child,  //  >
    Descendant,  // space
    NextSibling,  // +
    LaterSibling,  // ~
}

pub enum SimpleSelector {
    IDSelector(~str),
    ClassSelector(~str),
    LocalNameSelector{lowercase_name: ~str, cased_name: ~str},
    NamespaceSelector(~str),

    // Attribute selectors
    AttrExists(AttrSelector),  // [foo]
    AttrEqual(AttrSelector, ~str),  // [foo=bar]
    AttrIncludes(AttrSelector, ~str),  // [foo~=bar]
    AttrDashMatch(AttrSelector, ~str),  // [foo|=bar]
    AttrPrefixMatch(AttrSelector, ~str),  // [foo^=bar]
    AttrSubstringMatch(AttrSelector, ~str),  // [foo*=bar]
    AttrSuffixMatch(AttrSelector, ~str),  // [foo$=bar]

    // Pseudo-classes
    Empty,
    Root,
    Lang(~str),
//    NthChild(u32, u32),
//    NthLastChild(u32, u32),
//    NthOfType(u32, u32),
//    NthLastOfType(u32, u32),
    Negation(~[SimpleSelector]),
    // ...
}

pub struct AttrSelector {
    lowercase_name: ~str,
    cased_name: ~str,
    namespace: Option<~str>,
}

type Iter = iterator::PeekableIterator<ComponentValue, vec::ConsumeIterator<ComponentValue>>;

// None means invalid selector
pub fn parse_selector_list(input: ~[ComponentValue], namespaces: &NamespaceMap)
                           -> Option<~[Selector]> {
    let iter = &mut input.consume_iter().peekable();
    let first = match parse_selector(iter, namespaces) {
        None => return None,
        Some(result) => result
    };
    let mut results = ~[first];

    loop {
        skip_whitespace(iter);
        match iter.peek() {
            None => break,  // EOF
            Some(&Comma) => (),
            _ => return None,
        }
        match parse_selector(iter, namespaces) {
            Some(selector) => results.push(selector),
            None => return None,
        }
    }
    Some(results)
}

// None means invalid selector
fn parse_selector(iter: &mut Iter, namespaces: &NamespaceMap)
                  -> Option<Selector> {
    let (first, pseudo_element) = match parse_simple_selectors(iter, namespaces) {
        None => return None,
        Some(result) => result
    };
    let mut compound = CompoundSelector{ simple_selectors: first, next: None };
    let mut pseudo_element = pseudo_element;

    while pseudo_element.is_none() {
        let any_whitespace = skip_whitespace(iter);
        let combinator = match iter.peek() {
            None => break,  // EOF
            Some(&Delim('>')) => { iter.next(); Child },
            Some(&Delim('+')) => { iter.next(); NextSibling },
            Some(&Delim('~')) => { iter.next(); LaterSibling },
            Some(_) => {
                if any_whitespace { Descendant }
                else { return None }
            }
        };
        match parse_simple_selectors(iter, namespaces) {
            None => return None,
            Some((simple_selectors, pseudo)) => {
                compound = CompoundSelector {
                    simple_selectors: simple_selectors,
                    next: Some((~compound, combinator))
                };
                pseudo_element = pseudo;
            }
        }
    }
    let selector = Selector{
        specificity: compute_specificity(&compound, &pseudo_element),
        compound_selectors: compound,
        pseudo_element: pseudo_element,
    };
    Some(selector)
}

fn compute_specificity(mut selector: &CompoundSelector,
                       pseudo_element: &Option<PseudoElement>) -> u32 {
    struct Specificity {
        id_selectors: u32,
        class_like_selectors: u32,
        element_selectors: u32,
    }
    let mut specificity = Specificity {
        id_selectors: 0,
        class_like_selectors: 0,
        element_selectors: 0,
    };
    if pseudo_element.is_some() { specificity.element_selectors += 1 }

    simple_selectors_specificity(selector.simple_selectors, &mut specificity);
    loop {
        match selector.next {
            None => break,
            Some((ref next_selector, _)) => {
                selector = &**next_selector;
                simple_selectors_specificity(selector.simple_selectors, &mut specificity)
            }
        }
    }

    fn simple_selectors_specificity(simple_selectors: &[SimpleSelector],
                                    specificity: &mut Specificity) {
        for simple_selector in simple_selectors.iter() {
            match simple_selector {
                &LocalNameSelector{_} => specificity.element_selectors += 1,
                &IDSelector(_) => specificity.id_selectors += 1,
                &ClassSelector(_)
                | &AttrExists(_) | &AttrEqual(_, _) | &AttrIncludes(_, _) | &AttrDashMatch(_, _)
                | &AttrPrefixMatch(_, _) | &AttrSubstringMatch(_, _) | &AttrSuffixMatch(_, _)
                | &Empty | &Root | &Lang(_)
                => specificity.class_like_selectors += 1,
                &NamespaceSelector(_) => (),
                &Negation(ref negated)
                => simple_selectors_specificity(negated.as_slice(), specificity),
            }
        }
    }

    static MAX_10BIT: u32 = (1u32 << 10) - 1;
    specificity.id_selectors.min(&MAX_10BIT) << 20
    | specificity.class_like_selectors.min(&MAX_10BIT) << 10
    | specificity.id_selectors.min(&MAX_10BIT)
}

// None means invalid selector
fn parse_simple_selectors(iter: &mut Iter, namespaces: &NamespaceMap)
                           -> Option<(~[SimpleSelector], Option<PseudoElement>)> {
    let mut empty = true;
    let mut simple_selectors = match parse_type_selector(iter, namespaces) {
        None => return None,  // invalid selector
        Some(None) => ~[],
        Some(Some(s)) => { empty = false; s }
    };

    let mut pseudo_element = None;
    loop {
        match parse_one_simple_selector(iter, namespaces, /* inside_negation = */ false) {
            None => return None, // invalid selector
            Some(None) => break,
            Some(Some(Left(s))) => simple_selectors.push(s),
            Some(Some(Right(p))) => { pseudo_element = Some(p); break },
        }
    }
    if empty { None }  // An empty selector is invalid
    else { Some((simple_selectors, pseudo_element)) }
}

// None means invalid selector
// Some(None) means no type selector
// Some(Some([...])) is a type selector. Might be empty for *|*
fn parse_type_selector(iter: &mut Iter, namespaces: &NamespaceMap)
                       -> Option<Option<~[SimpleSelector]>> {
    skip_whitespace(iter);
    match parse_qualified_name(iter, /* allow_universal = */ true, namespaces) {
        None => None,  // invalid selector
        Some(None) => Some(None),
        Some(Some((namespace, local_name))) => {
            let mut simple_selectors = ~[];
            match namespace {
                Some(url) => simple_selectors.push(NamespaceSelector(url)),
                None => (),
            }
            match local_name {
                Some(name) => simple_selectors.push(LocalNameSelector{
                    lowercase_name: to_ascii_lower(name),
                    cased_name: name,
                }),
                None => (),
            }
            Some(Some(simple_selectors))
        }
    }
}

// Parse a simple selector other than a type selector
fn parse_one_simple_selector(iter: &mut Iter, namespaces: &NamespaceMap, inside_negation: bool)
                         -> Option<Option<Either<SimpleSelector, PseudoElement>>> {
    match iter.peek() {
        Some(&IDHash(_)) => match iter.next() {
            Some(IDHash(id)) => Some(Some(Left(IDSelector(id)))),
            _ => fail!("Implementation error, this should not happen."),
        },
        Some(&Delim('.')) => {
            iter.next();
            match iter.next() {
                Some(Ident(class)) => Some(Some(Left(ClassSelector(class)))),
                _ => None,  // invalid selector
            }
        }
        Some(&SquareBracketBlock(_)) => match iter.next() {
            Some(SquareBracketBlock(content))
            => match parse_attribute_selector(content, namespaces) {
                None => None,
                Some(simple_selector) => Some(Some(Left(simple_selector))),
            },
            _ => fail!("Implementation error, this should not happen."),
        },
        Some(&Delim(':')) => {
            iter.next();
            match iter.next() {
                Some(Ident(name)) => match parse_simple_pseudo_class(name) {
                    None => None,
                    Some(result) => Some(Some(result)),
                },
                Some(Function(name, arguments)) => match parse_functional_pseudo_class(
                        name, arguments, namespaces, inside_negation) {
                    None => None,
                    Some(simple_selector) => Some(Some(Left(simple_selector))),
                },
                Some(Delim(':')) => {
                    match iter.next() {
                        Some(Ident(name)) => match parse_pseudo_element(name) {
                            Some(pseudo_element) => Some(Some(Right(pseudo_element))),
                            _ => None,
                        },
                        _ => None,
                    }
                }
                _ => None,
            }
        }
        _ => Some(None),
    }
}

// None means invalid selector
// Some(None) means not a qualified name
// Some(Some((None, None)) means *|*
// Some(Some((Some(url), None)) means prefix|*
// Some(Some((None, Some(name)) means *|name
// Some(Some((Some(url), Some(name))) means prefix|name
// ... or equivalent
fn parse_qualified_name(iter: &mut Iter, allow_universal: bool, namespaces: &NamespaceMap)
                       -> Option<Option<(Option<~str>, Option<~str>)>> {
    #[inline]
    fn default_namespace(namespaces: &NamespaceMap, local_name: Option<~str>)
                         -> Option<Option<(Option<~str>, Option<~str>)>> {
        match namespaces.default {
            None => Some(Some((None, local_name))),
            Some(ref url) => Some(Some((Some(url.to_owned()), local_name))),
        }
    }

    #[inline]
    fn explicit_namespace(iter: &mut Iter, allow_universal: bool, namespace_url: Option<~str>)
                         -> Option<Option<(Option<~str>, Option<~str>)>> {
        assert!(iter.next() == Some(Delim('|')));
        match iter.peek() {
            Some(&Delim('*')) if allow_universal => {
                iter.next();
                Some(Some((namespace_url, None)))
            },
            Some(&Ident(_)) => {
                let local_name = get_next_ident(iter);
                Some(Some((namespace_url, Some(local_name))))
            },
            _ => None,  // invalid selector
        }
    }

    match iter.peek() {
        Some(&Ident(_)) => {
            let value = get_next_ident(iter);
            match iter.peek() {
                Some(&Delim('|')) => default_namespace(namespaces, Some(value)),
                _ => {
                    let namespace_url = match namespaces.prefix_map.find(&value) {
                        None => return None,  // Undeclared namespace prefix: invalid selector
                        Some(ref url) => url.to_owned(),
                    };
                    explicit_namespace(iter, allow_universal, Some(namespace_url))
                },
            }
        },
        Some(&Delim('*')) => {
            iter.next();  // Consume '*'
            match iter.peek() {
                Some(&Delim('|')) => {
                    if allow_universal { default_namespace(namespaces, None) }
                    else { None }
                },
                _ => explicit_namespace(iter, allow_universal, None),
            }
        },
        Some(&Delim('|')) => explicit_namespace(iter, allow_universal, Some(~"")),
        _ => return None,
    }
}

fn parse_attribute_selector(content: ~[ComponentValue], namespaces: &NamespaceMap)
                            -> Option<SimpleSelector> {
    let iter = &mut content.consume_iter().peekable();
    let attr = match parse_qualified_name(iter, /* allow_universal = */ false, namespaces) {
        None => return None,  // invalid selector
        Some(None) => return None,
        Some(Some((_, None))) => fail!("Implementation error, this should not happen."),
        Some(Some((namespace, Some(local_name)))) => AttrSelector {
            namespace: namespace,
            lowercase_name: to_ascii_lower(local_name),
            cased_name: local_name,
        },
    };
    skip_whitespace(iter);
    macro_rules! get_value( () => {{
        skip_whitespace(iter);
        match iter.next() {
            Some(Ident(value)) | Some(String(value)) => value,
            _ => return None,
        }
    }};)
    let result = match iter.next() {
        None => AttrExists(attr),  // [foo]
        Some(Delim('=')) => AttrEqual(attr, get_value!()),  // [foo=bar]
        Some(IncludeMatch) => AttrIncludes(attr, get_value!()),  // [foo~=bar]
        Some(DashMatch) => AttrDashMatch(attr, get_value!()),  // [foo|=bar]
        Some(PrefixMatch) => AttrPrefixMatch(attr, get_value!()),  // [foo^=bar]
        Some(SubstringMatch) => AttrSubstringMatch(attr, get_value!()),  // [foo*=bar]
        Some(SuffixMatch) => AttrSuffixMatch(attr, get_value!()),  // [foo$=bar]
        _ => return None
    };
    skip_whitespace(iter);
    if iter.next().is_none() { Some(result) } else { None }
}

fn parse_simple_pseudo_class(name: ~str) -> Option<Either<SimpleSelector, PseudoElement>> {
    let lower_name: &str = to_ascii_lower(name);
    match lower_name {
        "root" => Some(Left(Root)),
        "empty" => Some(Left(Empty)),

        // Supported CSS 2.1 pseudo-elements only.
        "before" => Some(Right(Before)),
        "after" => Some(Right(After)),
        "first-line" => Some(Right(FirstLine)),
        "first-letter" => Some(Right(FirstLetter)),
        _ => None
    }
}

fn parse_functional_pseudo_class(name: ~str, arguments: ~[ComponentValue],
                                 namespaces: &NamespaceMap, inside_negation: bool)
                                 -> Option<SimpleSelector> {
    let lower_name: &str = to_ascii_lower(name);
    match lower_name {
        "lang" => parse_lang(arguments),
        "not" => if inside_negation { None } else { parse_negation(arguments, namespaces) },
        _ => None
    }
}

fn parse_pseudo_element(name: ~str) -> Option<PseudoElement> {
    let lower_name: &str = to_ascii_lower(name);
    match lower_name {
        // All supported pseudo-elements
        "before" => Some(Before),
        "after" => Some(After),
        "first-line" => Some(FirstLine),
        "first-letter" => Some(FirstLetter),
        _ => None
    }
}

fn parse_lang(arguments: ~[ComponentValue]) -> Option<SimpleSelector> {
    let mut iter = arguments.consume_skip_whitespace();
    match iter.next() {
        Some(Ident(value)) => {
            if "" == value || iter.next().is_some() { None }
            else { Some(Lang(value)) }
        },
        _ => None,
    }
}

// Level 3: Parse ONE simple_selector
fn parse_negation(arguments: ~[ComponentValue], namespaces: &NamespaceMap)
                  -> Option<SimpleSelector> {
    let iter = &mut arguments.consume_iter().peekable();
    Some(Negation(match parse_type_selector(iter, namespaces) {
        None => return None,  // invalid selector
        Some(Some(s)) => s,
        Some(None) => {
            match parse_one_simple_selector(iter, namespaces, /* inside_negation = */ true) {
                Some(Some(Left(s))) => ~[s],
                _ => return None
            }
        },
    }))
}

/// Assuming the next token is an ident, consume it and return its value
#[inline]
fn get_next_ident(iter: &mut Iter) -> ~str {
    match iter.next() {
        Some(Ident(value)) => value,
        _ => fail!("Implementation error, this should not happen."),
    }
}

#[inline]
fn skip_whitespace(iter: &mut Iter) -> bool {
    let mut any_whitespace = false;
    loop {
        if iter.peek() != Some(&WhiteSpace) { return any_whitespace }
        any_whitespace = true;
        iter.next();
    }
}
<|endoftext|>


<commit_before><commit_msg>Add enclosing_method.rs.<commit_after>use std::io;

use util::*;
use classfile::error::Result;

#[derive(Debug)]
pub struct EnclosingMethodAttribute {
    pub class_index: u16,
    pub method_index: u16,
}

impl EnclosingMethodAttribute {
    pub fn read<T: io::Read>(rdr: &mut T) -> Result<EnclosingMethodAttribute> {
        let class_index = try!(read_u16(rdr));
        let method_index = try!(read_u16(rdr));
        Ok(EnclosingMethodAttribute {
            class_index: class_index,
            method_index: method_index,
        })
    }
}
<|endoftext|>


<commit_before><commit_msg>Add env util<commit_after>struct options {
    ignore_env: bool,
    null: bool,
    unsets: ~[~str],
    sets: ~[(~str, ~str)],
    program: ~[~str]
}

fn usage(prog: &str) {
    println!("Usage: {:s} [OPTION]... [-] [NAME=VALUE]... [COMMAND [ARG]...]", prog);
    println!("Sets each NAME as VALUE in the environment, then run COMMAND\n");
    println!("Possible options are:");
    println!("  -i, --ignore-environment  starts with an empty environment");
    println!("  -0, --null end each line with a 0 byte instead of a \\\\n\n");
}

fn version() {
    println!("env (Rust Coreutils) 1.0");
}

fn print_env(null: bool) {
    println!("env!")
}

fn main() {
    let args = std::os::args();
    let prog = args[0].as_slice();

    // to handle arguments the same way than GNU env, we can't use getopts
    // and have to do this:

    let mut opts = ~options {
        ignore_env: false,
        null: false,
        unsets: ~[],
        sets: ~[],
        program: ~[]
    };

    let mut wait_cmd = false;
    let mut iter = args.iter();
    iter.next(); // skip program

    for opt in iter {
        if wait_cmd {
            // we still accept NAME=VAL here but not other options
            let mut sp = opt.splitn_iter('=', 1);
            let name = sp.next();
            let value = sp.next();

            match (name, value) {
                (Some(n), Some(v)) => {
                    opts.sets.push((n.into_owned(), v.into_owned()));
                }
                _ => {
                    // read the program now
                    opts.program.push(opt.to_owned());
                    break;
                }
            }
        }

        else {
            if opt.starts_with("--") {
                match *opt {
                    ~"--help" => { usage(prog); return }
                    ~"--version" => { version(); return }

                    ~"--ignore-environment" => {
                        opts.ignore_env = true;
                    }

                    ~"--null" => {
                        opts.null = true;
                    }

                    _ => {
                        println!("{:s}: invalid option \"{:s}\"", prog, *opt);
                        println!("Type \"{:s} --help\" for detailed informations", prog);
                        return
                    }
                }
            }

            else {
                match *opt {
                    ~"-" => {
                        // implies -i and stop parsing opts
                        wait_cmd = true;
                        opts.ignore_env = true;
                    }

                    _ => {
                        // is it a NAME=VALUE like opt ?
                        let mut sp = opt.splitn_iter('=', 1);
                        let name = sp.next();
                        let value = sp.next();

                        match (name, value) {
                            (Some(n), Some(v)) => {
                                // yes
                                opts.sets.push((n.into_owned(), v.into_owned()));
                                wait_cmd = true;
                            }
                            // no, its a program-like opt
                            _ => {
                                opts.program.push(opt.to_owned());
                                break;
                            }
                        }
                    }
                }
            }
        }
    }

    // read program arguments now
    for opt in iter {
        opts.program.push(opt.to_owned());
    }

    let env = std::os::env();

    if opts.ignore_env {
        for &(ref name, _) in env.iter() {
            std::os::unsetenv(name.as_slice())
        }
    }

    for &(ref name, ref val) in opts.sets.iter() {
        std::os::setenv(name.as_slice(), val.as_slice())
    }

    match opts.program {
        [ref prog, ..args] => {
            let status = std::run::process_status(prog.as_slice(), args);
            std::os::set_exit_status(status)
        }
        [] => { print_env(opts.null); }
    }
}
<|endoftext|>


<commit_before><commit_msg>Better error handling in plugin instance initial connect.<commit_after><|endoftext|>


<commit_before><commit_msg>fix typo<commit_after><|endoftext|>


<commit_before><commit_msg>Fix Error::description().<commit_after><|endoftext|>


<commit_before><commit_msg>Remove deprected import<commit_after><|endoftext|>


<commit_before><commit_msg>adds queries<commit_after>use std::rc::Rc;
use chrono::{ Date, Duration, Local };
use regex::Regex;

use posting::ClearedStatus;
use quantity::Quantity;

#[derive(Clone, PartialEq, Eq)]
pub enum Query {
    Any,
    None,
    Not(Rc<Query>),
    Or(Vec<Query>),
    And(Vec<Query>),
    Code(Regex),
    Desc(Regex),
    Acct(Regex),
    Date(Duration),
    Date2(Duration),
    Status(ClearedStatus),
    Real(bool),
    Amount(Quantity),
    Symbol(Regex),
    Empty(bool),
    Depth(usize),
    Tag(Regex, Option<Regex>)
}

#[derive(Clone, PartialEq, Eq)]
pub enum QueryOption {
    InAccountOnly(String),
    InAccount(String)
}

pub fn parse_query(day: Date<Local>, query: String) -> (Query, Vec<QueryOption>) {
    (Query::None, Vec::new())
}

pub fn in_account(query_opts: &Vec<QueryOption>) -> Option<(String, bool)> {
    for opt in query_opts {
        match opt {
            &QueryOption::InAccountOnly(ref a) => return Some((a.clone(), false)),
            &QueryOption::InAccount(ref a) => return Some((a.clone(), true))
        }
    }

    None
}

pub fn account_name_level(account_name: String) -> usize {
    return 0;
}

pub fn matches_account(query: &Query, account_name: String) -> bool {
    match query {
        &Query::None => false,
        &Query::Not(ref x) => matches_account(x.as_ref(), account_name),
        &Query::Or(ref xs) => xs.iter().any(|x| matches_account(x, account_name.clone())),
        &Query::And(ref xs) => xs.iter().all(|x| matches_account(x, account_name.clone())),
        &Query::Depth(d) => account_name_level(account_name) <= d,
        &Query::Tag(_, _) => false,
        _ => true,
    }
}
<|endoftext|>


<commit_before><commit_msg>Use url.path_mut() in tests.<commit_after><|endoftext|>


<commit_before><commit_msg>Letting the user input a guess<commit_after><|endoftext|>


<commit_before><commit_msg>Add tests<commit_after><|endoftext|>


<commit_before><commit_msg>replace all ocurrences of Rc with Arc to make our persitent list thread safe<commit_after><|endoftext|>


<commit_before><commit_msg>add generate-testnet command<commit_after>//! This module implement all core commands.

use std::fs;
use std::path::Path;

use helpers::generate_testnet_config;
use config::ConfigFile;

use super::internal::{Command, Feedback};
use super::{Argument, Context, ArgumentType, CommandName, NamedArgument};
const DEFAULT_EXONUM_LISTEN_PORT: u16 = 6333;
/*
pub struct RunCommand;
impl RunCommand;
{
    pub fn args() -> Vec<Argument> {
        SubCommand::with_name("run")
            .about("Run node with given configuration")
            .arg(Arg::with_name("NODE_CONFIG_PATH")
                     .short("c")
                     .long("node-config")
                     .help("Path to node configuration file")
                     .required(true)
                     .takes_value(true))
            .arg(Arg::with_name("LEVELDB_PATH")
                     .short("d")
                     .long("leveldb-path")
                     .help("Use leveldb database with the given path")
                     .required(false)
                     .takes_value(true))
            .arg(Arg::with_name("PUBLIC_API_ADDRESS")
                     .long("public-api-address")
                     .help("Listen address for public api")
                     .required(false)
                     .takes_value(true))
            .arg(Arg::with_name("PRIVATE_API_ADDRESS")
                     .long("private-api-address")
                     .help("Listen address for private api")
                     .required(false)
                     .takes_value(true))
    }

    pub fn node_config_path(matches: &'a ArgMatches<'a>) -> &'a Path {
        matches
            .value_of("NODE_CONFIG_PATH")
            .map(Path::new)
            .expect("Path to node configuration is no setted")
    }

    pub fn node_config(matches: &'a ArgMatches<'a>) -> NodeConfig {
        let path = Self::node_config_path(matches);
        let mut cfg: NodeConfig = ConfigFile::load(path).unwrap();
        // Override api options
        if let Some(addr) = Self::public_api_address(matches) {
            cfg.api.public_api_address = Some(addr);
        }
        if let Some(addr) = Self::private_api_address(matches) {
            cfg.api.private_api_address = Some(addr);
        }
        cfg
    }

    pub fn public_api_address(matches: &'a ArgMatches<'a>) -> Option<SocketAddr> {
        matches
            .value_of("PUBLIC_API_ADDRESS")
            .map(|s| {
                     s.parse()
                         .expect("Public api address has incorrect format")
                 })
    }

    pub fn private_api_address(matches: &'a ArgMatches<'a>) -> Option<SocketAddr> {
        matches
            .value_of("PRIVATE_API_ADDRESS")
            .map(|s| {
                     s.parse()
                         .expect("Private api address has incorrect format")
                 })
    }

    pub fn leveldb_path(matches: &'a ArgMatches<'a>) -> Option<&'a Path> {
        matches.value_of("LEVELDB_PATH").map(Path::new)
    }

    #[cfg(not(feature="memorydb"))]
    pub fn db(matches: &'a ArgMatches<'a>) -> Storage {
        use storage::{LevelDB, LevelDBOptions};

        let path = Self::leveldb_path(matches).unwrap();
        let mut options = LevelDBOptions::new();
        options.create_if_missing = true;
        LevelDB::new(path, options).unwrap()
    }

    #[cfg(feature="memorydb")]
    pub fn db(_: &'a ArgMatches<'a>) -> Storage {
        use storage::MemoryDB;
        MemoryDB::new()
    }
}

#[derive(Serialize, Deserialize)]
pub struct ValidatorIdent {
    pub variables: BTreeMap<String, Value>,
    keys: BTreeMap<String, Value>,
    addr: SocketAddr,
}

impl ValidatorIdent {

    pub fn addr(&self) -> SocketAddr {
        self.addr
    }

    pub fn keys(&self) -> &BTreeMap<String, Value> {
        &self.keys
    }
}

#[derive(Serialize, Deserialize, Default)]
pub struct ConfigTemplate {
    validators: BTreeMap<PublicKey, ValidatorIdent>,
    consensus_cfg: ConsensusConfig,
    count: usize,
    pub services: BTreeMap<String, Value>,
}

impl ConfigTemplate {
    pub fn count(&self) -> usize {
        self.count
    }

    pub fn validators(&self) -> &BTreeMap<PublicKey, ValidatorIdent> {
        &self.validators
    }

    pub fn consensus_cfg(&self) -> &ConsensusConfig {
        &self.consensus_cfg
    }
}

// toml file could not save array without "field name"
#[derive(Serialize, Deserialize)]
struct PubKeyConfig {
    public_key: PublicKey,
    services_pub_keys: BTreeMap<String, Value>
}

#[derive(Serialize, Deserialize)]
pub struct KeyConfig {
    public_key: PublicKey,
    secret_key: SecretKey,
    services_sec_keys: BTreeMap<String, Value>
}

pub struct KeyGeneratorCommand;

impl KeyGeneratorCommand {
    /// Creates basic keygen subcommand.
    pub fn new<'a>() -> App<'a, 'a> {
        SubCommand::with_name("keygen")
            .about("Generate basic node secret key.")
            .arg(Arg::with_name("KEYCHAIN")
                     .help("Path to key config.")
                     .required(true)
                     .index(1))
    }

    /// Path where keychain config should be saved
    pub fn keychain_filee<'a>(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("KEYCHAIN").unwrap())
    }

    /// Generates and writes key config to `keychain()` path.
    pub fn execute_default(matches: &ArgMatches) {
        Self::execute(matches, None, None)
    }

    /// Generates and writes key config to `keychain()` path.
    /// Append `services_sec_keys` to keychain.
    /// Append `services_pub_keys` to public key config.
    /// `add-validator` command autmaticaly share public key config.
    pub fn execute<X, Y>(matches: &ArgMatches,
                    services_sec_keys: X,
                    services_pub_keys: Y)
    where X: Into<Option<BTreeMap<String, Value>>>,
          Y: Into<Option<BTreeMap<String, Value>>>
    {
        let (pub_key, sec_key) = crypto::gen_keypair();
        let keyconfig = Self::keychain_filee(matches);
        let pub_key_path = keyconfig.with_extension("pub");
        let pub_key_config: PubKeyConfig = PubKeyConfig {
            public_key: pub_key,
            services_pub_keys: services_pub_keys.into().unwrap_or_default(),
        };
        // save pub_key seperately
        ConfigFile::save(&pub_key_config, &pub_key_path)
                    .expect("Could not write public key file.");

        let config = KeyConfig {
            public_key: pub_key,
            secret_key: sec_key,
            services_sec_keys: services_sec_keys.into().unwrap_or_default(),
        };

        ConfigFile::save(&config, Self::keychain_filee(matches))
                    .expect("Could not write keychain file.");
    }
}

/// implements command for template generating
pub struct GenerateTemplateCommand;
impl GenerateTemplateCommand {
    pub fn new<'a>() -> App<'a, 'a> {
        SubCommand::with_name("generate-template")
            .about("Generate basic template.")
            .arg(Arg::with_name("COUNT")
                     .help("Validator total count.")
                     .required(true)
                     .index(1))
            .arg(Arg::with_name("TEMPLATE")
                     .help("Path to template config.")
                     .required(true)
                     .index(2))
    }

    /// Path where template config should be saved
    pub fn template_file_path<'a>(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("TEMPLATE").unwrap())
    }
    /// Validator total count
    pub fn validator_count(matches: &ArgMatches) -> usize {
        matches.value_of("COUNT").unwrap().parse().unwrap()
    }

    /// Write default template config into `template()` path.
    pub fn execute_default(matches: &ArgMatches) {
        Self::execute(matches, None)
    }
    /// Write default template config into `template()` path.
    /// You can append some values to template as second argument.
    pub fn execute<T>(matches: &ArgMatches, values: T)
        where T: Into<Option<BTreeMap<String, Value>>>
    {
        let values = values.into().unwrap_or_default();
        let template = ConfigTemplate {
            count: Self::validator_count(matches),
            services: values,
            ..ConfigTemplate::default()
        };

        ConfigFile::save(&template, Self::template_file_path(matches))
                        .expect("Could not write template file.");
    }
}

/// `add-validator` - append validator to template.
/// Automaticaly share keys from public key config.
pub struct AddValidatorCommand;
impl AddValidatorCommand {
    pub fn new<'a>() -> App<'a, 'a> {
        SubCommand::with_name("add-validator")
            .about("Preinit configuration, add validator to config template.")
            .arg(Arg::with_name("TEMPLATE")
                     .help("Path to template")
                     .required(true)
                     .index(1))
            .arg(Arg::with_name("PUBLIC_KEY")
                     .help("Path to public key file.")
                     .required(true)
                     .index(2))
            .arg(Arg::with_name("LISTEN_ADDR")
                     .short("a")
                     .long("listen-addr")
                     .required(true)
                     .takes_value(true))

    }

    /// path to public_key file
    pub fn public_key_file_path<'a>(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("PUBLIC_KEY").unwrap())
    }

    /// path to template config
    pub fn template_file_path<'a>(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("TEMPLATE").unwrap())
    }

    // exonum listen addr
    pub fn listen_addr(matches: &ArgMatches) -> String {
        matches.value_of("LISTEN_ADDR").unwrap().to_string()
    }

    /// Add validator to template config.
    pub fn execute_default(matches: &ArgMatches) {
        Self::execute(matches, |_, _| Ok(()))
    }

    #[cfg_attr(feature="cargo-clippy", allow(map_entry))]
    pub fn execute<F>(matches: &ArgMatches, on_add: F)
        where F: FnOnce(&mut ValidatorIdent, &mut ConfigTemplate)
                        -> Result<(), Box<Error>>,
    {
        let template_path = Self::template_file_path(matches);
        let public_key_path = Self::public_key_file_path(matches);
        let addr = Self::listen_addr(matches);
        let mut addr_parts = addr.split(':');

        let mut template: ConfigTemplate = ConfigFile::load(template_path).unwrap();
        let public_key_config: PubKeyConfig = ConfigFile::load(public_key_path).unwrap();
        let addr = format!("{}:{}",
                           addr_parts.next().expect("expected ip addr"),
                           addr_parts.next().map_or(DEFAULT_EXONUM_LISTEN_PORT,
                                                    |s| s.parse().expect("could not parse port")))
                .parse()
                .unwrap();
        if !template.validators.contains_key(&public_key_config.public_key) {
            if template.validators.len() >= template.count {
                panic!("This template already full.");
            }

            let mut ident = ValidatorIdent {
                addr: addr,
                variables: BTreeMap::default(),
                keys: public_key_config.services_pub_keys,
            };

            on_add(&mut ident, &mut template)
                  .expect("could not add validator, service return");

            template.validators.insert(public_key_config.public_key, ident);
        } else {
            panic!("This node already in template");
        }

        ConfigFile::save(&template, template_path).unwrap();
    }
}

pub struct InitCommand;

impl InitCommand {
    pub fn new<'a>() -> App<'a, 'a> {
        SubCommand::with_name("init")
            .about("Toolchain to generate configuration")
            .arg(Arg::with_name("FULL_TEMPLATE")
                     .help("Path to full template")
                     .required(true)
                     .index(1))
            .arg(Arg::with_name("KEYCHAIN")
                     .help("Path to keychain config.")
                     .required(true)
                     .index(2))
            .arg(Arg::with_name("CONFIG_PATH")
                     .help("Path to node config.")
                     .required(true)
                     .index(3))

    }

    /// path to full template config
    pub fn template<'a>(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("FULL_TEMPLATE").unwrap())
    }

    /// path to output config
    pub fn config<'a>(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("CONFIG_PATH").unwrap())
    }

    /// path to keychain (public and secret keys)
    pub fn keychain<'a>(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("KEYCHAIN").unwrap())
    }

    /// Add validator to template config.
    pub fn execute_default(matches: &ArgMatches) {
        Self::execute(matches, |config, _, _| Ok(Value::try_from(config)? ))
    }

    pub fn execute<F>(matches: &ArgMatches, on_init: F)
        where F: FnOnce(NodeConfig, &ConfigTemplate, &BTreeMap<String, Value>)
                        -> Result<Value, Box<Error>>
    {
        let config_path = Self::config(matches);
        let template_path = Self::template(matches);
        let keychain_path = Self::keychain(matches);

        let template: ConfigTemplate = ConfigFile::load(template_path)
                                                .expect("Failed to load config template.");
        let keychain: KeyConfig = ConfigFile::load(keychain_path)
                                                .expect("Failed to load key config.");

        if template.validators.len() != template.count {
            panic!("Template should be full.");
        }

        let genesis = GenesisConfig::new(template.validators.iter().map(|(k, _)| *k));
        let peers = template
            .validators
            .iter()
            .map(|(_, ident)| ident.addr)
            .collect();
        let validator_ident = &template.validators[&keychain.public_key];

        let config = NodeConfig {
            listen_address: validator_ident.addr,
            network: Default::default(),
            peers: peers,
            public_key: keychain.public_key,
            secret_key: keychain.secret_key,
            genesis: genesis,
            api: Default::default(),
        };
        let value = on_init(config, &template, &keychain.services_sec_keys)
            .expect("Could not create config from template, services return error");
        ConfigFile::save(&value, config_path)
                .expect("Could not write config file.");

    }
}

*/

pub struct GenerateTestnetCommand;

impl Command for GenerateTestnetCommand {
    fn args(&self) -> Vec<Argument> {
        vec![
            Argument {
                name: "OUTPUT_DIR",
                argument: ArgumentType::Named (
                    NamedArgument {
                        short_name: "o",
                        long_name: "output_dir",
                    }
                ),
                required: true,
                help: "Path to directory where save configs.",
            },
            Argument {
                name: "START_PORT",
                argument: ArgumentType::Named (
                    NamedArgument {
                        short_name: "p",
                        long_name: "start-port",
                    }
                ),
                required: false,
                help: "Port number started from which should validators listen.",
            },
            Argument {
                name: "COUNT",
                argument: ArgumentType::Positional,
                required: true,
                help: "Count of validators in testnet.",
            }
        ]
    }

    fn name(&self) -> CommandName {
        "generate-testnet"
    }

    fn about(&self) -> &str {
        "Generates genesis configuration for testnet"
    }

    fn execute(&self,
               context: Context,
               _: &Fn(Context) -> Context) -> Feedback {

        let dir = context.get::<String>("OUTPUT_DIR").unwrap();
        let count = context.get::<u8>("COUNT").unwrap();
        let start_port = context.get::<u16>("START_PORT")
                                .unwrap_or_else(|| DEFAULT_EXONUM_LISTEN_PORT);

        let dir = Path::new(&dir);
        let dir = dir.join("validators");
        if !dir.exists() {
            fs::create_dir_all(&dir).unwrap();
        }

        let configs = generate_testnet_config(count, start_port);
        for (idx, cfg) in configs.into_iter().enumerate() {
            let file_name = format!("{}.toml", idx);
            ConfigFile::save(&cfg, &dir.join(file_name)).unwrap();
        }

        Feedback::None
    }
}<|endoftext|>


<commit_before><commit_msg>Add command for FLAC metdata<commit_after>extern crate docopt;
extern crate flac;
extern crate rustc_serialize;

use docopt::Docopt;
use flac::{ReadStream, Stream, StreamProducer};

use std::env;
use std::fs::File;

const USAGE: &'static str = "
Usage: metadata streaminfo <input>
       metadata --help

Options:
  -h, --help   Show this message.
";

#[derive(Debug, RustcDecodable)]
struct Arguments {
  arg_input: String,
  cmd_streaminfo: bool,
}

fn print_stream_info<P: StreamProducer>(stream: &Stream<P>) {
  let info = stream.info();

  println!("StreamInfo
  Minimum block size: {}
  Maximum block size: {}
  Maximum frame size: {}
  Maximum frame size: {}
  Sample rate: {} Hz
  Number of channels: {}
  Bits per sample: {}
  Total samples: {}
  MD5 sum: {:?}",
  info.min_block_size, info.max_block_size,
  info.min_frame_size, info.max_frame_size,
  info.sample_rate, info.channels, info.bits_per_sample, info.total_samples,
  info.md5_sum);
}

fn main() {
  let args: Arguments = Docopt::new(USAGE)
    .and_then(|d| d.argv(env::args()).decode())
    .unwrap_or_else(|e| e.exit());

  let stream = Stream::<ReadStream<File>>::from_file(&args.arg_input)
                 .expect("Couldn't parse file");

  if args.cmd_streaminfo {
    print_stream_info(&stream);
  }
}
<|endoftext|>


<commit_before><commit_msg>progress tracking example<commit_after>//! A demonstration of timely dataflow progress tracking, using differential dataflow operators.

extern crate timely;
extern crate differential_dataflow;

use timely::PartialOrder;
use timely::dataflow::*;
use timely::dataflow::operators::probe::Handle;

use differential_dataflow::input::Input;
use differential_dataflow::Collection;
use differential_dataflow::operators::*;

use differential_dataflow::lattice::Lattice;

use timely::progress::{Timestamp, Source, Target, Location};
use timely::progress::timestamp::PathSummary;

fn main() {

    timely::execute_from_args(std::env::args(), move |worker| {

        let timer = worker.timer();
        let mut probe = Handle::new();

        let (mut nodes, mut edges, mut times) = worker.dataflow::<usize,_,_>(|scope| {

            let (node_input, nodes) = scope.new_collection();
            let (edge_input, edges) = scope.new_collection();
            let (time_input, times) = scope.new_collection();

            // Detect cycles that do not increment timestamps.
            find_cycles::<_,usize>(nodes.clone(), edges.clone())
                .inspect(move |x| println!("{:?}\tcycles: {:?}", timer.elapsed(), x))
                .probe_with(&mut probe);

            // Summarize all paths to inputs of operator zero.
            summarize::<_,usize>(nodes.clone(), edges.clone())
                .inspect(move |x| println!("{:?}\tsummary: {:?}", timer.elapsed(), x))
                .probe_with(&mut probe);

            // Track the frontier at each dataflow location.
            frontier::<_,usize>(nodes, edges, times)
                .inspect(move |x| println!("{:?}\tfrontier: {:?}", timer.elapsed(), x))
                .probe_with(&mut probe);

            (node_input, edge_input, time_input)
        });

        // A PageRank-like graph, as represented here:
        //  https://github.com/TimelyDataflow/diagnostics/blob/master/examples/pagerank.png
        nodes.insert((Target::new(2, 0), Source::new(2, 0), 1));
        nodes.insert((Target::new(3, 0), Source::new(3, 0), 0));
        nodes.insert((Target::new(3, 1), Source::new(3, 0), 0));
        nodes.insert((Target::new(4, 0), Source::new(4, 0), 0));

        edges.insert((Source::new(1, 0), Target::new(3, 0)));
        edges.insert((Source::new(3, 0), Target::new(4, 0)));
        edges.insert((Source::new(4, 0), Target::new(2, 0)));
        edges.insert((Source::new(2, 0), Target::new(3, 1)));

        // Initially no capabilities.
        nodes.advance_to(1); nodes.flush();
        edges.advance_to(1); edges.flush();
        times.advance_to(1); times.flush();

        while probe.less_than(times.time()) {
            worker.step();
        }

        // Introduce a new input capability at time zero.
        times.insert((Location::new_source(1, 0), 0));

        nodes.advance_to(2); nodes.flush();
        edges.advance_to(2); edges.flush();
        times.advance_to(2); times.flush();

        while probe.less_than(times.time()) {
            worker.step();
        }

        // Remove input capability and produce a message.
        times.remove((Location::new_source(1, 0), 0));
        times.insert((Location::new_target(3, 0), 0));

        nodes.advance_to(3); nodes.flush();
        edges.advance_to(3); edges.flush();
        times.advance_to(3); times.flush();

        while probe.less_than(times.time()) {
            worker.step();
        }

        // Consume the message, and .. do nothing, I guess.
        times.remove((Location::new_target(3, 0), 0));

        nodes.advance_to(4); nodes.flush();
        edges.advance_to(4); edges.flush();
        times.advance_to(4); times.flush();

        while probe.less_than(times.time()) {
            worker.step();
        }

        println!("finished; elapsed: {:?}", timer.elapsed());
    }).unwrap();
}

/// Propagates times along a timely dataflow graph.
///
/// Timely dataflow graphs are described by nodes with interconnected input and output ports,
/// and edges which connect output ports to input ports of what may be other nodes.
///
/// A set of times at various locations (input or output ports) could traverse nodes and
/// edges to arrive at various other locations. Each location can then track minimal times
/// that can reach them: those times not greater than some other time that can reach it.
///
/// The computation to determine this, and to maintain it as times change, is an iterative
/// computation that propagates times and maintains the minimal elements at each location.
fn frontier<G: Scope, T: Timestamp>(
    nodes: Collection<G, (Target, Source, T::Summary)>,
    edges: Collection<G, (Source, Target)>,
    times: Collection<G, (Location, T)>,
) -> Collection<G, (Location, T)>
where
    G::Timestamp: Lattice+Ord,
    T::Summary: differential_dataflow::ExchangeData,
{
    // Translate node and edge transitions into a common Location to Location edge with an associated Summary.
    let nodes = nodes.map(|(target, source, summary)| (Location::from(target), (Location::from(source), summary)));
    let edges = edges.map(|(source, target)| (Location::from(source), (Location::from(target), Default::default())));
    let transitions: Collection<G, (Location, (Location, T::Summary))> = nodes.concat(&edges);

    times
        .iterate(|reach| {
            transitions
                .enter(&reach.scope())
                .join_map(&reach, |_from, (dest, summ), time| (dest.clone(), summ.results_in(time)))
                .flat_map(|(dest, time)| time.map(move |time| (dest, time)))
                .concat(&times.enter(&reach.scope()))
                .reduce(|_location, input, output: &mut Vec<(T, isize)>| {
                    // retain the lower envelope of times.
                    for (t1, _count1) in input.iter() {
                        if !input.iter().any(|(t2, _count2)| t2.less_than(t1)) {
                            output.push(((*t1).clone(), 1));
                        }
                    }
                })
        })
        .consolidate()
}

/// Summary paths from locations to operator zero inputs.
fn summarize<G: Scope, T: Timestamp>(
    nodes: Collection<G, (Target, Source, T::Summary)>,
    edges: Collection<G, (Source, Target)>,
) -> Collection<G, (Location, (Location, T::Summary))>
where
    G::Timestamp: Lattice+Ord,
    T::Summary: differential_dataflow::ExchangeData+std::hash::Hash,
{
    // Start from trivial reachability from each input to itself.
    let zero_inputs =
    edges
        .map(|(_source, target)| Location::from(target))
        .filter(|location| location.node == 0)
        .map(|location| (location, (location, Default::default())));

    // Retain node connections along "default" timestamp summaries.
    let nodes = nodes.map(|(target, source, summary)| (Location::from(source), (Location::from(target), summary)));
    let edges = edges.map(|(source, target)| (Location::from(target), (Location::from(source), Default::default())));
    let transitions: Collection<G, (Location, (Location, T::Summary))> = nodes.concat(&edges);

    zero_inputs
        .iterate(|summaries| {
            transitions
                .enter(&summaries.scope())
                .join_map(summaries, |_middle, (from, summ1), (to, summ2)| (from.clone(), to.clone(), summ1.followed_by(summ2)))
                .flat_map(|(from, to, summ)| summ.map(move |summ| (from, (to, summ))))
                .concat(&zero_inputs.enter(&summaries.scope()))
                .map(|(from, (to, summary))| ((from, to), summary))
                .reduce(|_from_to, input, output| {
                    for (summary, _count) in input.iter() {
                        if !input.iter().any(|(sum2, _count2)| sum2.less_than(*summary)) {
                            output.push(((*summary).clone(), 1));
                        }
                    }
                })
                .map(|((from, to), summary)| (from, (to, summary)))

        })
        .consolidate()
}

/// Identifies cycles along paths that do not increment timestamps.
fn find_cycles<G: Scope, T: Timestamp>(
    nodes: Collection<G, (Target, Source, T::Summary)>,
    edges: Collection<G, (Source, Target)>,
) -> Collection<G, (Location, Location)>
where
    G::Timestamp: Lattice+Ord,
    T::Summary: differential_dataflow::ExchangeData,
{
    // Retain node connections along "default" timestamp summaries.
    let nodes = nodes.flat_map(|(target, source, summary)| {
        if summary != Default::default() {
            Some((Location::from(target), Location::from(source)))
        }
        else {
            None
        }
    });
    let edges = edges.map(|(source, target)| (Location::from(source), Location::from(target)));
    let transitions: Collection<G, (Location, Location)> = nodes.concat(&edges);

    // Repeatedly restrict to locations with an incoming path.
    transitions
        .iterate(|locations| {
            let active =
            locations
                .map(|(_source, target)| target)
                .distinct();
            transitions
                .enter(&locations.scope())
                .semijoin(&active)
        })
        .consolidate()
}<|endoftext|>