<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern mod std;
extern mod extra;

use std::cell::Cell;
use std::io;
use std::os;
use std::run;
use extra::digest::{Digest, DigestUtil};
use extra::sha1::Sha1;
use extra::test::{DynTestName, DynTestFn, TestDesc, TestOpts, TestDescAndFn};
use extra::test::run_tests_console;

fn main() {
    let args = os::args();
    if args.len() < 2 {
        println("error: at least one reftest list must be given");
        os::set_exit_status(1);
        return;
    }

    let tests = parse_lists(args.tail());
    let test_opts = TestOpts {
        filter: None,
        run_ignored: false,
        logfile: None,
        run_tests: true,
        run_benchmarks: false,
        save_results: None,
        compare_results: None,
    };

    if !run_tests_console(&test_opts, tests) {
        os::set_exit_status(1);
    }
}

enum ReftestKind {
    Same,
    Different,
}

struct Reftest {
    name: ~str,
    kind: ReftestKind,
    left: ~str,
    right: ~str,
}

fn parse_lists(filenames: &[~str]) -> ~[TestDescAndFn] {
    let mut tests: ~[TestDescAndFn] = ~[];
    for filenames.iter().advance |file| {
        let file_path = Path(*file);
        let contents = match io::read_whole_file_str(&file_path) {
            Ok(x) => x,
            Err(s) => fail!(s)
        };

        for contents.line_iter().advance |line| {
            let parts: ~[&str] = line.split_iter(' ').filter(|p| !p.is_empty()).collect();

            if parts.len() != 3 {
                fail!(fmt!("reftest line: '%s' doesn't match 'KIND LEFT RIGHT'", line));
            }

            let kind = match parts[0] {
                "==" => Same,
                "!=" => Different,
                _ => fail!(fmt!("reftest line: '%s' has invalid kind '%s'",
                                line, parts[0]))
            };
            let src_dir = file_path.dirname();
            let file_left = src_dir + "/" + parts[1];
            let file_right = src_dir + "/" + parts[2];

            let reftest = Reftest {
                name: parts[1] + " / " + parts[2],
                kind: kind,
                left: file_left,
                right: file_right,
            };

            tests.push(make_test(reftest));
        }
    }
    tests
}

fn make_test(reftest: Reftest) -> TestDescAndFn {
    let name = reftest.name.clone();
    let reftest = Cell::new(reftest);
    TestDescAndFn {
        desc: TestDesc {
            name: DynTestName(name),
            ignore: false,
            should_fail: false,
        },
        testfn: DynTestFn(|| {
            check_reftest(reftest.take());
        }),
    }
}

fn check_reftest(reftest: Reftest) {
    let id = gen_id(&reftest);
    let left_filename = fmt!("/tmp/%s-left.png", id);
    let right_filename = fmt!("/tmp/%s-right.png", id);
    let left_path = Path(left_filename);
    let right_path = Path(right_filename);

    let options = run::ProcessOptions::new();
    let args = ~[~"-o", left_filename.clone(), reftest.left.clone()];
    let mut process = run::Process::new("./servo", args, options);
    let _retval = process.finish();
    // assert!(retval == 0);

    let args = ~[~"-o", right_filename.clone(), reftest.right.clone()];
    let mut process = run::Process::new("./servo", args, options);
    let _retval = process.finish();
    // assert!(retval == 0);

    // check the pngs are bit equal
    let left_sha = calc_hash(&left_path);
    os::remove_file(&left_path);

    let right_sha = calc_hash(&right_path);
    os::remove_file(&right_path);

    assert!(left_sha.is_some());
    assert!(right_sha.is_some());
    match reftest.kind {
        Same => assert!(left_sha == right_sha),
        Different => assert!(left_sha != right_sha),
    }
}

fn gen_id(reftest: &Reftest) -> ~str {
    let mut sha = Sha1::new();
    match reftest.kind {
        Same => sha.input_str("=="),
        Different => sha.input_str("!="),
    }
    sha.input_str(reftest.left);
    sha.input_str(reftest.right);
    sha.result_str()
}

fn calc_hash(path: &Path) -> Option<~str> {
    match io::file_reader(path) {
        Err(*) => None,
        Ok(reader) => {
            let mut sha = Sha1::new();
            loop {
                let bytes = reader.read_bytes(4096);
                sha.input(bytes);
                if bytes.len() < 4096 { break; }
            }
            Some(sha.result_str())
        }
    }
}<commit_msg>Update Rust language for 'make check-ref'<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern mod std;
extern mod extra;

use std::cell::Cell;
use std::io;
use std::os;
use std::run;
use extra::digest::Digest;
use extra::sha1::Sha1;
use extra::test::{DynTestName, DynTestFn, TestDesc, TestOpts, TestDescAndFn};
use extra::test::run_tests_console;

fn main() {
    let args = os::args();
    if args.len() < 2 {
        println("error: at least one reftest list must be given");
        os::set_exit_status(1);
        return;
    }

    let tests = parse_lists(args.tail());
    let test_opts = TestOpts {
        filter: None,
        run_ignored: false,
        logfile: None,
        run_tests: true,
        run_benchmarks: false,
        ratchet_noise_percent: None,
        ratchet_metrics: None,
        save_metrics: None,
    };

    if !run_tests_console(&test_opts, tests) {
        os::set_exit_status(1);
    }
}

enum ReftestKind {
    Same,
    Different,
}

struct Reftest {
    name: ~str,
    kind: ReftestKind,
    left: ~str,
    right: ~str,
}

fn parse_lists(filenames: &[~str]) -> ~[TestDescAndFn] {
    let mut tests: ~[TestDescAndFn] = ~[];
    for file in filenames.iter() {
        let file_path = Path(*file);
        let contents = match io::read_whole_file_str(&file_path) {
            Ok(x) => x,
            Err(s) => fail!(s)
        };

        for line in contents.line_iter() {
            let parts: ~[&str] = line.split_iter(' ').filter(|p| !p.is_empty()).collect();

            if parts.len() != 3 {
                fail!(fmt!("reftest line: '%s' doesn't match 'KIND LEFT RIGHT'", line));
            }

            let kind = match parts[0] {
                "==" => Same,
                "!=" => Different,
                _ => fail!(fmt!("reftest line: '%s' has invalid kind '%s'",
                                line, parts[0]))
            };
            let src_dir = file_path.dirname();
            let file_left = src_dir + "/" + parts[1];
            let file_right = src_dir + "/" + parts[2];

            let reftest = Reftest {
                name: parts[1] + " / " + parts[2],
                kind: kind,
                left: file_left,
                right: file_right,
            };

            tests.push(make_test(reftest));
        }
    }
    tests
}

fn make_test(reftest: Reftest) -> TestDescAndFn {
    let name = reftest.name.clone();
    let reftest = Cell::new(reftest);
    TestDescAndFn {
        desc: TestDesc {
            name: DynTestName(name),
            ignore: false,
            should_fail: false,
        },
        testfn: DynTestFn(|| {
            check_reftest(reftest.take());
        }),
    }
}

fn check_reftest(reftest: Reftest) {
    let id = gen_id(&reftest);
    let left_filename = fmt!("/tmp/%s-left.png", id);
    let right_filename = fmt!("/tmp/%s-right.png", id);
    let left_path = Path(left_filename);
    let right_path = Path(right_filename);

    let options = run::ProcessOptions::new();
    let args = ~[~"-o", left_filename.clone(), reftest.left.clone()];
    let mut process = run::Process::new("./servo", args, options);
    let _retval = process.finish();
    // assert!(retval == 0);

    let args = ~[~"-o", right_filename.clone(), reftest.right.clone()];
    let mut process = run::Process::new("./servo", args, options);
    let _retval = process.finish();
    // assert!(retval == 0);

    // check the pngs are bit equal
    let left_sha = calc_hash(&left_path);
    os::remove_file(&left_path);

    let right_sha = calc_hash(&right_path);
    os::remove_file(&right_path);

    assert!(left_sha.is_some());
    assert!(right_sha.is_some());
    match reftest.kind {
        Same => assert!(left_sha == right_sha),
        Different => assert!(left_sha != right_sha),
    }
}

fn gen_id(reftest: &Reftest) -> ~str {
    let mut sha = Sha1::new();
    match reftest.kind {
        Same => sha.input_str("=="),
        Different => sha.input_str("!="),
    }
    sha.input_str(reftest.left);
    sha.input_str(reftest.right);
    sha.result_str()
}

fn calc_hash(path: &Path) -> Option<~str> {
    match io::file_reader(path) {
        Err(*) => None,
        Ok(reader) => {
            let mut sha = Sha1::new();
            loop {
                let bytes = reader.read_bytes(4096);
                sha.input(bytes);
                if bytes.len() < 4096 { break; }
            }
            Some(sha.result_str())
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::VecDeque;

use languageserver_types::TextDocumentContentChangeEvent;

use gluon::base::source;
use gluon::base::pos::Span;

use rpc::ServerError;
use location_translation::range_to_byte_span;

struct VersionedChange {
    version: u64,
    content_changes: Vec<TextDocumentContentChangeEvent>,
}

/// Type which applies text changes in the order that the client sends them.
/// Out of order changes are stored until all earlier changes have been received after which they
/// are applied all at once.
pub struct TextChanges {
    changes: VecDeque<VersionedChange>,
}

impl TextChanges {
    pub fn new() -> Self {
        TextChanges {
            changes: VecDeque::new(),
        }
    }

    pub fn add(&mut self, version: u64, content_changes: Vec<TextDocumentContentChangeEvent>) {
        let i = self.changes
            .iter()
            .position(|change| change.version > version)
            .unwrap_or(self.changes.len());
        self.changes.insert(
            i,
            VersionedChange {
                version,
                content_changes,
            },
        );
    }

    pub fn apply_changes(
        &mut self,
        source: &mut String,
        mut version: u64,
    ) -> Result<u64, ServerError<()>> {
        while let Some(change) = self.changes.pop_front() {
            assert!(
                (change.version == version && change.content_changes.is_empty())
                    || change.version > version,
                "BUG: Attempt to apply old change on newer contents"
            );
            if change.content_changes.is_empty() {
                continue;
            }
            if version + 1 != change.version {
                self.changes.push_front(change);
                break;
            }
            version += 1;
            apply_changes(source, &change.content_changes)?
        }
        Ok(version)
    }
}

fn apply_changes(
    source: &mut String,
    content_changes: &[TextDocumentContentChangeEvent],
) -> Result<(), ServerError<()>> {
    for change in content_changes {
        let lines = source::Lines::new(source.bytes());
        apply_change(source, lines, change)?;
    }
    Ok(())
}

fn apply_change(
    source: &mut String,
    lines: source::Lines,
    change: &TextDocumentContentChangeEvent,
) -> Result<(), ServerError<()>> {
    info!("Applying change: {:?}", change);
    let span = match (change.range, change.range_length) {
        (None, None) => Span::new(0.into(), source.len().into()),
        (Some(range), None) | (Some(range), Some(_)) => {
            range_to_byte_span(&source::Source::with_lines(source, lines), &range)?
        }
        (None, Some(_)) => panic!("Invalid change"),
    };
    if let Some(range_length) = change.range_length {
        assert!(range_length as usize == (span.end - span.start).to_usize());
    }
    source.drain(span.start.to_usize()..span.end.to_usize());
    source.insert_str(span.start.to_usize(), &change.text);
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;

    use languageserver_types::{Position, Range};

    #[test]
    fn apply_changes_test() {
        let mut source = String::new();
        apply_changes(
            &mut source,
            &[
                TextDocumentContentChangeEvent {
                    range: Some(Range {
                        start: Position {
                            line: 0,
                            character: 0,
                        },
                        end: Position {
                            line: 0,
                            character: 0,
                        },
                    }),
                    range_length: None,
                    text: "test".to_string(),
                },
            ],
        ).unwrap();

        assert_eq!(source, "test");

        apply_changes(
            &mut source,
            &[
                TextDocumentContentChangeEvent {
                    range: Some(Range {
                        start: Position {
                            line: 0,
                            character: 2,
                        },
                        end: Position {
                            line: 0,
                            character: 3,
                        },
                    }),
                    range_length: Some(1),
                    text: "".to_string(),
                },
            ],
        ).unwrap();

        assert_eq!(source, "tet");

        apply_changes(
            &mut source,
            &[
                TextDocumentContentChangeEvent {
                    range: Some(Range {
                        start: Position {
                            line: 0,
                            character: 2,
                        },
                        end: Position {
                            line: 0,
                            character: 3,
                        },
                    }),
                    range_length: Some(1),
                    text: "ab".to_string(),
                },
            ],
        ).unwrap();

        assert_eq!(source, "teab");
    }
}
<commit_msg>Remove assert that is now wrong<commit_after>use std::collections::VecDeque;

use languageserver_types::TextDocumentContentChangeEvent;

use gluon::base::source;
use gluon::base::pos::Span;

use rpc::ServerError;
use location_translation::range_to_byte_span;

struct VersionedChange {
    version: u64,
    content_changes: Vec<TextDocumentContentChangeEvent>,
}

/// Type which applies text changes in the order that the client sends them.
/// Out of order changes are stored until all earlier changes have been received after which they
/// are applied all at once.
pub struct TextChanges {
    changes: VecDeque<VersionedChange>,
}

impl TextChanges {
    pub fn new() -> Self {
        TextChanges {
            changes: VecDeque::new(),
        }
    }

    pub fn add(&mut self, version: u64, content_changes: Vec<TextDocumentContentChangeEvent>) {
        let i = self.changes
            .iter()
            .position(|change| change.version > version)
            .unwrap_or(self.changes.len());
        self.changes.insert(
            i,
            VersionedChange {
                version,
                content_changes,
            },
        );
    }

    pub fn apply_changes(
        &mut self,
        source: &mut String,
        mut version: u64,
    ) -> Result<u64, ServerError<()>> {
        while let Some(change) = self.changes.pop_front() {
            assert!(
                (change.version == version && change.content_changes.is_empty())
                    || change.version > version,
                "BUG: Attempt to apply old change on newer contents"
            );
            if change.content_changes.is_empty() {
                continue;
            }
            if version + 1 != change.version {
                self.changes.push_front(change);
                break;
            }
            version += 1;
            apply_changes(source, &change.content_changes)?
        }
        Ok(version)
    }
}

fn apply_changes(
    source: &mut String,
    content_changes: &[TextDocumentContentChangeEvent],
) -> Result<(), ServerError<()>> {
    for change in content_changes {
        let lines = source::Lines::new(source.bytes());
        apply_change(source, lines, change)?;
    }
    Ok(())
}

fn apply_change(
    source: &mut String,
    lines: source::Lines,
    change: &TextDocumentContentChangeEvent,
) -> Result<(), ServerError<()>> {
    info!("Applying change: {:?}", change);
    let span = match (change.range, change.range_length) {
        (None, None) => Span::new(0.into(), source.len().into()),
        (Some(range), None) | (Some(range), Some(_)) => {
            range_to_byte_span(&source::Source::with_lines(source, lines), &range)?
        }
        (None, Some(_)) => panic!("Invalid change"),
    };
    source.drain(span.start.to_usize()..span.end.to_usize());
    source.insert_str(span.start.to_usize(), &change.text);
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;

    use languageserver_types::{Position, Range};

    #[test]
    fn apply_changes_test() {
        let mut source = String::new();
        apply_changes(
            &mut source,
            &[
                TextDocumentContentChangeEvent {
                    range: Some(Range {
                        start: Position {
                            line: 0,
                            character: 0,
                        },
                        end: Position {
                            line: 0,
                            character: 0,
                        },
                    }),
                    range_length: None,
                    text: "test".to_string(),
                },
            ],
        ).unwrap();

        assert_eq!(source, "test");

        apply_changes(
            &mut source,
            &[
                TextDocumentContentChangeEvent {
                    range: Some(Range {
                        start: Position {
                            line: 0,
                            character: 2,
                        },
                        end: Position {
                            line: 0,
                            character: 3,
                        },
                    }),
                    range_length: Some(1),
                    text: "".to_string(),
                },
            ],
        ).unwrap();

        assert_eq!(source, "tet");

        apply_changes(
            &mut source,
            &[
                TextDocumentContentChangeEvent {
                    range: Some(Range {
                        start: Position {
                            line: 0,
                            character: 2,
                        },
                        end: Position {
                            line: 0,
                            character: 3,
                        },
                    }),
                    range_length: Some(1),
                    text: "ab".to_string(),
                },
            ],
        ).unwrap();

        assert_eq!(source, "teab");
    }
}
<|endoftext|>


<commit_before>// For reference on linking to C++ functions, see https://github.com/rust-lang/rust/issues/5853#issuecomment-44365672

#[cfg(target_family = "windows")]
#[allow(non_snake_case)]
mod Platform {
    pub mod Details {
        #[link(name = "vccorlib")]
        #[cfg(target_arch="x86_64")]
        extern "C" {
            // This generates invalid program output causing a crash when this function is called. See https://github.com/rust-lang/rust/issues/23216 for details.
            #[link_name = "?GetCmdArguments@Details@Platform@@YAPEAPEA_WPEAH@Z"]
            pub fn GetCmdArguments(argc : *mut ::libc::c_int) -> *const *const ::libc::wchar_t;
        }

        #[link(name = "vccorlib")]
        #[cfg(target_arch = "x86")]
        extern "C" {
            // This generates invalid program output causing a crash when this function is called. See https://github.com/rust-lang/rust/issues/23216 for details.
            #[link_name = "?GetCmdArguments@Details@Platform@@YAPAPA_WPAH@Z"]
            pub fn GetCmdArguments(argc : *mut ::libc::c_int) -> *const *const ::libc::wchar_t;
        }
    }
}

pub fn get_command_arguments(argc : ::libc::c_int) -> (*const *const ::libc::wchar_t, ::libc::c_int) {
    let mut argc = argc;
    ( unsafe { Platform::Details::GetCmdArguments(&mut argc) }, argc)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_get_command_arguments() {
        let (argv, argc) = get_command_arguments(0);
        assert!(argc == 1);
    }
}<commit_msg>Make get_command_arguments slightly more Rust friendly<commit_after>// For reference on linking to C++ functions, see https://github.com/rust-lang/rust/issues/5853#issuecomment-44365672

#[cfg(target_family = "windows")]
#[allow(non_snake_case)]
mod Platform {
    pub mod Details {
        #[link(name = "vccorlib")]
        #[cfg(target_arch="x86_64")]
        extern "C" {
            // This generates invalid program output causing a crash when this function is called. See https://github.com/rust-lang/rust/issues/23216 for details.
            #[link_name = "?GetCmdArguments@Details@Platform@@YAPEAPEA_WPEAH@Z"]
            pub fn GetCmdArguments(argc : *mut ::libc::c_int) -> *const *const ::libc::wchar_t;
        }

        #[link(name = "vccorlib")]
        #[cfg(target_arch = "x86")]
        extern "C" {
            // This generates invalid program output causing a crash when this function is called. See https://github.com/rust-lang/rust/issues/23216 for details.
            #[link_name = "?GetCmdArguments@Details@Platform@@YAPAPA_WPAH@Z"]
            pub fn GetCmdArguments(argc : *mut ::libc::c_int) -> *const *const ::libc::wchar_t;
        }
    }
}

pub fn get_command_arguments(argc : ::libc::c_int) -> (&'static [* const ::libc::wchar_t], usize) {
    let mut argc = argc;
    let argv = unsafe { Platform::Details::GetCmdArguments(&mut argc) };
    ( unsafe { ::std::slice::from_raw_parts(argv, argc as usize) }, argc as usize)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_get_command_arguments() {
        let (argv, argc) = get_command_arguments(0);
        assert!(argc == 1);
        for i in 0..argc {
            let argument : &[::libc::wchar_t] = unsafe { ::std::slice::from_raw_parts(argv[i], ::libc::wcslen(argv[i]) as usize) };
            // println!("Foo: {}", argument)
            // assert!(argument[0] == 'C' as u16)
        }
    }
}<|endoftext|>


<commit_before>use event::Event;
use sass::comment::SassComment;
use sass::rule::SassRule;
use sass::selector::SassSelector;
use sass::variable::SassVariable;
use top_level_event::TopLevelEvent;

use std::borrow::Cow::Borrowed;

fn is_ascii_whitespace(c: u8) -> bool {
   is_newline(c) || is_ascii_whitespace_no_nl(c)
}

fn is_ascii_whitespace_no_nl(c: u8) -> bool {
    c == b'\t' || c == 0x0b || c == 0x0c || c == b' '
}

fn is_newline(c: u8) -> bool {
    c == b'\n' || c == b'\r'
}

fn isnt_newline(c: u8) -> bool {
    !is_newline(c)
}

// unusual among "scan" functions in that it scans from the _back_ of the string
// TODO: should also scan unicode whitespace?
fn scan_trailing_whitespace(data: &str) -> usize {
    match data.as_bytes().iter().rev().position(|&c| !is_ascii_whitespace_no_nl(c)) {
        Some(i) => i,
        None => data.len()
    }
}

#[derive(Debug)]
pub struct Tokenizer<'a> {
    sass: &'a str,
    bytes: &'a [u8],
    offset: usize,
    state: State,
    sass_rule_stack: Vec<SassRule<'a>>,
    current_sass_rule: SassRule<'a>,
}

#[derive(PartialEq, Debug, Clone)]
enum State {
    OutsideRules,
    InVariable,
    InComment,
    InRule,
    InSelectors,
    InProperties,
    EndRule,
    Eof,
}

impl<'a> Tokenizer<'a> {
    pub fn new(sass: &'a str) -> Tokenizer<'a> {
        Tokenizer {
            sass: &sass,
            bytes: &sass.as_bytes(),
            offset: 0,
            state: State::OutsideRules,
            sass_rule_stack: Vec::new(),
            current_sass_rule: SassRule::new(),
        }
    }

    fn start_something(&mut self) -> Option<TopLevelEvent<'a>> {
        self.current_sass_rule = SassRule::new();

        self.pick_something();
        while self.state != State::OutsideRules {
            let curr_state = self.state.clone();
            match curr_state {
                State::Eof => {
                    return None
                },
                State::InSelectors => {
                    let sel = self.next_selector();
                    if sel.is_some() {
                        self.current_sass_rule.selectors.push(sel.unwrap());
                    }
                },
                State::InProperties => {
                    let prop = self.next_property();
                    if prop.is_some() {
                        self.current_sass_rule.children.push(prop.unwrap());
                    }
                },
                State::EndRule => {
                    // consume '}', should probably be checking that's what we actually have
                    self.offset += 1;

                    match self.sass_rule_stack.pop() {
                        Some(ref mut rule) => {
                            rule.children.push(Event::ChildRule(self.current_sass_rule.clone()));
                            self.current_sass_rule = (*rule).clone();
                            self.pick_something();
                        },
                        None => self.state = State::OutsideRules,
                    }
                },
                State::InRule => {
                    self.sass_rule_stack.push(self.current_sass_rule.clone());
                    self.current_sass_rule = SassRule::new();
                    self.pick_something();
                },
                State::InVariable => {
                    let var = self.next_variable();
                    if var.is_some() {
                        return var
                    } else {
                        // is this really what we should be doing here? reachable?
                        self.state = State::Eof;
                    }
                },
                State::InComment => {
                    let comment = self.next_comment();
                    if comment.is_some() {
                        if self.sass_rule_stack.len() == 0 &&
                           self.current_sass_rule.selectors.len() == 0 &&
                           self.current_sass_rule.children.len() == 0 {
                               return Some(TopLevelEvent::Comment(SassComment { comment: comment.unwrap() }))
                        } else {
                            self.current_sass_rule.children.push(comment.unwrap());
                            self.pick_something();
                        }
                    } else {
                        // is this really what we should be doing here? reachable?
                        self.state = State::Eof;
                    }
                }
                unknown_state => {
                    println!("i dont know what to do for {:?}", unknown_state);
                    println!("current sass rule = {:?}", self.current_sass_rule);
                    self.state = State::Eof;
                },
            }
        }

        Some(TopLevelEvent::Rule(self.current_sass_rule.clone()))
    }

    fn pick_something(&mut self) {
        self.skip_leading_whitespace();

        if self.offset == self.sass.len() {
            self.state = State::Eof;
            return
        }

        let c = self.bytes[self.offset];

        if c == b'}' {
            self.state = State::EndRule;
            return
        }

        if c == b'$' {
            self.state = State::InVariable;
            return
        }

        if c == b'/' && (self.offset + 1) < self.sass.len() {
            let d = self.bytes[self.offset + 1];
            if d == b'*' {
                self.state = State::InComment;
                return
            }
        }

        self.state = State::InSelectors;
    }

    fn scan_while<F>(&mut self, data: &str, f: F) -> usize
            where F: Fn(u8) -> bool {
        match data.as_bytes().iter().position(|&c| !f(c)) {
            Some(i) => i,
            None => data.len()
        }
    }

    fn skip_leading_whitespace(&mut self) {
        let mut i = self.offset;
        let limit = self.sass.len();

        while i < limit {
            let c = self.bytes[i];
            if is_ascii_whitespace(c) {
                i += self.scan_while(&self.sass[i..self.sass.len()], is_ascii_whitespace);
            } else if c == b'/' && i + 1 < limit && self.bytes[i + 1] == b'/' {
                i += self.scan_while(&self.sass[i..self.sass.len()], isnt_newline);
            } else {
                self.offset = i;
                return
            }
        }
        self.offset = limit;
    }

    fn next_comment(&mut self) -> Option<Event<'a>> {
        let comment_body_beginning = self.offset;
        let mut i = comment_body_beginning + 2;
        let limit = self.sass.len();

        while i < limit {
            match self.bytes[i..limit].iter().position(|&c| c == b'*' ) {
                Some(pos) => { i += pos; },
                None => { break; },
            }

            if self.bytes[i+1] == b'/' {
                self.offset = i + 2;
                return Some(Event::Comment(Borrowed(&self.sass[comment_body_beginning..i + 2])))
            } else {
                i += 1;
            }
        }
        None
    }

    fn next_variable(&mut self) -> Option<TopLevelEvent<'a>> {
        // TODO: can parts of this be deduplicated with properties?
        let name_beginning = self.offset;
        let mut i = name_beginning;
        let limit = self.sass.len();

        while i < limit {
            match self.bytes[i..limit].iter().position(|&c| c == b':' ) {
                Some(pos) => { i += pos; },
                None => { break; },
            }

            let name_end = i;

            i += 1;
            self.offset = i;
            self.skip_leading_whitespace();

            let value_beginning = self.offset;
            i = value_beginning;

            while i < limit {
                match self.bytes[i..limit].iter().position(|&c| c == b';') {
                    Some(pos) => { i += pos; },
                    None => { i = limit; break; },
                }

                let value_end = i;
                self.offset = i + 1;

                self.skip_leading_whitespace();

                return Some(TopLevelEvent::Variable(SassVariable{
                    name: Borrowed(&self.sass[name_beginning..name_end]),
                    value: Borrowed(&self.sass[value_beginning..value_end]),
                }))
            }
        }
        self.offset = self.sass.len();
        None
    }

    fn next_property(&mut self) -> Option<Event<'a>> {
        self.skip_leading_whitespace();

        if self.offset == self.sass.len() {
            self.state = State::Eof;
            return None
        }

        let name_beginning = self.offset;
        let mut i = name_beginning;
        let limit = self.sass.len();

        let c = self.bytes[i];
        if c == b'}' {
            self.state = State::EndRule;
            return None
        }

        let d = self.bytes[i + 1];
        if c == b'/' && d == b'*' {
            self.state = State::InComment;
            return None
        }

        while i < limit {
            match self.bytes[i..limit].iter().position(|&c| c == b':' || c == b'{') {
                Some(pos) => { i += pos; },
                None => { break; },
            }

            // Inefficient since we already skipped the whitespace and we'll have to
            // do it again but oh well
            let c = self.bytes[i];
            if c == b'{' {
                self.state = State::InRule;
                return None
            }

            let name_end = i;

            i += 1;
            self.offset = i;
            self.skip_leading_whitespace();

            let value_beginning = self.offset;
            i = value_beginning;

            while i < limit {
                match self.bytes[i..limit].iter().position(|&c| c == b';') {
                    Some(pos) => { i += pos; },
                    None => { i = limit; break; },
                }

                let value_end = i;
                self.offset = i + 1;

                self.skip_leading_whitespace();

                if self.bytes[name_beginning] == b'$' {
                    return Some(Event::Variable(SassVariable {
                        name: Borrowed(&self.sass[name_beginning..name_end]),
                        value: Borrowed(&self.sass[value_beginning..value_end])
                    }))
                } else {
                    return Some(Event::Property(
                        Borrowed(&self.sass[name_beginning..name_end]),
                        Borrowed(&self.sass[value_beginning..value_end])
                    ))
                }
            }
        }
        self.offset = self.sass.len();
        None
    }

    fn next_selector(&mut self) -> Option<SassSelector<'a>> {
        let beginning = self.offset;
        let mut i = beginning;
        let limit = self.sass.len();

        while i < limit {
            match self.bytes[i..limit].iter().position(|&c| c == b',' || c == b'{' || c == b':') {
                Some(pos) => { i += pos; },
                None => { i = limit; break; },
            }

            let c = self.bytes[i];

            if c == b':' {
                self.state = State::InProperties;
                return None
            }

            if c == b',' || c == b'{' {
                let n = scan_trailing_whitespace(&self.sass[beginning..i]);
                let end = i - n;
                if end > beginning {
                    if c == b'{' {
                        if self.current_sass_rule.selectors_done {
                            self.state = State::InRule;
                            return None
                        } else {
                            self.current_sass_rule.selectors_done = true;
                            self.state = State::InProperties;
                        }
                    }
                    self.offset = i + 1;
                    return Some(SassSelector { name: Borrowed(&self.sass[beginning..end]) })
                }
            }

            self.offset = i;
            if i > beginning {
                return Some(SassSelector { name: Borrowed(&self.sass[beginning..i]) })
            }
            i += 1;
        }

        if i > beginning {
            self.offset = i;
            Some(SassSelector { name: Borrowed(&self.sass[beginning..i]) })
        } else {
            self.state = State::Eof;
            None
        }
    }
}

impl<'a> Iterator for Tokenizer<'a> {
    type Item = TopLevelEvent<'a>;

    fn next(&mut self) -> Option<TopLevelEvent<'a>> {
        if self.offset < self.sass.len() {
            return self.start_something()
        }
        None
    }
}
<commit_msg>Stop cloning self.state; use if/else instead of match<commit_after>use event::Event;
use sass::comment::SassComment;
use sass::rule::SassRule;
use sass::selector::SassSelector;
use sass::variable::SassVariable;
use top_level_event::TopLevelEvent;

use std::borrow::Cow::Borrowed;

fn is_ascii_whitespace(c: u8) -> bool {
   is_newline(c) || is_ascii_whitespace_no_nl(c)
}

fn is_ascii_whitespace_no_nl(c: u8) -> bool {
    c == b'\t' || c == 0x0b || c == 0x0c || c == b' '
}

fn is_newline(c: u8) -> bool {
    c == b'\n' || c == b'\r'
}

fn isnt_newline(c: u8) -> bool {
    !is_newline(c)
}

// unusual among "scan" functions in that it scans from the _back_ of the string
// TODO: should also scan unicode whitespace?
fn scan_trailing_whitespace(data: &str) -> usize {
    match data.as_bytes().iter().rev().position(|&c| !is_ascii_whitespace_no_nl(c)) {
        Some(i) => i,
        None => data.len()
    }
}

#[derive(Debug)]
pub struct Tokenizer<'a> {
    sass: &'a str,
    bytes: &'a [u8],
    offset: usize,
    state: State,
    sass_rule_stack: Vec<SassRule<'a>>,
    current_sass_rule: SassRule<'a>,
}

#[derive(PartialEq, Debug, Clone)]
enum State {
    OutsideRules,
    InVariable,
    InComment,
    InRule,
    InSelectors,
    InProperties,
    EndRule,
    Eof,
}

impl<'a> Tokenizer<'a> {
    pub fn new(sass: &'a str) -> Tokenizer<'a> {
        Tokenizer {
            sass: &sass,
            bytes: &sass.as_bytes(),
            offset: 0,
            state: State::OutsideRules,
            sass_rule_stack: Vec::new(),
            current_sass_rule: SassRule::new(),
        }
    }

    fn start_something(&mut self) -> Option<TopLevelEvent<'a>> {
        self.current_sass_rule = SassRule::new();

        self.pick_something();
        while self.state != State::OutsideRules {
            if self.state == State::Eof { return None }

            if self.state == State::InSelectors {
                let sel = self.next_selector();
                if sel.is_some() {
                    self.current_sass_rule.selectors.push(sel.unwrap());
                }
            } else if self.state == State::InProperties {
                let prop = self.next_property();
                if prop.is_some() {
                    self.current_sass_rule.children.push(prop.unwrap());
                }
            } else if self.state == State::EndRule {
                // consume '}', should probably be checking that's what we actually have
                self.offset += 1;

                match self.sass_rule_stack.pop() {
                    Some(ref mut rule) => {
                        rule.children.push(Event::ChildRule(self.current_sass_rule.clone()));
                        self.current_sass_rule = (*rule).clone();
                        self.pick_something();
                    },
                    None => self.state = State::OutsideRules,
                }
            } else if self.state == State::InRule {
                self.sass_rule_stack.push(self.current_sass_rule.clone());
                self.current_sass_rule = SassRule::new();
                self.pick_something();
            } else if self.state == State::InVariable {
                let var = self.next_variable();
                if var.is_some() {
                    return var
                } else {
                    // is this really what we should be doing here? reachable?
                    self.state = State::Eof;
                }
            } else if self.state == State::InComment {
                let comment = self.next_comment();
                if comment.is_some() {
                    if self.sass_rule_stack.len() == 0 &&
                       self.current_sass_rule.selectors.len() == 0 &&
                       self.current_sass_rule.children.len() == 0 {
                           return Some(TopLevelEvent::Comment(SassComment { comment: comment.unwrap() }))
                    } else {
                        self.current_sass_rule.children.push(comment.unwrap());
                        self.pick_something();
                    }
                } else {
                    // is this really what we should be doing here? reachable?
                    self.state = State::Eof;
                }
            } else {
                println!("i dont know what to do for {:?}", self.state);
                println!("current sass rule = {:?}", self.current_sass_rule);
                self.state = State::Eof;
            }
        }

        Some(TopLevelEvent::Rule(self.current_sass_rule.clone()))
    }

    fn pick_something(&mut self) {
        self.skip_leading_whitespace();

        if self.offset == self.sass.len() {
            self.state = State::Eof;
            return
        }

        let c = self.bytes[self.offset];

        if c == b'}' {
            self.state = State::EndRule;
            return
        }

        if c == b'$' {
            self.state = State::InVariable;
            return
        }

        if c == b'/' && (self.offset + 1) < self.sass.len() {
            let d = self.bytes[self.offset + 1];
            if d == b'*' {
                self.state = State::InComment;
                return
            }
        }

        self.state = State::InSelectors;
    }

    fn scan_while<F>(&mut self, data: &str, f: F) -> usize
            where F: Fn(u8) -> bool {
        match data.as_bytes().iter().position(|&c| !f(c)) {
            Some(i) => i,
            None => data.len()
        }
    }

    fn skip_leading_whitespace(&mut self) {
        let mut i = self.offset;
        let limit = self.sass.len();

        while i < limit {
            let c = self.bytes[i];
            if is_ascii_whitespace(c) {
                i += self.scan_while(&self.sass[i..self.sass.len()], is_ascii_whitespace);
            } else if c == b'/' && i + 1 < limit && self.bytes[i + 1] == b'/' {
                i += self.scan_while(&self.sass[i..self.sass.len()], isnt_newline);
            } else {
                self.offset = i;
                return
            }
        }
        self.offset = limit;
    }

    fn next_comment(&mut self) -> Option<Event<'a>> {
        let comment_body_beginning = self.offset;
        let mut i = comment_body_beginning + 2;
        let limit = self.sass.len();

        while i < limit {
            match self.bytes[i..limit].iter().position(|&c| c == b'*' ) {
                Some(pos) => { i += pos; },
                None => { break; },
            }

            if self.bytes[i+1] == b'/' {
                self.offset = i + 2;
                return Some(Event::Comment(Borrowed(&self.sass[comment_body_beginning..i + 2])))
            } else {
                i += 1;
            }
        }
        None
    }

    fn next_variable(&mut self) -> Option<TopLevelEvent<'a>> {
        // TODO: can parts of this be deduplicated with properties?
        let name_beginning = self.offset;
        let mut i = name_beginning;
        let limit = self.sass.len();

        while i < limit {
            match self.bytes[i..limit].iter().position(|&c| c == b':' ) {
                Some(pos) => { i += pos; },
                None => { break; },
            }

            let name_end = i;

            i += 1;
            self.offset = i;
            self.skip_leading_whitespace();

            let value_beginning = self.offset;
            i = value_beginning;

            while i < limit {
                match self.bytes[i..limit].iter().position(|&c| c == b';') {
                    Some(pos) => { i += pos; },
                    None => { i = limit; break; },
                }

                let value_end = i;
                self.offset = i + 1;

                self.skip_leading_whitespace();

                return Some(TopLevelEvent::Variable(SassVariable{
                    name: Borrowed(&self.sass[name_beginning..name_end]),
                    value: Borrowed(&self.sass[value_beginning..value_end]),
                }))
            }
        }
        self.offset = self.sass.len();
        None
    }

    fn next_property(&mut self) -> Option<Event<'a>> {
        self.skip_leading_whitespace();

        if self.offset == self.sass.len() {
            self.state = State::Eof;
            return None
        }

        let name_beginning = self.offset;
        let mut i = name_beginning;
        let limit = self.sass.len();

        let c = self.bytes[i];
        if c == b'}' {
            self.state = State::EndRule;
            return None
        }

        let d = self.bytes[i + 1];
        if c == b'/' && d == b'*' {
            self.state = State::InComment;
            return None
        }

        while i < limit {
            match self.bytes[i..limit].iter().position(|&c| c == b':' || c == b'{') {
                Some(pos) => { i += pos; },
                None => { break; },
            }

            // Inefficient since we already skipped the whitespace and we'll have to
            // do it again but oh well
            let c = self.bytes[i];
            if c == b'{' {
                self.state = State::InRule;
                return None
            }

            let name_end = i;

            i += 1;
            self.offset = i;
            self.skip_leading_whitespace();

            let value_beginning = self.offset;
            i = value_beginning;

            while i < limit {
                match self.bytes[i..limit].iter().position(|&c| c == b';') {
                    Some(pos) => { i += pos; },
                    None => { i = limit; break; },
                }

                let value_end = i;
                self.offset = i + 1;

                self.skip_leading_whitespace();

                if self.bytes[name_beginning] == b'$' {
                    return Some(Event::Variable(SassVariable {
                        name: Borrowed(&self.sass[name_beginning..name_end]),
                        value: Borrowed(&self.sass[value_beginning..value_end])
                    }))
                } else {
                    return Some(Event::Property(
                        Borrowed(&self.sass[name_beginning..name_end]),
                        Borrowed(&self.sass[value_beginning..value_end])
                    ))
                }
            }
        }
        self.offset = self.sass.len();
        None
    }

    fn next_selector(&mut self) -> Option<SassSelector<'a>> {
        let beginning = self.offset;
        let mut i = beginning;
        let limit = self.sass.len();

        while i < limit {
            match self.bytes[i..limit].iter().position(|&c| c == b',' || c == b'{' || c == b':') {
                Some(pos) => { i += pos; },
                None => { i = limit; break; },
            }

            let c = self.bytes[i];

            if c == b':' {
                self.state = State::InProperties;
                return None
            }

            if c == b',' || c == b'{' {
                let n = scan_trailing_whitespace(&self.sass[beginning..i]);
                let end = i - n;
                if end > beginning {
                    if c == b'{' {
                        if self.current_sass_rule.selectors_done {
                            self.state = State::InRule;
                            return None
                        } else {
                            self.current_sass_rule.selectors_done = true;
                            self.state = State::InProperties;
                        }
                    }
                    self.offset = i + 1;
                    return Some(SassSelector { name: Borrowed(&self.sass[beginning..end]) })
                }
            }

            self.offset = i;
            if i > beginning {
                return Some(SassSelector { name: Borrowed(&self.sass[beginning..i]) })
            }
            i += 1;
        }

        if i > beginning {
            self.offset = i;
            Some(SassSelector { name: Borrowed(&self.sass[beginning..i]) })
        } else {
            self.state = State::Eof;
            None
        }
    }
}

impl<'a> Iterator for Tokenizer<'a> {
    type Item = TopLevelEvent<'a>;

    fn next(&mut self) -> Option<TopLevelEvent<'a>> {
        if self.offset < self.sass.len() {
            return self.start_something()
        }
        None
    }
}
<|endoftext|>


<commit_before>/// The tokenizer for the query interpreter

use error::*;

#[derive(Debug, PartialEq, Eq)]
pub enum Token {
    Identifier {
        ident: String,
        next: Option<Box<Token>>
    },

    Index {
        idx: usize,
        next: Option<Box<Token>>
    }
}

impl Token {

    pub fn next(&self) -> Option<&Box<Token>> {
        match self {
            &Token::Identifier { ref next, .. } => next.as_ref(),
            &Token::Index { ref next, .. }      => next.as_ref(),
        }
    }

    pub fn set_next(&mut self, token: Token) {
        match self {
            &mut Token::Identifier { ref mut next, .. } => *next = Some(Box::new(token)),
            &mut Token::Index { ref mut next, .. }      => *next = Some(Box::new(token)),
        }
    }

    /// Pop the last token from the chain of tokens
    ///
    /// Returns None if the current Token has no next token
    pub fn pop_last(&mut self) -> Option<Box<Token>> {
        if !self.has_next() {
            None
        } else {
            match self {
                &mut Token::Identifier { next: ref mut next, .. } => {
                    next.take()
                },

                &mut Token::Index { next: ref mut next, .. } => {
                    next.take()
                },
            }
        }
    }

    #[cfg(test)]
    pub fn identifier(&self) -> &String {
        match self {
            &Token::Identifier { ref ident, .. } => &ident,
            _ => unreachable!(),
        }
    }

}

pub fn tokenize_with_seperator(query: &String, seperator: char) -> Result<Token> {
    use std::str::Split;

    /// Creates a Token object from a string
    ///
    /// # Panics
    ///
    /// * If the internal regex does not compile (should never happen)
    /// * If the token is non-valid (that is, a array index with a non-i64)
    /// * If the regex does not find anything
    /// * If the integer in the brackets (`[]`) cannot be parsed to a valid i64
    ///
    /// # Incorrect behaviour
    ///
    /// * If the regex finds multiple captures
    ///
    /// # Returns
    ///
    /// The `Token` object with the correct identifier/index for this token and no next token.
    ///
    fn mk_token_object(s: &str) -> Result<Token> {
        use regex::Regex;
        use std::str::FromStr;

        lazy_static! {
            static ref RE: Regex = Regex::new(r"^\[\d+\]$").unwrap();
        }

        if !has_array_brackets(s) {
            return Ok(Token::Identifier { ident: String::from(s), next: None });
        }

        match RE.captures(s) {
            None => return Err(Error::from(ErrorKind::ArrayAccessWithoutIndex)),
            Some(captures) => {
                match captures.get(0) {
                    None => Ok(Token::Identifier { ident: String::from(s), next: None }),
                    Some(mtch) => {
                        let mtch = without_array_brackets(mtch.as_str());
                        let i : usize = FromStr::from_str(&mtch).unwrap(); // save because regex
                        Ok(Token::Index {
                            idx: i,
                            next: None,
                        })
                    }
                }
            }
        }
    }

    /// Check whether a str begins with '[' and ends with ']'
    fn has_array_brackets(s: &str) -> bool {
        s.as_bytes()[0] == b'[' && s.as_bytes()[s.len() - 1] == b']'
    }

    /// Remove '[' and ']' from a str
    fn without_array_brackets(s: &str) -> String {
        s.replace("[","").replace("]","")
    }

    fn build_token_tree(split: &mut Split<char>, last: &mut Token) -> Result<()> {
        match split.next() {
            None        => { /* No more tokens */ }
            Some(token) => {
                if token.len() == 0 {
                    return Err(Error::from(ErrorKind::EmptyIdentifier));
                }
                let mut token = try!(mk_token_object(token));
                try!(build_token_tree(split, &mut token));
                last.set_next(token);
            }
        }
        Ok(())
    }

    if query.is_empty() {
        return Err(Error::from(ErrorKind::EmptyQueryError));
    }

    let mut tokens = query.split(seperator);

    match tokens.next() {
        None        => Err(Error::from(ErrorKind::EmptyQueryError)),
        Some(token) => {
            if token.len() == 0 {
                return Err(Error::from(ErrorKind::EmptyIdentifier));
            }
            let mut tok = try!(mk_token_object(token));
            let _       = try!(build_token_tree(&mut tokens, &mut tok));
            Ok(tok)
        }
    }
}

#[cfg(test)]
mod test {
    use error::ErrorKind;
    use super::*;

    use std::ops::Deref;

    #[test]
    fn test_tokenize_empty_query_to_error() {
        let tokens = tokenize_with_seperator(&String::from(""), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::EmptyQueryError { .. }));
    }

    #[test]
    fn test_tokenize_seperator_only() {
        let tokens = tokenize_with_seperator(&String::from("."), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::EmptyIdentifier { .. }));
    }

    #[test]
    fn test_tokenize_array_brackets_only() {
        let tokens = tokenize_with_seperator(&String::from("[]"), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::ArrayAccessWithoutIndex { .. }));
    }

    #[test]
    fn test_tokenize_identifiers_with_array_brackets_only() {
        let tokens = tokenize_with_seperator(&String::from("a.b.c.[]"), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::ArrayAccessWithoutIndex { .. }));
    }

    #[test]
    fn test_tokenize_identifiers_in_array_brackets() {
        let tokens = tokenize_with_seperator(&String::from("[a]"), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::ArrayAccessWithoutIndex { .. }));
    }

    #[test]
    fn test_tokenize_single_token_query() {
        let tokens = tokenize_with_seperator(&String::from("example"), '.');
        assert!(tokens.is_ok());
        let tokens = tokens.unwrap();

        assert!(match tokens {
            Token::Identifier { ref ident, next: None } => {
                assert_eq!("example", ident);
                true
            },
            _ => false,
        });
    }

    #[test]
    fn test_tokenize_double_token_query() {
        let tokens = tokenize_with_seperator(&String::from("a.b"), '.');
        assert!(tokens.is_ok());
        let tokens = tokens.unwrap();

        assert!(match tokens {
            Token::Identifier { next: Some(ref next), .. } => {
                assert_eq!("b", next.deref().identifier());
                match next.deref() {
                    &Token::Identifier { next: None, .. } => true,
                    _ => false
                }
            },
            _ => false,
        });
        assert_eq!("a", tokens.identifier());
    }

    #[test]
    fn test_tokenize_ident_then_array_query() {
        let tokens = tokenize_with_seperator(&String::from("a.[0]"), '.');
        assert!(tokens.is_ok());
        let tokens = tokens.unwrap();

        assert_eq!("a", tokens.identifier());
        assert!(match tokens {
            Token::Identifier { next: Some(ref next), .. } => {
                match next.deref() {
                    &Token::Index { idx: 0, next: None } => true,
                    _ => false
                }
            },
            _ => false,
        });
    }

    #[test]
    fn test_tokenize_many_idents_then_array_query() {
        let tokens = tokenize_with_seperator(&String::from("a.b.c.[1000]"), '.');
        assert!(tokens.is_ok());
        let tokens = tokens.unwrap();

        assert_eq!("a", tokens.identifier());

        let expected =
            Token::Identifier {
                ident: String::from("a"),
                next: Some(Box::new(Token::Identifier {
                    ident: String::from("b"),
                    next: Some(Box::new(Token::Identifier {
                        ident: String::from("c"),
                        next: Some(Box::new(Token::Index {
                            idx: 1000,
                            next: None,
                        })),
                    })),
                })),
            };

        assert_eq!(expected, tokens);
    }

    #[test]
    fn test_tokenize_empty_token_after_good_token() {
        let tokens = tokenize_with_seperator(&String::from("a..b"), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::EmptyIdentifier { .. }));
    }

    quickcheck! {
        fn test_array_index(i: usize) -> bool {
            match tokenize_with_seperator(&format!("[{}]", i), '.') {
                Ok(Token::Index { next: None, ..  }) => true,
                _                                    => false,
            }
        }
    }

    #[test]
    fn test_pop_last_token_from_single_identifier_token_is_none() {
        let mut token = Token::Identifier {
            ident: String::from("something"),
            next: None,
        };

        let last = token.pop_last();
        assert!(last.is_none());
    }

    #[test]
    fn test_pop_last_token_from_single_index_token_is_none() {
        let mut token = Token::Index {
            idx: 0,
            next: None,
        };

        let last = token.pop_last();
        assert!(last.is_none());
    }

    #[test]
    fn test_pop_last_token_from_single_identifier_token_is_one() {
        let mut token = Token::Identifier {
            ident: String::from("some"),
            next: Some(Box::new(Token::Identifier {
                ident: String::from("thing"),
                next: None,
            })),
        };

        let last = token.pop_last();

        assert!(last.is_some());
        let last = last.unwrap();

        assert!(is_match!(*last, Token::Identifier { .. }));
        match *last {
            Token::Identifier { ident: ident, .. } => {
                assert_eq!("thing", ident);
            }
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_pop_last_token_from_single_index_token_is_one() {
        let mut token = Token::Index {
            idx: 0,
            next: Some(Box::new(Token::Index {
                idx: 1,
                next: None,
            })),
        };

        let last = token.pop_last();

        assert!(last.is_some());
        let last = last.unwrap();

        assert!(is_match!(*last, Token::Index { idx: 1, .. }));
    }

    #[test]
    fn test_pop_last_token_from_identifier_chain() {
        let tokens = tokenize_with_seperator(&String::from("a.b.c.d.e.f"), '.');
        assert!(tokens.is_ok());
        let mut tokens = tokens.unwrap();

        let last = tokens.pop_last();
        assert!(last.is_some());
        assert_eq!("f", last.unwrap().identifier());
    }

    #[test]
    fn test_pop_last_token_from_mixed_chain() {
        let tokens = tokenize_with_seperator(&String::from("a.[100].c.[3].e.f"), '.');
        assert!(tokens.is_ok());
        let mut tokens = tokens.unwrap();

        let last = tokens.pop_last();
        assert!(last.is_some());
        assert_eq!("f", last.unwrap().identifier());
    }

    #[test]
    fn test_pop_last_token_from_identifier_chain_is_array() {
        let tokens = tokenize_with_seperator(&String::from("a.b.c.d.e.f.[1000]"), '.');
        assert!(tokens.is_ok());
        let mut tokens = tokens.unwrap();

        let last = tokens.pop_last();
        assert!(last.is_some());
        assert_eq!(1000, last.unwrap().idx());
    }

    #[test]
    fn test_pop_last_token_from_mixed_chain_is_array() {
        let tokens = tokenize_with_seperator(&String::from("a.[100].c.[3].e.f.[1000]"), '.');
        assert!(tokens.is_ok());
        let mut tokens = tokens.unwrap();

        let last = tokens.pop_last();
        assert!(last.is_some());
        assert_eq!(1000, last.unwrap().idx());
    }

    #[test]
    fn test_pop_last_token_from_one_token() {
        let tokens = tokenize_with_seperator(&String::from("a"), '.');
        assert!(tokens.is_ok());
        let mut tokens = tokens.unwrap();

        let last = tokens.pop_last();
        assert!(last.is_none());
    }

}
<commit_msg>Revert "Remove unused function"<commit_after>/// The tokenizer for the query interpreter

use error::*;

#[derive(Debug, PartialEq, Eq)]
pub enum Token {
    Identifier {
        ident: String,
        next: Option<Box<Token>>
    },

    Index {
        idx: usize,
        next: Option<Box<Token>>
    }
}

impl Token {

    pub fn next(&self) -> Option<&Box<Token>> {
        match self {
            &Token::Identifier { ref next, .. } => next.as_ref(),
            &Token::Index { ref next, .. }      => next.as_ref(),
        }
    }

    /// Convenience function for `token.next().is_some()`
    pub fn has_next(&self) -> bool {
        self.next().is_some()
    }

    pub fn set_next(&mut self, token: Token) {
        match self {
            &mut Token::Identifier { ref mut next, .. } => *next = Some(Box::new(token)),
            &mut Token::Index { ref mut next, .. }      => *next = Some(Box::new(token)),
        }
    }

    /// Pop the last token from the chain of tokens
    ///
    /// Returns None if the current Token has no next token
    pub fn pop_last(&mut self) -> Option<Box<Token>> {
        if !self.has_next() {
            None
        } else {
            match self {
                &mut Token::Identifier { next: ref mut next, .. } => {
                    next.take()
                },

                &mut Token::Index { next: ref mut next, .. } => {
                    next.take()
                },
            }
        }
    }

    #[cfg(test)]
    pub fn identifier(&self) -> &String {
        match self {
            &Token::Identifier { ref ident, .. } => &ident,
            _ => unreachable!(),
        }
    }

}

pub fn tokenize_with_seperator(query: &String, seperator: char) -> Result<Token> {
    use std::str::Split;

    /// Creates a Token object from a string
    ///
    /// # Panics
    ///
    /// * If the internal regex does not compile (should never happen)
    /// * If the token is non-valid (that is, a array index with a non-i64)
    /// * If the regex does not find anything
    /// * If the integer in the brackets (`[]`) cannot be parsed to a valid i64
    ///
    /// # Incorrect behaviour
    ///
    /// * If the regex finds multiple captures
    ///
    /// # Returns
    ///
    /// The `Token` object with the correct identifier/index for this token and no next token.
    ///
    fn mk_token_object(s: &str) -> Result<Token> {
        use regex::Regex;
        use std::str::FromStr;

        lazy_static! {
            static ref RE: Regex = Regex::new(r"^\[\d+\]$").unwrap();
        }

        if !has_array_brackets(s) {
            return Ok(Token::Identifier { ident: String::from(s), next: None });
        }

        match RE.captures(s) {
            None => return Err(Error::from(ErrorKind::ArrayAccessWithoutIndex)),
            Some(captures) => {
                match captures.get(0) {
                    None => Ok(Token::Identifier { ident: String::from(s), next: None }),
                    Some(mtch) => {
                        let mtch = without_array_brackets(mtch.as_str());
                        let i : usize = FromStr::from_str(&mtch).unwrap(); // save because regex
                        Ok(Token::Index {
                            idx: i,
                            next: None,
                        })
                    }
                }
            }
        }
    }

    /// Check whether a str begins with '[' and ends with ']'
    fn has_array_brackets(s: &str) -> bool {
        s.as_bytes()[0] == b'[' && s.as_bytes()[s.len() - 1] == b']'
    }

    /// Remove '[' and ']' from a str
    fn without_array_brackets(s: &str) -> String {
        s.replace("[","").replace("]","")
    }

    fn build_token_tree(split: &mut Split<char>, last: &mut Token) -> Result<()> {
        match split.next() {
            None        => { /* No more tokens */ }
            Some(token) => {
                if token.len() == 0 {
                    return Err(Error::from(ErrorKind::EmptyIdentifier));
                }
                let mut token = try!(mk_token_object(token));
                try!(build_token_tree(split, &mut token));
                last.set_next(token);
            }
        }
        Ok(())
    }

    if query.is_empty() {
        return Err(Error::from(ErrorKind::EmptyQueryError));
    }

    let mut tokens = query.split(seperator);

    match tokens.next() {
        None        => Err(Error::from(ErrorKind::EmptyQueryError)),
        Some(token) => {
            if token.len() == 0 {
                return Err(Error::from(ErrorKind::EmptyIdentifier));
            }
            let mut tok = try!(mk_token_object(token));
            let _       = try!(build_token_tree(&mut tokens, &mut tok));
            Ok(tok)
        }
    }
}

#[cfg(test)]
mod test {
    use error::ErrorKind;
    use super::*;

    use std::ops::Deref;

    #[test]
    fn test_tokenize_empty_query_to_error() {
        let tokens = tokenize_with_seperator(&String::from(""), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::EmptyQueryError { .. }));
    }

    #[test]
    fn test_tokenize_seperator_only() {
        let tokens = tokenize_with_seperator(&String::from("."), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::EmptyIdentifier { .. }));
    }

    #[test]
    fn test_tokenize_array_brackets_only() {
        let tokens = tokenize_with_seperator(&String::from("[]"), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::ArrayAccessWithoutIndex { .. }));
    }

    #[test]
    fn test_tokenize_identifiers_with_array_brackets_only() {
        let tokens = tokenize_with_seperator(&String::from("a.b.c.[]"), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::ArrayAccessWithoutIndex { .. }));
    }

    #[test]
    fn test_tokenize_identifiers_in_array_brackets() {
        let tokens = tokenize_with_seperator(&String::from("[a]"), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::ArrayAccessWithoutIndex { .. }));
    }

    #[test]
    fn test_tokenize_single_token_query() {
        let tokens = tokenize_with_seperator(&String::from("example"), '.');
        assert!(tokens.is_ok());
        let tokens = tokens.unwrap();

        assert!(match tokens {
            Token::Identifier { ref ident, next: None } => {
                assert_eq!("example", ident);
                true
            },
            _ => false,
        });
    }

    #[test]
    fn test_tokenize_double_token_query() {
        let tokens = tokenize_with_seperator(&String::from("a.b"), '.');
        assert!(tokens.is_ok());
        let tokens = tokens.unwrap();

        assert!(match tokens {
            Token::Identifier { next: Some(ref next), .. } => {
                assert_eq!("b", next.deref().identifier());
                match next.deref() {
                    &Token::Identifier { next: None, .. } => true,
                    _ => false
                }
            },
            _ => false,
        });
        assert_eq!("a", tokens.identifier());
    }

    #[test]
    fn test_tokenize_ident_then_array_query() {
        let tokens = tokenize_with_seperator(&String::from("a.[0]"), '.');
        assert!(tokens.is_ok());
        let tokens = tokens.unwrap();

        assert_eq!("a", tokens.identifier());
        assert!(match tokens {
            Token::Identifier { next: Some(ref next), .. } => {
                match next.deref() {
                    &Token::Index { idx: 0, next: None } => true,
                    _ => false
                }
            },
            _ => false,
        });
    }

    #[test]
    fn test_tokenize_many_idents_then_array_query() {
        let tokens = tokenize_with_seperator(&String::from("a.b.c.[1000]"), '.');
        assert!(tokens.is_ok());
        let tokens = tokens.unwrap();

        assert_eq!("a", tokens.identifier());

        let expected =
            Token::Identifier {
                ident: String::from("a"),
                next: Some(Box::new(Token::Identifier {
                    ident: String::from("b"),
                    next: Some(Box::new(Token::Identifier {
                        ident: String::from("c"),
                        next: Some(Box::new(Token::Index {
                            idx: 1000,
                            next: None,
                        })),
                    })),
                })),
            };

        assert_eq!(expected, tokens);
    }

    #[test]
    fn test_tokenize_empty_token_after_good_token() {
        let tokens = tokenize_with_seperator(&String::from("a..b"), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::EmptyIdentifier { .. }));
    }

    quickcheck! {
        fn test_array_index(i: usize) -> bool {
            match tokenize_with_seperator(&format!("[{}]", i), '.') {
                Ok(Token::Index { next: None, ..  }) => true,
                _                                    => false,
            }
        }
    }

    #[test]
    fn test_pop_last_token_from_single_identifier_token_is_none() {
        let mut token = Token::Identifier {
            ident: String::from("something"),
            next: None,
        };

        let last = token.pop_last();
        assert!(last.is_none());
    }

    #[test]
    fn test_pop_last_token_from_single_index_token_is_none() {
        let mut token = Token::Index {
            idx: 0,
            next: None,
        };

        let last = token.pop_last();
        assert!(last.is_none());
    }

    #[test]
    fn test_pop_last_token_from_single_identifier_token_is_one() {
        let mut token = Token::Identifier {
            ident: String::from("some"),
            next: Some(Box::new(Token::Identifier {
                ident: String::from("thing"),
                next: None,
            })),
        };

        let last = token.pop_last();

        assert!(last.is_some());
        let last = last.unwrap();

        assert!(is_match!(*last, Token::Identifier { .. }));
        match *last {
            Token::Identifier { ident: ident, .. } => {
                assert_eq!("thing", ident);
            }
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_pop_last_token_from_single_index_token_is_one() {
        let mut token = Token::Index {
            idx: 0,
            next: Some(Box::new(Token::Index {
                idx: 1,
                next: None,
            })),
        };

        let last = token.pop_last();

        assert!(last.is_some());
        let last = last.unwrap();

        assert!(is_match!(*last, Token::Index { idx: 1, .. }));
    }

    #[test]
    fn test_pop_last_token_from_identifier_chain() {
        let tokens = tokenize_with_seperator(&String::from("a.b.c.d.e.f"), '.');
        assert!(tokens.is_ok());
        let mut tokens = tokens.unwrap();

        let last = tokens.pop_last();
        assert!(last.is_some());
        assert_eq!("f", last.unwrap().identifier());
    }

    #[test]
    fn test_pop_last_token_from_mixed_chain() {
        let tokens = tokenize_with_seperator(&String::from("a.[100].c.[3].e.f"), '.');
        assert!(tokens.is_ok());
        let mut tokens = tokens.unwrap();

        let last = tokens.pop_last();
        assert!(last.is_some());
        assert_eq!("f", last.unwrap().identifier());
    }

    #[test]
    fn test_pop_last_token_from_identifier_chain_is_array() {
        let tokens = tokenize_with_seperator(&String::from("a.b.c.d.e.f.[1000]"), '.');
        assert!(tokens.is_ok());
        let mut tokens = tokens.unwrap();

        let last = tokens.pop_last();
        assert!(last.is_some());
        assert_eq!(1000, last.unwrap().idx());
    }

    #[test]
    fn test_pop_last_token_from_mixed_chain_is_array() {
        let tokens = tokenize_with_seperator(&String::from("a.[100].c.[3].e.f.[1000]"), '.');
        assert!(tokens.is_ok());
        let mut tokens = tokens.unwrap();

        let last = tokens.pop_last();
        assert!(last.is_some());
        assert_eq!(1000, last.unwrap().idx());
    }

    #[test]
    fn test_pop_last_token_from_one_token() {
        let tokens = tokenize_with_seperator(&String::from("a"), '.');
        assert!(tokens.is_ok());
        let mut tokens = tokens.unwrap();

        let last = tokens.pop_last();
        assert!(last.is_none());
    }

}
<|endoftext|>


<commit_before>use std::comm::SharedChan;

fn main() {
    let (port, chan): (Port<int>, Chan<int>) = stream();
    let chan = SharedChan::new(chan);

    let docs: ~[~str] = ~[~"hello world", ~"hello guys", ~"world"];

    fn mapper(doc: ~str) -> ~[(~str, ~str)]{
        let words: ~[~str] = doc.split_iter(' ')
            .filter(|&x| x != "")
            .map(|x| {
                x.to_owned()
            }).collect();

        let mut ret: ~[(~str, ~str)] = ~[];
        for w in words.iter() {
//            println(w.to_str() + ", 1");
            let tup: (~str, ~str) = (w.to_str(), ~"1");
            ret.push(tup);
        }

        ret
    }

    fn reducer(key: ~str, vals: ~[~str]) {

    }

    docs.mapreduce(mapper, reducer);

    let vals = [40, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10];
    for i in range(0, vals.len()) {
        let child_chan = chan.clone();
        do spawn {
            let res = fib(vals[i]);
            print("("+i.to_str()+")");
            child_chan.send(res);
        }
    }

    let mut result = 0;
    for i in range(0, vals.len()) {
        result += port.recv();
    }

    println("\nresult: "+result.to_str());
}

fn fib(n: int) -> int {
    match n {
        1 => 1,
        2 => 1,
        _ => fib(n-1) + fib(n-2)
    }
}

//fn mapreduce(mapper : extern fn(~str), reducer : extern fn(~str, ~[~str]) ) {

trait MapReduce {
    fn mapreduce( &self, extern fn(~str) -> ~[(~str, ~str)], extern fn(~str, ~[~str]) );
}

impl MapReduce for ~[~str] {
    fn mapreduce( &self, mapper: extern fn(~str) -> ~[(~str, ~str)], reducer: extern fn(~str, ~[~str]) ) {
        println("map reducing!!");
        for doc in self.iter() {
            let ivals: ~[(~str, ~str)] = mapper(doc.to_owned());
            println(fmt!("%?", ivals));
        }
    }
}<commit_msg>working on intermediate steps<commit_after>use std::comm::SharedChan;
use std::hashmap::HashMap;

fn main() {
    let (port, chan): (Port<int>, Chan<int>) = stream();
    let chan = SharedChan::new(chan);

    let docs: ~[~str] = ~[~"hello world", ~"hello guys", ~"world"];

    fn mapper(doc: ~str) -> ~[(~str, ~str)] {
        let words: ~[~str] = doc.split_iter(' ')
            .filter(|&x| x != "")
            .map(|x| {
                x.to_owned()
            }).collect();

        let mut ret: ~[(~str, ~str)] = ~[];
        for w in words.iter() {
//            println(w.to_str() + ", 1");
            let tup: (~str, ~str) = (w.to_str(), ~"1");
            ret.push(tup);
        }

        ret
    }

    fn reducer(key: ~str, vals: ~[~str]) {

    }

    docs.mapreduce(mapper, reducer);

    let vals = [40, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10];
    for i in range(0, vals.len()) {
        let child_chan = chan.clone();
        do spawn {
            let res = fib(vals[i]);
            print("("+i.to_str()+")");
            child_chan.send(res);
        }
    }

    let mut result = 0;
    for i in range(0, vals.len()) {
        result += port.recv();
    }

    println("\nresult: "+result.to_str());
}

fn fib(n: int) -> int {
    match n {
        1 => 1,
        2 => 1,
        _ => fib(n-1) + fib(n-2)
    }
}

//fn mapreduce(mapper : extern fn(~str), reducer : extern fn(~str, ~[~str]) ) {

trait MapReduce {
    fn mapreduce( &self, extern fn(~str) -> ~[(~str, ~str)], extern fn(~str, ~[~str]) );
}

impl MapReduce for ~[~str] {
    fn mapreduce( &self, mapper: extern fn(~str) -> ~[(~str, ~str)], reducer: extern fn(~str, ~[~str]) ) {
        println("map reducing!!");
        let (port, chan): (Port<~[(~str, ~str)]>, Chan<~[(~str, ~str)]>) = stream();
        let chan = SharedChan::new(chan);
        let mut chans: int = 0;
        for doc in self.iter() {
            let child_chan = chan.clone();
            let doc_owned = doc.to_owned();
            chans += 1;
            do spawn {
                let ivals: ~[(~str, ~str)] = mapper(doc_owned.clone());
                child_chan.send(ivals);
            }
        }

        let mut key_vals_map: HashMap<~str, ~[~str]> = HashMap::new();
        for _ in range(0, chans) {
            let ivals: ~[(~str, ~str)] = port.recv();
//            println(fmt!("%?", ivals));

//            let mut argv: ~[~str] = ivals.map(|x| x.to_owned()).collect();

            for ival in ivals.iter() {
                println(fmt!("%?", ival));

            }
        }
    }
}<|endoftext|>


<commit_before>//! oracle metadata fetcher

use retry;
use metadata;
use errors::*;

use openssh_keys::PublicKey;

#[derive(Debug, Deserialize, Clone)]
struct InstanceData {
    #[serde(rename = "availabilityDomain")]
    availability_domain: String,
    #[serde(rename = "compartmentId")]
    compartment_id: String,
    #[serde(rename = "displayName")]
    display_name: String,
    id: String,
    image: String,
    region: String,
    shape: String,
    #[serde(rename = "timeCreated")]
    time_created: u64,
    metadata: Metadata,
}

#[derive(Debug, Deserialize, Clone)]
struct Metadata {
    ssh_authorized_keys: String,
}

pub fn fetch_metadata() -> Result<metadata::Metadata> {
    let client = retry::Client::new()
        .chain_err(|| "oracle: failed to create http client")?;

    let data: InstanceData = client.get(retry::Json, "http://169.254.169.254/opc/v1/instance/".into()).send()
        .chain_err(|| "oracle: failed to get instance metadata from metadata service")?
        .ok_or_else(|| "oracle: failed to get instance metadata from metadata service: no response")?;

    let ssh_keys = PublicKey::read_keys(data.metadata.ssh_authorized_keys.as_bytes())?;

    Ok(metadata::Metadata::builder()
        .add_attribute("ORACLE_OCI_DISPLAY_NAME".into(), data.display_name)
        .add_attribute("ORACLE_OCI_INSTANCE_ID".into(), data.id)
        .add_attribute("ORACLE_OCI_REGION".into(), data.region)
        .add_publickeys(ssh_keys)
        .build())
}
<commit_msg>providers/oracle: use default when key is missing<commit_after>//! oracle metadata fetcher

use retry;
use metadata;
use errors::*;

use openssh_keys::PublicKey;

#[derive(Debug, Deserialize, Clone)]
struct InstanceData {
    #[serde(rename = "availabilityDomain")]
    availability_domain: String,
    #[serde(rename = "compartmentId")]
    compartment_id: String,
    #[serde(rename = "displayName")]
    display_name: String,
    id: String,
    image: String,
    region: String,
    shape: String,
    #[serde(rename = "timeCreated")]
    time_created: u64,
    metadata: Metadata,
}

#[derive(Debug, Deserialize, Clone)]
struct Metadata {
    #[serde(default)]
    ssh_authorized_keys: String,
}

pub fn fetch_metadata() -> Result<metadata::Metadata> {
    let client = retry::Client::new()
        .chain_err(|| "oracle: failed to create http client")?;

    let data: InstanceData = client.get(retry::Json, "http://169.254.169.254/opc/v1/instance/".into()).send()
        .chain_err(|| "oracle: failed to get instance metadata from metadata service")?
        .ok_or_else(|| "oracle: failed to get instance metadata from metadata service: no response")?;

    let ssh_keys = PublicKey::read_keys(data.metadata.ssh_authorized_keys.as_bytes())?;

    Ok(metadata::Metadata::builder()
        .add_attribute("ORACLE_OCI_DISPLAY_NAME".into(), data.display_name)
        .add_attribute("ORACLE_OCI_INSTANCE_ID".into(), data.id)
        .add_attribute("ORACLE_OCI_REGION".into(), data.region)
        .add_publickeys(ssh_keys)
        .build())
}
<|endoftext|>


<commit_before>extern crate rustc_serialize;

use rustc_serialize::base64::{self, ToBase64};
use rustc_serialize::hex::FromHex;

use std::fs::File;
use std::fs;
use std::io::{Error, ErrorKind};
use std::io::Read;

pub fn imgcat(path: &str, width: usize) -> String {
    let mut f = match File::open(path) {
        Err(why) => panic!("couldn't open: {}", why),
        Ok(file) => file,
    };
    let mut buffer = Vec::new();
    f.read_to_end(&mut buffer);

    let e = buffer.as_slice().to_base64(base64::STANDARD);
    return String::from(format!("\x1b]1337;File=inline=1;width={width};:{code}\x07\x0a", width = width, code = e));
}
<commit_msg>imgcat - remove newline<commit_after>extern crate rustc_serialize;

use rustc_serialize::base64::{self, ToBase64};
use rustc_serialize::hex::FromHex;

use std::fs::File;
use std::fs;
use std::io::{Error, ErrorKind};
use std::io::Read;

pub fn imgcat(path: &str, width: usize) -> String {
    let mut f = match File::open(path) {
        Err(why) => panic!("couldn't open: {}", why),
        Ok(file) => file,
    };
    let mut buffer = Vec::new();
    f.read_to_end(&mut buffer);

    let e = buffer.as_slice().to_base64(base64::STANDARD);
    return String::from(format!("\x1b]1337;File=inline=1;width={width};:{code}\x07", width = width,  code = e));
}
<|endoftext|>