<commit_before>use bytes::Bytes;
use error::{Error, HyperError};
use futures::{Async, Future, Poll, Stream};
use futures::stream::Fuse;
use std::error;
use std::fmt::{self, Display, Formatter};
use std::time::Duration;
use tokio_core::reactor::{Handle, Timeout};

// Synonym of `twitter_stream_message::util::string_enums`
macro_rules! string_enums {
    (
        $(
            $(#[$attr:meta])*
            pub enum $E:ident {
                $(
                    $(#[$v_attr:meta])*
                    :$V:ident($by:expr) // The leading (ugly) colon is to suppress local ambiguity error.
                ),*;
                $(#[$u_attr:meta])*
                :$U:ident(_),
            }
        )*
    ) => {
        $(
            $(#[$attr])*
            pub enum $E {
                $(
                    $(#[$v_attr])*
                    $V,
                )*
                $(#[$u_attr])*
                $U(String),
            }

            impl ::std::convert::AsRef<str> for $E {
                fn as_ref(&self) -> &str {
                    match *self {
                        $($E::$V => $by,)*
                        $E::$U(ref s) => s,
                    }
                }
            }

            impl ::std::cmp::PartialEq for $E {
                fn eq(&self, other: &$E) -> bool {
                    match *self {
                        $($E::$V => match *other {
                            $E::$V => true,
                            $E::$U(ref s) if $by == s => true,
                            _ => false,
                        },)*
                        $E::$U(ref s) => match *other {
                            $($E::$V => $by == s,)*
                            $E::$U(ref t) => s == t,
                        },
                    }
                }
            }

            impl ::std::hash::Hash for $E {
                fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
                    match *self {
                        $($E::$V => $by.hash(state),)*
                        $E::$U(ref s) => s.hash(state),
                    }
                }
            }

            impl ::std::cmp::Eq for $E {}
        )*
    }
}

pub struct BaseTimeout {
    dur: Duration,
    handle: Handle,
    timer: Timeout,
}

/// Adds a timeout to a `Stream`. Inspired by `tokio_timer::TimeoutStream`.
pub struct TimeoutStream<S> {
    stream: S,
    inner: Option<BaseTimeout>,
}

/// A stream over the lines (delimited by CRLF) of a `Body`.
pub struct Lines<B> where B: Stream {
    inner: Fuse<B>,
    buf: Bytes,
}

/// Represents an infallible operation in `default_connector::new`.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub enum Never {}

impl BaseTimeout {
    pub fn new(dur: Duration, handle: Handle) -> Option<Self> {
        Timeout::new(dur, &handle).ok().map(|timer| {
            BaseTimeout {
                dur: dur,
                handle: handle,
                timer: timer,
            }
        })
    }

    pub fn for_stream<S>(self, stream: S) -> TimeoutStream<S> {
        TimeoutStream {
            stream: stream,
            inner: Timeout::new(self.dur, &self.handle).ok().map(move |timer| {
                BaseTimeout {
                    timer: timer,
                    ..self
                }
            }),
        }
    }

    pub fn timer_mut(&mut self) -> &mut Timeout {
        &mut self.timer
    }
}

impl<S> TimeoutStream<S> {
    pub fn never(stream: S) -> Self {
        TimeoutStream {
            stream: stream,
            inner: None,
        }
    }
}

impl<S> Stream for TimeoutStream<S> where S: Stream<Error=HyperError> {
    type Item = S::Item;
    type Error = Error;

    fn poll(&mut self) -> Poll<Option<S::Item>, Error> {
        self.stream.poll().map_err(Error::Hyper).and_then(|async| {
            let ret;

            if let Some(ref mut inner) = self.inner {
                match async {
                    Async::Ready(Some(v)) => {
                        ret = Ok(Some(v).into());
                        if let Ok(timer) = Timeout::new(inner.dur, &inner.handle) {
                            inner.timer = timer;
                            return ret;
                        }
                        // goto timeout_new_failed;
                    },
                    Async::Ready(None) => return Ok(Async::Ready(None)),
                    Async::NotReady => match inner.timer.poll() {
                        Ok(Async::Ready(())) => return Err(Error::TimedOut),
                        Ok(Async::NotReady) => return Ok(Async::NotReady),
                        Err(_) => unreachable!(), // `Timeout` never fails.
                    },
                }
            } else {
                return Ok(async);
            }

            // timeout_new_failed:
            self.inner = None;
            ret
        })
    }
}

impl<B> Lines<B> where B: Stream {
    pub fn new(body: B) -> Self {
        Lines {
            inner: body.fuse(),
            buf: Bytes::new(),
        }
    }
}

impl<B> Stream for Lines<B> where B: Stream, B::Item: Into<Bytes> {
    type Item = Bytes;
    type Error = B::Error;

    fn poll(&mut self) -> Poll<Option<Bytes>, B::Error> {
        use std::mem;

        macro_rules! try_ready_some {
            ($poll:expr) => {{
                let poll = $poll;
                match try_ready!(poll) {
                    Some(v) => v,
                    None    => return Ok(None.into()),
                }
            }};
        }

        if self.buf.is_empty() {
            self.buf = try_ready_some!(self.inner.poll()).into();
        }

        fn remove_first_line(buf: &mut Bytes) -> Option<Bytes> {
            (buf as &Bytes).into_iter().enumerate()
                .find(|&(i, b)| b'\r' == b && Some(&b'\n') == buf.get(i + 1))
                .map(|(i, _)| buf.split_to(i + 2))
        }

        if let Some(buf) = remove_first_line(&mut self.buf) {
            return Ok(Some(buf).into());
        }

        if self.buf.is_empty() {
            self.buf = try_ready_some!(self.inner.poll()).into();
        }

        // Extend the buffer until a newline is found:
        loop {
            match try_ready!(self.inner.poll()) {
                Some(chunk) => {
                    let mut chunk = chunk.into();
                    if &b'\r' == self.buf.last().unwrap() && Some(&b'\n') == chunk.first() {
                        let i = self.buf.len() + 1;
                        self.buf.extend_from_slice(&chunk);
                        let next = self.buf.split_off(i);
                        let ret = mem::replace(&mut self.buf, next);
                        return Ok(Some(ret).into());
                    } else if let Some(tail) = remove_first_line(&mut chunk) {
                        self.buf.extend_from_slice(&tail);
                        let ret = mem::replace(&mut self.buf, chunk);
                        return Ok(Some(ret).into());
                    } else {
                        self.buf.extend_from_slice(&chunk);
                    }
                },
                None => {
                    let ret = mem::replace(&mut self.buf, Bytes::new());
                    return Ok(Some(ret).into());
                },
            };
        }
    }
}

impl error::Error for Never {
    fn description(&self) -> &str {
        unreachable!();
    }
}

impl Display for Never {
    fn fmt(&self, _: &mut Formatter) -> fmt::Result {
        unreachable!();
    }
}

#[cfg(test)]
mod test {
    use bytes::Bytes;
    use futures::stream;
    use super::*;

    #[test]
    fn lines() {
        let lines = vec![
            "abc\r\n",
            "d\r\n",
            "efg\r\n",
            "hijk\r\n",
            "\r\n",
            "lmn\r\n",
            "opq\rrs\r\n",
            "\n\rtuv\r\r\n",
            "wxyz",
        ];
        let body = vec![
            Bytes::from(b"abc\r\n".to_vec()),
            Bytes::from(b"d\r\nefg\r\n".to_vec()),
            Bytes::from(b"hi".to_vec()),
            Bytes::from(b"jk".to_vec()),
            Bytes::from(b"".to_vec()),
            Bytes::from(b"\r\n".to_vec()),
            Bytes::from(b"\r\n".to_vec()),
            Bytes::from(b"lmn\r\nop".to_vec()),
            Bytes::from(b"q\rrs\r".to_vec()),
            Bytes::from(b"\n\n\rtuv\r\r\n".to_vec()),
            Bytes::from(b"wxyz".to_vec()),
        ];

        let mut iter1 = lines.iter().cloned();
        let mut iter2 = Lines::new(stream::iter::<_,_,()>(body.into_iter().map(Ok)))
            .wait().map(|s| String::from_utf8(s.unwrap().to_vec()).unwrap());

        for _ in 0..(lines.len()+1) {
            assert_eq!(
                iter1.next(),
                iter2.next().as_ref().map(String::as_str)
            );
        }
    }
}
<commit_msg>Fix a deprecation warning for `futures::stream::iter`<commit_after>use bytes::Bytes;
use error::{Error, HyperError};
use futures::{Async, Future, Poll, Stream};
use futures::stream::Fuse;
use std::error;
use std::fmt::{self, Display, Formatter};
use std::time::Duration;
use tokio_core::reactor::{Handle, Timeout};

// Synonym of `twitter_stream_message::util::string_enums`
macro_rules! string_enums {
    (
        $(
            $(#[$attr:meta])*
            pub enum $E:ident {
                $(
                    $(#[$v_attr:meta])*
                    :$V:ident($by:expr) // The leading (ugly) colon is to suppress local ambiguity error.
                ),*;
                $(#[$u_attr:meta])*
                :$U:ident(_),
            }
        )*
    ) => {
        $(
            $(#[$attr])*
            pub enum $E {
                $(
                    $(#[$v_attr])*
                    $V,
                )*
                $(#[$u_attr])*
                $U(String),
            }

            impl ::std::convert::AsRef<str> for $E {
                fn as_ref(&self) -> &str {
                    match *self {
                        $($E::$V => $by,)*
                        $E::$U(ref s) => s,
                    }
                }
            }

            impl ::std::cmp::PartialEq for $E {
                fn eq(&self, other: &$E) -> bool {
                    match *self {
                        $($E::$V => match *other {
                            $E::$V => true,
                            $E::$U(ref s) if $by == s => true,
                            _ => false,
                        },)*
                        $E::$U(ref s) => match *other {
                            $($E::$V => $by == s,)*
                            $E::$U(ref t) => s == t,
                        },
                    }
                }
            }

            impl ::std::hash::Hash for $E {
                fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
                    match *self {
                        $($E::$V => $by.hash(state),)*
                        $E::$U(ref s) => s.hash(state),
                    }
                }
            }

            impl ::std::cmp::Eq for $E {}
        )*
    }
}

pub struct BaseTimeout {
    dur: Duration,
    handle: Handle,
    timer: Timeout,
}

/// Adds a timeout to a `Stream`. Inspired by `tokio_timer::TimeoutStream`.
pub struct TimeoutStream<S> {
    stream: S,
    inner: Option<BaseTimeout>,
}

/// A stream over the lines (delimited by CRLF) of a `Body`.
pub struct Lines<B> where B: Stream {
    inner: Fuse<B>,
    buf: Bytes,
}

/// Represents an infallible operation in `default_connector::new`.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub enum Never {}

impl BaseTimeout {
    pub fn new(dur: Duration, handle: Handle) -> Option<Self> {
        Timeout::new(dur, &handle).ok().map(|timer| {
            BaseTimeout {
                dur: dur,
                handle: handle,
                timer: timer,
            }
        })
    }

    pub fn for_stream<S>(self, stream: S) -> TimeoutStream<S> {
        TimeoutStream {
            stream: stream,
            inner: Timeout::new(self.dur, &self.handle).ok().map(move |timer| {
                BaseTimeout {
                    timer: timer,
                    ..self
                }
            }),
        }
    }

    pub fn timer_mut(&mut self) -> &mut Timeout {
        &mut self.timer
    }
}

impl<S> TimeoutStream<S> {
    pub fn never(stream: S) -> Self {
        TimeoutStream {
            stream: stream,
            inner: None,
        }
    }
}

impl<S> Stream for TimeoutStream<S> where S: Stream<Error=HyperError> {
    type Item = S::Item;
    type Error = Error;

    fn poll(&mut self) -> Poll<Option<S::Item>, Error> {
        self.stream.poll().map_err(Error::Hyper).and_then(|async| {
            let ret;

            if let Some(ref mut inner) = self.inner {
                match async {
                    Async::Ready(Some(v)) => {
                        ret = Ok(Some(v).into());
                        if let Ok(timer) = Timeout::new(inner.dur, &inner.handle) {
                            inner.timer = timer;
                            return ret;
                        }
                        // goto timeout_new_failed;
                    },
                    Async::Ready(None) => return Ok(Async::Ready(None)),
                    Async::NotReady => match inner.timer.poll() {
                        Ok(Async::Ready(())) => return Err(Error::TimedOut),
                        Ok(Async::NotReady) => return Ok(Async::NotReady),
                        Err(_) => unreachable!(), // `Timeout` never fails.
                    },
                }
            } else {
                return Ok(async);
            }

            // timeout_new_failed:
            self.inner = None;
            ret
        })
    }
}

impl<B> Lines<B> where B: Stream {
    pub fn new(body: B) -> Self {
        Lines {
            inner: body.fuse(),
            buf: Bytes::new(),
        }
    }
}

impl<B> Stream for Lines<B> where B: Stream, B::Item: Into<Bytes> {
    type Item = Bytes;
    type Error = B::Error;

    fn poll(&mut self) -> Poll<Option<Bytes>, B::Error> {
        use std::mem;

        macro_rules! try_ready_some {
            ($poll:expr) => {{
                let poll = $poll;
                match try_ready!(poll) {
                    Some(v) => v,
                    None    => return Ok(None.into()),
                }
            }};
        }

        if self.buf.is_empty() {
            self.buf = try_ready_some!(self.inner.poll()).into();
        }

        fn remove_first_line(buf: &mut Bytes) -> Option<Bytes> {
            (buf as &Bytes).into_iter().enumerate()
                .find(|&(i, b)| b'\r' == b && Some(&b'\n') == buf.get(i + 1))
                .map(|(i, _)| buf.split_to(i + 2))
        }

        if let Some(buf) = remove_first_line(&mut self.buf) {
            return Ok(Some(buf).into());
        }

        if self.buf.is_empty() {
            self.buf = try_ready_some!(self.inner.poll()).into();
        }

        // Extend the buffer until a newline is found:
        loop {
            match try_ready!(self.inner.poll()) {
                Some(chunk) => {
                    let mut chunk = chunk.into();
                    if &b'\r' == self.buf.last().unwrap() && Some(&b'\n') == chunk.first() {
                        let i = self.buf.len() + 1;
                        self.buf.extend_from_slice(&chunk);
                        let next = self.buf.split_off(i);
                        let ret = mem::replace(&mut self.buf, next);
                        return Ok(Some(ret).into());
                    } else if let Some(tail) = remove_first_line(&mut chunk) {
                        self.buf.extend_from_slice(&tail);
                        let ret = mem::replace(&mut self.buf, chunk);
                        return Ok(Some(ret).into());
                    } else {
                        self.buf.extend_from_slice(&chunk);
                    }
                },
                None => {
                    let ret = mem::replace(&mut self.buf, Bytes::new());
                    return Ok(Some(ret).into());
                },
            };
        }
    }
}

impl error::Error for Never {
    fn description(&self) -> &str {
        unreachable!();
    }
}

impl Display for Never {
    fn fmt(&self, _: &mut Formatter) -> fmt::Result {
        unreachable!();
    }
}

#[cfg(test)]
mod test {
    use bytes::Bytes;
    use futures::stream;
    use super::*;

    #[test]
    fn lines() {
        let lines = vec![
            "abc\r\n",
            "d\r\n",
            "efg\r\n",
            "hijk\r\n",
            "\r\n",
            "lmn\r\n",
            "opq\rrs\r\n",
            "\n\rtuv\r\r\n",
            "wxyz",
        ];
        let body = vec![
            Bytes::from(b"abc\r\n".to_vec()),
            Bytes::from(b"d\r\nefg\r\n".to_vec()),
            Bytes::from(b"hi".to_vec()),
            Bytes::from(b"jk".to_vec()),
            Bytes::from(b"".to_vec()),
            Bytes::from(b"\r\n".to_vec()),
            Bytes::from(b"\r\n".to_vec()),
            Bytes::from(b"lmn\r\nop".to_vec()),
            Bytes::from(b"q\rrs\r".to_vec()),
            Bytes::from(b"\n\n\rtuv\r\r\n".to_vec()),
            Bytes::from(b"wxyz".to_vec()),
        ];

        let mut iter1 = lines.iter().cloned();
        let mut iter2 = Lines::new(stream::iter_ok::<_,()>(body))
            .wait()
            .map(|s| String::from_utf8(s.unwrap().to_vec()).unwrap());

        for _ in 0..(lines.len()+1) {
            assert_eq!(
                iter1.next(),
                iter2.next().as_ref().map(String::as_str)
            );
        }
    }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::rc::Rc;

use super::ast::nodes::*;
use super::ir::layout::{
    Address, Import, Instruction, InstructionBuilder, Module as IrModule, SharedFunction,
    SharedSlot, SharedValue,
};
use super::vm::prelude::is_in_prelude;

trait Scope {
    fn add_local(&mut self, name: &String) -> SharedSlot;

    fn resolve(&mut self, name: &String) -> SharedSlot;

    /// Acts the same as `resolve`, but records bindings along the way.
    fn resolve_as_binding(&mut self, name: &String) -> SharedSlot;
}

struct FunctionScope<'a> {
    parent: &'a mut dyn Scope,
    function: SharedFunction,
    // Keep track of every variable we've seen. Some of them may end up bound,
    // so we'll actually make them proper local variables or bound variables
    // when we traverse upwards.
    locals: HashMap<String, SharedSlot>,
    // Keep track of which variables need to be bound and come from parent
    // bindings.
    bindings: HashSet<String>,
    parent_bindings: HashMap<String, SharedSlot>,
}

impl<'a> FunctionScope<'a> {
    fn new(parent: &'a mut dyn Scope, function: SharedFunction) -> Self {
        Self {
            parent,
            function,
            locals: HashMap::new(),
            bindings: HashSet::new(),
            parent_bindings: HashMap::new(),
        }
    }
}

impl<'a> Scope for FunctionScope<'a> {
    fn add_local(&mut self, name: &String) -> SharedSlot {
        let slot = SharedSlot::new_local(name.clone());
        self.locals.insert(name.clone(), slot.clone());
        slot
    }

    fn resolve(&mut self, name: &String) -> SharedSlot {
        if let Some(resolved) = self.locals.get(name) {
            resolved.clone()
        } else {
            let slot = self.parent.resolve_as_binding(name);
            self.parent_bindings.insert(name.clone(), slot.clone());
            slot
        }
    }

    fn resolve_as_binding(&mut self, name: &String) -> SharedSlot {
        if let Some(resolved) = self.locals.get(name) {
            // Since this was called from a lower function scope we now know
            // we need to bind it for that lower scope.
            self.bindings.insert(name.clone());
            resolved.clone()
        } else {
            let slot = self.parent.resolve_as_binding(name);
            self.parent_bindings.insert(name.clone(), slot.clone());
            slot
        }
    }
}

struct ModuleScope {
    module: Rc<RefCell<IrModule>>,
    bindings: HashMap<String, SharedSlot>,
    // Map an import name to its source.
    imports: HashMap<String, Import>,
}

impl Scope for ModuleScope {
    fn add_local(&mut self, name: &String) -> SharedSlot {
        let slot = SharedSlot::new_static(name.clone());
        self.bindings.insert(name.clone(), slot.clone());
        slot
    }

    fn resolve(&mut self, name: &String) -> SharedSlot {
        if is_in_prelude(name) {
            self.imports.insert(
                name.to_owned(),
                Import::Named("prelude".to_owned(), name.to_owned()),
            );
            return SharedSlot::new_static(name.clone());
        }
        if let Some(slot) = self.bindings.get(name) {
            slot.clone()
        } else {
            // Automatically add it because it might be imported via
            // an `import *`.
            self.add_local(name)
        }
    }

    fn resolve_as_binding(&mut self, name: &String) -> SharedSlot {
        self.resolve(name)
    }
}

struct Compiler {
    module: Rc<RefCell<IrModule>>,
    current: SharedFunction,
}

impl Compiler {
    fn new() -> Self {
        let module = Rc::new(RefCell::new(IrModule::new()));
        let current = module.borrow().main_function();
        Self { module, current }
    }

    fn compile_module(&mut self, module: &Module) {
        let mut module_scope = ModuleScope {
            module: self.module.clone(),
            bindings: HashMap::new(),
            imports: HashMap::new(),
        };

        // We should start in the main function.
        assert_eq!(self.current, self.module.borrow().main_function());

        let mut scope = FunctionScope::new(&mut module_scope, self.current.clone());
        for node in module.nodes.iter() {
            self.compile_node(node, &mut scope);
            // We should always end up back in the main function.
            assert_eq!(self.current, self.module.borrow().main_function());
        }
        // Insert a return at the end to make sure empty modules don't crash.
        self.build_return_null();
        Compiler::finalize_function(self.current.clone(), &scope);

        // Now that we've visited the whole program we can write out the
        // imports we've found.
        self.module.borrow_mut().imports = module_scope.imports;
    }

    fn compile_node(&mut self, node: &Node, scope: &mut dyn Scope) -> SharedValue {
        match node {
            &Node::Assignment(ref assignment) => self.compile_assignment(assignment, scope),
            &Node::Block(ref block) => self.compile_anonymous_block(block, scope),
            &Node::Function(ref function) => self.compile_function(function, scope),
            &Node::Identifier(ref identifier) => self.compile_identifier(identifier, scope),
            &Node::Infix(ref infix) => self.compile_infix(infix, scope),
            &Node::Integer(ref integer) => self.compile_integer(integer, scope),
            &Node::PostfixCall(ref call) => self.compile_postfix_call(call, scope),
            &Node::Return(ref ret) => self.compile_return(ret, scope),
            &Node::Var(ref var) => self.compile_var(var, scope),
            _ => panic!("Cannot compile node: {:?}", node),
        }
    }

    fn compile_assignment(
        &mut self,
        assignment: &Assignment,
        scope: &mut dyn Scope,
    ) -> SharedValue {
        let lhs = &*assignment.lhs;
        let assignee = match &lhs {
            &Node::Identifier(identifier) => {
                let local = &identifier.value;
                scope.resolve(local)
            }
            _ => unreachable!("Cannot assign to: {:?}", lhs),
        };

        let rval = self.compile_node(&assignment.rhs, scope);
        self.build_set(assignee, rval.clone());
        rval
    }

    fn compile_anonymous_block(&mut self, block: &Block, scope: &mut dyn Scope) -> SharedValue {
        // Push a new basic block and branch to it.
        self.current.borrow_mut().push_basic_block(true);

        let mut implicit_return = self.null_value();
        for node in block.nodes.iter() {
            implicit_return = self.compile_node(node, scope);
        }

        // Exit from the current block to the new block.
        self.current.borrow_mut().push_basic_block(true);

        implicit_return
    }

    fn compile_function(&mut self, function: &Function, scope: &mut dyn Scope) -> SharedValue {
        let name = function.name.to_owned();
        let enclosing_function = self.current.clone();
        let new_function = match &name {
            Some(name) => self.module.borrow_mut().new_named_function(name.clone()),
            None => self
                .module
                .borrow_mut()
                .new_anonymous_function(enclosing_function.clone()),
        };
        self.current = new_function.clone();

        let slot = name.map(|name| scope.add_local(&name));
        let mut function_scope = FunctionScope::new(scope, self.current.clone());
        let body = &*function.body;
        let lval = self.compile_node(body, &mut function_scope);
        match body {
            Node::Block(_) => self.build_return_null(),
            _ => self.build_return(lval),
        };
        // Save the bindings so that we know how to build the closure.
        Compiler::finalize_function(new_function.clone(), &function_scope);

        self.current = enclosing_function;
        let lval = self.build_make_function(new_function);
        if let Some(slot) = slot {
            self.build_set(slot, lval.clone());
        };
        lval
    }

    fn finalize_function(function: SharedFunction, scope: &FunctionScope) {
        let mut function = function.borrow_mut();

        let mut all_locals = scope.locals.clone();
        // The bindings will have been filled in by nested functions within
        // this function. We therefore now need to remove any local that's
        // been bound and promote it to lexical.
        for binding in scope.bindings.iter() {
            let slot = all_locals
                .remove(binding)
                .expect(&format!("Missing local for binding: {}", binding));
            slot.promote_from_local_to_lexical(binding.clone());
        }
        // Remaining entries in `all_locals` will now only be unbound locals
        // (ie. ones that won't be captured in a closure).
        let unbound_locals = all_locals;

        let mut locals = vec![];
        for (index, (name, slot)) in unbound_locals.iter().enumerate() {
            locals.push(name.clone());
            slot.set_local_index(index as u8);
        }

        function.locals = locals;
        function.bindings = scope.bindings.clone();
        // We only need to capture our parent's bindings if we use non-static
        // ones (eg. lexical slots or local slots that will be promoted
        // to lexical).
        function.parent_bindings = scope.parent_bindings.values().any(|slot| !slot.is_static());
    }

    fn compile_identifier(
        &mut self,
        identifier: &Identifier,
        scope: &mut dyn Scope,
    ) -> SharedValue {
        let local = &identifier.value;
        self.build_get(scope.resolve(local))
    }

    fn compile_infix(&mut self, infix: &Infix, scope: &mut dyn Scope) -> SharedValue {
        let lhs = self.compile_node(&infix.lhs, scope);
        let rhs = self.compile_node(&infix.rhs, scope);
        self.build_op_add(lhs, rhs)
    }

    fn compile_integer(&mut self, integer: &Integer, _scope: &mut dyn Scope) -> SharedValue {
        self.build_make_integer(integer.value)
    }

    fn compile_postfix_call(&mut self, call: &PostfixCall, scope: &mut dyn Scope) -> SharedValue {
        let target = self.compile_node(&call.target, scope);
        let mut arguments = vec![];
        for argument in call.arguments.iter() {
            arguments.push(self.compile_node(argument, scope));
        }
        self.build_call(target, arguments)
    }

    fn compile_return(&mut self, ret: &Return, scope: &mut dyn Scope) -> SharedValue {
        if let Some(ref rhs) = ret.rhs {
            let rval = self.compile_node(&rhs, scope);
            self.build_return(rval);
        } else {
            self.build_return_null();
        }
        self.null_value()
    }

    fn compile_var(&mut self, var: &Var, scope: &mut dyn Scope) -> SharedValue {
        let slot = scope.add_local(&var.lhs.value);
        if let Some(ref rhs) = var.rhs {
            let rval = self.compile_node(rhs, scope);
            self.build_set(slot, rval);
        }
        self.null_value()
    }

    // Convenience proxy methods to the current function:

    fn null_value(&self) -> SharedValue {
        self.current.borrow().null_value()
    }
}

// Forward all the heavy lifting to the current function. This allows us to do
// stuff like `self.build_get_local()` above inside of `Compiler`.
impl InstructionBuilder for Compiler {
    fn new_value(&mut self) -> SharedValue {
        self.current.borrow_mut().new_value()
    }

    fn push(&mut self, instruction: Instruction) -> Address {
        self.current.borrow_mut().push(instruction)
    }

    fn track(&mut self, rval: SharedValue, address: Address) {
        self.current.borrow_mut().track(rval, address)
    }
}

pub fn compile(module: &Module) -> IrModule {
    let mut compiler = Compiler::new();
    compiler.compile_module(module);
    // The reference count should be 1 at this point.
    let module_cell = Rc::try_unwrap(compiler.module).unwrap();
    module_cell.into_inner()
}
<commit_msg>Implement implicit returns<commit_after>use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::rc::Rc;

use super::ast::nodes::*;
use super::ir::layout::{
    Address, Import, Instruction, InstructionBuilder, Module as IrModule, SharedFunction,
    SharedSlot, SharedValue,
};
use super::vm::prelude::is_in_prelude;

trait Scope {
    fn add_local(&mut self, name: &String) -> SharedSlot;

    fn resolve(&mut self, name: &String) -> SharedSlot;

    /// Acts the same as `resolve`, but records bindings along the way.
    fn resolve_as_binding(&mut self, name: &String) -> SharedSlot;
}

struct FunctionScope<'a> {
    parent: &'a mut dyn Scope,
    function: SharedFunction,
    // Keep track of every variable we've seen. Some of them may end up bound,
    // so we'll actually make them proper local variables or bound variables
    // when we traverse upwards.
    locals: HashMap<String, SharedSlot>,
    // Keep track of which variables need to be bound and come from parent
    // bindings.
    bindings: HashSet<String>,
    parent_bindings: HashMap<String, SharedSlot>,
}

impl<'a> FunctionScope<'a> {
    fn new(parent: &'a mut dyn Scope, function: SharedFunction) -> Self {
        Self {
            parent,
            function,
            locals: HashMap::new(),
            bindings: HashSet::new(),
            parent_bindings: HashMap::new(),
        }
    }
}

impl<'a> Scope for FunctionScope<'a> {
    fn add_local(&mut self, name: &String) -> SharedSlot {
        let slot = SharedSlot::new_local(name.clone());
        self.locals.insert(name.clone(), slot.clone());
        slot
    }

    fn resolve(&mut self, name: &String) -> SharedSlot {
        if let Some(resolved) = self.locals.get(name) {
            resolved.clone()
        } else {
            let slot = self.parent.resolve_as_binding(name);
            self.parent_bindings.insert(name.clone(), slot.clone());
            slot
        }
    }

    fn resolve_as_binding(&mut self, name: &String) -> SharedSlot {
        if let Some(resolved) = self.locals.get(name) {
            // Since this was called from a lower function scope we now know
            // we need to bind it for that lower scope.
            self.bindings.insert(name.clone());
            resolved.clone()
        } else {
            let slot = self.parent.resolve_as_binding(name);
            self.parent_bindings.insert(name.clone(), slot.clone());
            slot
        }
    }
}

struct ModuleScope {
    module: Rc<RefCell<IrModule>>,
    bindings: HashMap<String, SharedSlot>,
    // Map an import name to its source.
    imports: HashMap<String, Import>,
}

impl Scope for ModuleScope {
    fn add_local(&mut self, name: &String) -> SharedSlot {
        let slot = SharedSlot::new_static(name.clone());
        self.bindings.insert(name.clone(), slot.clone());
        slot
    }

    fn resolve(&mut self, name: &String) -> SharedSlot {
        if is_in_prelude(name) {
            self.imports.insert(
                name.to_owned(),
                Import::Named("prelude".to_owned(), name.to_owned()),
            );
            return SharedSlot::new_static(name.clone());
        }
        if let Some(slot) = self.bindings.get(name) {
            slot.clone()
        } else {
            // Automatically add it because it might be imported via
            // an `import *`.
            self.add_local(name)
        }
    }

    fn resolve_as_binding(&mut self, name: &String) -> SharedSlot {
        self.resolve(name)
    }
}

struct Compiler {
    module: Rc<RefCell<IrModule>>,
    current: SharedFunction,
}

impl Compiler {
    fn new() -> Self {
        let module = Rc::new(RefCell::new(IrModule::new()));
        let current = module.borrow().main_function();
        Self { module, current }
    }

    fn compile_module(&mut self, module: &Module) {
        let mut module_scope = ModuleScope {
            module: self.module.clone(),
            bindings: HashMap::new(),
            imports: HashMap::new(),
        };

        // We should start in the main function.
        assert_eq!(self.current, self.module.borrow().main_function());

        let mut scope = FunctionScope::new(&mut module_scope, self.current.clone());
        for node in module.nodes.iter() {
            self.compile_node(node, &mut scope);
            // We should always end up back in the main function.
            assert_eq!(self.current, self.module.borrow().main_function());
        }
        // Insert a return at the end to make sure empty modules don't crash.
        self.build_return_null();
        Compiler::finalize_function(self.current.clone(), &scope);

        // Now that we've visited the whole program we can write out the
        // imports we've found.
        self.module.borrow_mut().imports = module_scope.imports;
    }

    fn compile_node(&mut self, node: &Node, scope: &mut dyn Scope) -> SharedValue {
        match node {
            &Node::Assignment(ref assignment) => self.compile_assignment(assignment, scope),
            &Node::Block(ref block) => self.compile_anonymous_block(block, scope),
            &Node::Function(ref function) => self.compile_function(function, scope),
            &Node::Identifier(ref identifier) => self.compile_identifier(identifier, scope),
            &Node::Infix(ref infix) => self.compile_infix(infix, scope),
            &Node::Integer(ref integer) => self.compile_integer(integer, scope),
            &Node::PostfixCall(ref call) => self.compile_postfix_call(call, scope),
            &Node::Return(ref ret) => self.compile_return(ret, scope),
            &Node::Var(ref var) => self.compile_var(var, scope),
            _ => panic!("Cannot compile node: {:?}", node),
        }
    }

    fn compile_assignment(
        &mut self,
        assignment: &Assignment,
        scope: &mut dyn Scope,
    ) -> SharedValue {
        let lhs = &*assignment.lhs;
        let assignee = match &lhs {
            &Node::Identifier(identifier) => {
                let local = &identifier.value;
                scope.resolve(local)
            }
            _ => unreachable!("Cannot assign to: {:?}", lhs),
        };

        let rval = self.compile_node(&assignment.rhs, scope);
        self.build_set(assignee, rval.clone());
        rval
    }

    fn compile_anonymous_block(&mut self, block: &Block, scope: &mut dyn Scope) -> SharedValue {
        // Push a new basic block and branch to it.
        self.current.borrow_mut().push_basic_block(true);

        let mut implicit_return = self.null_value();
        for node in block.nodes.iter() {
            implicit_return = self.compile_node(node, scope);
        }

        // Exit from the current block to the new block.
        self.current.borrow_mut().push_basic_block(true);

        implicit_return
    }

    fn compile_function(&mut self, function: &Function, scope: &mut dyn Scope) -> SharedValue {
        let name = function.name.to_owned();
        let enclosing_function = self.current.clone();
        let new_function = match &name {
            Some(name) => self.module.borrow_mut().new_named_function(name.clone()),
            None => self
                .module
                .borrow_mut()
                .new_anonymous_function(enclosing_function.clone()),
        };
        self.current = new_function.clone();

        let slot = name.map(|name| scope.add_local(&name));
        let mut function_scope = FunctionScope::new(scope, self.current.clone());
        let body = &*function.body;
        let lval = self.compile_node(body, &mut function_scope);
        self.build_return(lval);
        // Save the bindings so that we know how to build the closure.
        Compiler::finalize_function(new_function.clone(), &function_scope);

        self.current = enclosing_function;
        let lval = self.build_make_function(new_function);
        if let Some(slot) = slot {
            self.build_set(slot, lval.clone());
        };
        lval
    }

    fn finalize_function(function: SharedFunction, scope: &FunctionScope) {
        let mut function = function.borrow_mut();

        let mut all_locals = scope.locals.clone();
        // The bindings will have been filled in by nested functions within
        // this function. We therefore now need to remove any local that's
        // been bound and promote it to lexical.
        for binding in scope.bindings.iter() {
            let slot = all_locals
                .remove(binding)
                .expect(&format!("Missing local for binding: {}", binding));
            slot.promote_from_local_to_lexical(binding.clone());
        }
        // Remaining entries in `all_locals` will now only be unbound locals
        // (ie. ones that won't be captured in a closure).
        let unbound_locals = all_locals;

        let mut locals = vec![];
        for (index, (name, slot)) in unbound_locals.iter().enumerate() {
            locals.push(name.clone());
            slot.set_local_index(index as u8);
        }

        function.locals = locals;
        function.bindings = scope.bindings.clone();
        // We only need to capture our parent's bindings if we use non-static
        // ones (eg. lexical slots or local slots that will be promoted
        // to lexical).
        function.parent_bindings = scope.parent_bindings.values().any(|slot| !slot.is_static());
    }

    fn compile_identifier(
        &mut self,
        identifier: &Identifier,
        scope: &mut dyn Scope,
    ) -> SharedValue {
        let local = &identifier.value;
        self.build_get(scope.resolve(local))
    }

    fn compile_infix(&mut self, infix: &Infix, scope: &mut dyn Scope) -> SharedValue {
        let lhs = self.compile_node(&infix.lhs, scope);
        let rhs = self.compile_node(&infix.rhs, scope);
        self.build_op_add(lhs, rhs)
    }

    fn compile_integer(&mut self, integer: &Integer, _scope: &mut dyn Scope) -> SharedValue {
        self.build_make_integer(integer.value)
    }

    fn compile_postfix_call(&mut self, call: &PostfixCall, scope: &mut dyn Scope) -> SharedValue {
        let target = self.compile_node(&call.target, scope);
        let mut arguments = vec![];
        for argument in call.arguments.iter() {
            arguments.push(self.compile_node(argument, scope));
        }
        self.build_call(target, arguments)
    }

    fn compile_return(&mut self, ret: &Return, scope: &mut dyn Scope) -> SharedValue {
        if let Some(ref rhs) = ret.rhs {
            let rval = self.compile_node(&rhs, scope);
            self.build_return(rval);
        } else {
            self.build_return_null();
        }
        self.null_value()
    }

    fn compile_var(&mut self, var: &Var, scope: &mut dyn Scope) -> SharedValue {
        let slot = scope.add_local(&var.lhs.value);
        if let Some(ref rhs) = var.rhs {
            let rval = self.compile_node(rhs, scope);
            self.build_set(slot, rval);
        }
        self.null_value()
    }

    // Convenience proxy methods to the current function:

    fn null_value(&self) -> SharedValue {
        self.current.borrow().null_value()
    }
}

// Forward all the heavy lifting to the current function. This allows us to do
// stuff like `self.build_get_local()` above inside of `Compiler`.
impl InstructionBuilder for Compiler {
    fn new_value(&mut self) -> SharedValue {
        self.current.borrow_mut().new_value()
    }

    fn push(&mut self, instruction: Instruction) -> Address {
        self.current.borrow_mut().push(instruction)
    }

    fn track(&mut self, rval: SharedValue, address: Address) {
        self.current.borrow_mut().track(rval, address)
    }
}

pub fn compile(module: &Module) -> IrModule {
    let mut compiler = Compiler::new();
    compiler.compile_module(module);
    // The reference count should be 1 at this point.
    let module_cell = Rc::try_unwrap(compiler.module).unwrap();
    module_cell.into_inner()
}
<|endoftext|>


<commit_before>use crate::authenticator_delegate::{AuthenticatorDelegate, Retry};
use crate::refresh::{RefreshFlow, RefreshResult};
use crate::storage::{hash_scopes, DiskTokenStorage, MemoryStorage, TokenStorage};
use crate::types::{ApplicationSecret, GetToken, StringError, Token};

use futures::{future, prelude::*};
use tokio_timer;

use std::error::Error;
use std::io;
use std::sync::{Arc, Mutex};

/// Authenticator abstracts different `GetToken` implementations behind one type and handles
/// caching received tokens. It's important to use it (instead of the flows directly) because
/// otherwise the user needs to be asked for new authorization every time a token is generated.
///
/// `ServiceAccountAccess` does not need (and does not work) with `Authenticator`, given that it
/// does not require interaction and implements its own caching. Use it directly.
///
/// NOTE: It is recommended to use a client constructed like this in order to prevent functions
/// like `hyper::run()` from hanging: `let client = hyper::Client::builder().keep_alive(false);`.
/// Due to token requests being rare, this should not result in a too bad performance problem.
pub struct Authenticator<
    T: GetToken,
    S: TokenStorage,
    AD: AuthenticatorDelegate,
    C: hyper::client::connect::Connect,
> {
    client: hyper::Client<C>,
    inner: Arc<Mutex<T>>,
    store: Arc<Mutex<S>>,
    delegate: AD,
}

impl<T: GetToken, AD: AuthenticatorDelegate, C: hyper::client::connect::Connect>
    Authenticator<T, MemoryStorage, AD, C>
{
    /// Create an Authenticator caching tokens for the duration of this authenticator.
    pub fn new(
        client: hyper::Client<C>,
        inner: T,
        delegate: AD,
    ) -> Authenticator<T, MemoryStorage, AD, C> {
        Authenticator {
            client: client,
            inner: Arc::new(Mutex::new(inner)),
            store: Arc::new(Mutex::new(MemoryStorage::new())),
            delegate: delegate,
        }
    }
}

impl<T: GetToken, AD: AuthenticatorDelegate, C: hyper::client::connect::Connect>
    Authenticator<T, DiskTokenStorage, AD, C>
{
    /// Create an Authenticator using the store at `path`.
    pub fn new_disk<P: AsRef<str>>(
        client: hyper::Client<C>,
        inner: T,
        delegate: AD,
        token_storage_path: P,
    ) -> io::Result<Authenticator<T, DiskTokenStorage, AD, C>> {
        Ok(Authenticator {
            client: client,
            inner: Arc::new(Mutex::new(inner)),
            store: Arc::new(Mutex::new(DiskTokenStorage::new(token_storage_path)?)),
            delegate: delegate,
        })
    }
}

impl<
        GT: 'static + GetToken + Send,
        S: 'static + TokenStorage + Send,
        AD: 'static + AuthenticatorDelegate + Send,
        C: 'static + hyper::client::connect::Connect + Clone + Send,
    > GetToken for Authenticator<GT, S, AD, C>
{
    /// Returns the API Key of the inner flow.
    fn api_key(&mut self) -> Option<String> {
        self.inner.lock().unwrap().api_key()
    }
    /// Returns the application secret of the inner flow.
    fn application_secret(&self) -> ApplicationSecret {
        self.inner.lock().unwrap().application_secret()
    }

    fn token<'b, I, T>(
        &mut self,
        scopes: I,
    ) -> Box<dyn Future<Item = Token, Error = Box<dyn Error + Send>> + Send>
    where
        T: AsRef<str> + Ord + 'b,
        I: Iterator<Item = &'b T>,
    {
        let (scope_key, scopes) = hash_scopes(scopes);
        let store = self.store.clone();
        let mut delegate = self.delegate.clone();
        let client = self.client.clone();
        let appsecret = self.inner.lock().unwrap().application_secret();
        let gettoken = self.inner.clone();
        let loopfn = move |()| -> Box<
            dyn Future<Item = future::Loop<Token, ()>, Error = Box<dyn Error + Send>> + Send,
        > {
            // How well does this work with tokio?
            match store.lock().unwrap().get(
                scope_key.clone(),
                &scopes.iter().map(|s| s.as_str()).collect(),
            ) {
                Ok(Some(t)) => {
                    if !t.expired() {
                        return Box::new(Ok(future::Loop::Break(t)).into_future());
                    }
                    // Implement refresh flow.
                    let refresh_token = t.refresh_token.clone();
                    let mut delegate = delegate.clone();
                    let refresh_fut = RefreshFlow::refresh_token(
                        client.clone(),
                        appsecret.clone(),
                        refresh_token,
                    )
                    .and_then(move |rr| match rr {
                        RefreshResult::Error(e) => {
                            delegate.token_refresh_failed(
                                format!("{}", e.description().to_string()),
                                &Some("the request has likely timed out".to_string()),
                            );
                            Err(Box::new(e) as Box<dyn Error + Send>)
                        }
                        RefreshResult::RefreshError(ref s, ref ss) => {
                            delegate.token_refresh_failed(
                                format!("{} {}", s, ss.clone().map(|s| format!("({})", s)).unwrap_or("".to_string())),
                                &Some("the refresh token is likely invalid and your authorization has been revoked".to_string()),
                            );
                            Err(Box::new(StringError::new(s.to_string(), ss.as_ref())) as Box<dyn Error + Send>)
                        }
                        RefreshResult::Success(t) => Ok(future::Loop::Break(t)),
                    });
                    Box::new(refresh_fut)
                }
                Ok(None) => {
                    let store = store.clone();
                    let scopes = scopes.clone();
                    let mut delegate = delegate.clone();
                    Box::new(
                        gettoken
                            .lock()
                            .unwrap()
                            .token(scopes.iter())
                            .and_then(move |t| {
                                if let Err(e) = store.lock().unwrap().set(
                                    scope_key,
                                    &scopes.iter().map(|s| s.as_str()).collect(),
                                    Some(t.clone()),
                                ) {
                                    match delegate.token_storage_failure(true, &e) {
                                        Retry::Skip => {
                                            Box::new(Ok(future::Loop::Break(t)).into_future())
                                        }
                                        Retry::Abort => Box::new(
                                            Err(Box::new(e) as Box<dyn Error + Send>).into_future(),
                                        ),
                                        Retry::After(d) => Box::new(
                                            tokio_timer::sleep(d)
                                                .then(|_| Ok(future::Loop::Continue(()))),
                                        )
                                            as Box<
                                                dyn Future<
                                                        Item = future::Loop<Token, ()>,
                                                        Error = Box<dyn Error + Send>,
                                                    > + Send,
                                            >,
                                    }
                                } else {
                                    Box::new(Ok(future::Loop::Break(t)).into_future())
                                }
                            }),
                    )
                }
                Err(err) => match delegate.token_storage_failure(false, &err) {
                    Retry::Abort | Retry::Skip => {
                        return Box::new(future::err(Box::new(err) as Box<dyn Error + Send>))
                    }
                    Retry::After(d) => {
                        return Box::new(
                            tokio_timer::sleep(d).then(|_| Ok(future::Loop::Continue(()))),
                        )
                    }
                },
            }
        };
        Box::new(future::loop_fn((), loopfn))
    }
}
<commit_msg>fix(refresh): Write refreshed tokens back to cache.<commit_after>use crate::authenticator_delegate::{AuthenticatorDelegate, Retry};
use crate::refresh::{RefreshFlow, RefreshResult};
use crate::storage::{hash_scopes, DiskTokenStorage, MemoryStorage, TokenStorage};
use crate::types::{ApplicationSecret, GetToken, StringError, Token};

use futures::{future, prelude::*};
use tokio_timer;

use std::error::Error;
use std::io;
use std::sync::{Arc, Mutex};

/// Authenticator abstracts different `GetToken` implementations behind one type and handles
/// caching received tokens. It's important to use it (instead of the flows directly) because
/// otherwise the user needs to be asked for new authorization every time a token is generated.
///
/// `ServiceAccountAccess` does not need (and does not work) with `Authenticator`, given that it
/// does not require interaction and implements its own caching. Use it directly.
///
/// NOTE: It is recommended to use a client constructed like this in order to prevent functions
/// like `hyper::run()` from hanging: `let client = hyper::Client::builder().keep_alive(false);`.
/// Due to token requests being rare, this should not result in a too bad performance problem.
pub struct Authenticator<
    T: GetToken,
    S: TokenStorage,
    AD: AuthenticatorDelegate,
    C: hyper::client::connect::Connect,
> {
    client: hyper::Client<C>,
    inner: Arc<Mutex<T>>,
    store: Arc<Mutex<S>>,
    delegate: AD,
}

impl<T: GetToken, AD: AuthenticatorDelegate, C: hyper::client::connect::Connect>
    Authenticator<T, MemoryStorage, AD, C>
{
    /// Create an Authenticator caching tokens for the duration of this authenticator.
    pub fn new(
        client: hyper::Client<C>,
        inner: T,
        delegate: AD,
    ) -> Authenticator<T, MemoryStorage, AD, C> {
        Authenticator {
            client: client,
            inner: Arc::new(Mutex::new(inner)),
            store: Arc::new(Mutex::new(MemoryStorage::new())),
            delegate: delegate,
        }
    }
}

impl<T: GetToken, AD: AuthenticatorDelegate, C: hyper::client::connect::Connect>
    Authenticator<T, DiskTokenStorage, AD, C>
{
    /// Create an Authenticator using the store at `path`.
    pub fn new_disk<P: AsRef<str>>(
        client: hyper::Client<C>,
        inner: T,
        delegate: AD,
        token_storage_path: P,
    ) -> io::Result<Authenticator<T, DiskTokenStorage, AD, C>> {
        Ok(Authenticator {
            client: client,
            inner: Arc::new(Mutex::new(inner)),
            store: Arc::new(Mutex::new(DiskTokenStorage::new(token_storage_path)?)),
            delegate: delegate,
        })
    }
}

impl<
        GT: 'static + GetToken + Send,
        S: 'static + TokenStorage + Send,
        AD: 'static + AuthenticatorDelegate + Send,
        C: 'static + hyper::client::connect::Connect + Clone + Send,
    > GetToken for Authenticator<GT, S, AD, C>
{
    /// Returns the API Key of the inner flow.
    fn api_key(&mut self) -> Option<String> {
        self.inner.lock().unwrap().api_key()
    }
    /// Returns the application secret of the inner flow.
    fn application_secret(&self) -> ApplicationSecret {
        self.inner.lock().unwrap().application_secret()
    }

    fn token<'b, I, T>(
        &mut self,
        scopes: I,
    ) -> Box<dyn Future<Item = Token, Error = Box<dyn Error + Send>> + Send>
    where
        T: AsRef<str> + Ord + 'b,
        I: Iterator<Item = &'b T>,
    {
        let (scope_key, scopes) = hash_scopes(scopes);
        let store = self.store.clone();
        let mut delegate = self.delegate.clone();
        let client = self.client.clone();
        let appsecret = self.inner.lock().unwrap().application_secret();
        let gettoken = self.inner.clone();
        let loopfn = move |()| -> Box<
            dyn Future<Item = future::Loop<Token, ()>, Error = Box<dyn Error + Send>> + Send,
        > {
            // How well does this work with tokio?
            match store.lock().unwrap().get(
                scope_key.clone(),
                &scopes.iter().map(|s| s.as_str()).collect(),
            ) {
                Ok(Some(t)) => {
                    if !t.expired() {
                        return Box::new(Ok(future::Loop::Break(t)).into_future());
                    }
                    // Implement refresh flow.
                    let refresh_token = t.refresh_token.clone();
                    let mut delegate = delegate.clone();
                    let store = store.clone();
                    let scopes = scopes.clone();
                    let refresh_fut = RefreshFlow::refresh_token(
                        client.clone(),
                        appsecret.clone(),
                        refresh_token,
                    )
                        .and_then(move |rr| -> Box<dyn Future<Item=future::Loop<Token, ()>, Error=Box<dyn Error+Send>> + Send> {
                            match rr {
                                RefreshResult::Error(e) => {
                                    delegate.token_refresh_failed(
                                        format!("{}", e.description().to_string()),
                                        &Some("the request has likely timed out".to_string()),
                                        );
                                    Box::new(Err(Box::new(e) as Box<dyn Error + Send>).into_future())
                                }
                                RefreshResult::RefreshError(ref s, ref ss) => {
                                    delegate.token_refresh_failed(
                                        format!("{} {}", s, ss.clone().map(|s| format!("({})", s)).unwrap_or("".to_string())),
                                        &Some("the refresh token is likely invalid and your authorization has been revoked".to_string()),
                                        );
                                    Box::new(Err(Box::new(StringError::new(s.to_string(), ss.as_ref())) as Box<dyn Error + Send>).into_future())
                                }
                                RefreshResult::Success(t) => {
                                    if let Err(e) = store.lock().unwrap().set(scope_key, &scopes.iter().map(|s| s.as_str()).collect(), Some(t.clone())) {
                                        match delegate.token_storage_failure(true, &e) {
                                            Retry::Skip => Box::new(Ok(future::Loop::Break(t)).into_future()),
                                            Retry::Abort => Box::new(Err(Box::new(e) as Box<dyn Error + Send>).into_future()),
                                            Retry::After(d) => Box::new(
                                                tokio_timer::sleep(d)
                                                .then(|_| Ok(future::Loop::Continue(()))),
                                                )
                                                as Box<
                                                dyn Future<
                                                Item = future::Loop<Token, ()>,
                                                Error = Box<dyn Error + Send>,
                                                > + Send,
                                                >,
                                        }
                                    } else {
                                        Box::new(Ok(future::Loop::Break(t)).into_future())
                                    }
                                },
                            }
                        });
                    Box::new(refresh_fut)
                }
                Ok(None) => {
                    let store = store.clone();
                    let scopes = scopes.clone();
                    let mut delegate = delegate.clone();
                    Box::new(
                        gettoken
                            .lock()
                            .unwrap()
                            .token(scopes.iter())
                            .and_then(move |t| {
                                if let Err(e) = store.lock().unwrap().set(
                                    scope_key,
                                    &scopes.iter().map(|s| s.as_str()).collect(),
                                    Some(t.clone()),
                                ) {
                                    match delegate.token_storage_failure(true, &e) {
                                        Retry::Skip => {
                                            Box::new(Ok(future::Loop::Break(t)).into_future())
                                        }
                                        Retry::Abort => Box::new(
                                            Err(Box::new(e) as Box<dyn Error + Send>).into_future(),
                                        ),
                                        Retry::After(d) => Box::new(
                                            tokio_timer::sleep(d)
                                                .then(|_| Ok(future::Loop::Continue(()))),
                                        )
                                            as Box<
                                                dyn Future<
                                                        Item = future::Loop<Token, ()>,
                                                        Error = Box<dyn Error + Send>,
                                                    > + Send,
                                            >,
                                    }
                                } else {
                                    Box::new(Ok(future::Loop::Break(t)).into_future())
                                }
                            }),
                    )
                }
                Err(err) => match delegate.token_storage_failure(false, &err) {
                    Retry::Abort | Retry::Skip => {
                        return Box::new(future::err(Box::new(err) as Box<dyn Error + Send>))
                    }
                    Retry::After(d) => {
                        return Box::new(
                            tokio_timer::sleep(d).then(|_| Ok(future::Loop::Continue(()))),
                        )
                    }
                },
            }
        };
        Box::new(future::loop_fn((), loopfn))
    }
}
<|endoftext|>


<commit_before>// Uncomment the following line to disable unstable warnings:
// #![allow(unstable)]

extern crate regex;
use regex::Regex;
use std::ascii::AsciiExt;
// use std::collections;
use std::io;
use std::io::{BufferedReader, File, IoResult};

pub mod config;
pub mod btree_map;

fn do_work(cfg: &config::Config) -> IoResult<()> {
    // Open input and output files
    let mut readers = vec![];
    if cfg.input.is_empty() {
        readers.push(BufferedReader::new(Box::new(io::stdin()) as Box<Reader>));
    } else {
        for name in cfg.input.iter() {
            let file = try!(File::open(&Path::new(name.as_slice())));
            readers.push(BufferedReader::new(Box::new(file) as Box<Reader>));
        }
    }
    let mut writer = match cfg.output {
        Some(ref x) => { Box::new(try!(File::create(&Path::new(x.as_slice())))) as Box<Writer> }
        None => { Box::new(io::stdout()) as Box<Writer> }
    };

    // Parse words
    let mut map = btree_map::BTreeMap::<String, u32>::new();
    // let mut map = collections::BTreeMap::<String, u32>::new();
    let re = Regex::new(r"\w+").unwrap();
    for reader in readers.iter_mut() {
        for line in reader.lines() {
            for caps in re.captures_iter(line.unwrap().as_slice()) {
                if let Some(cap) = caps.at(0) {
                    let word = match cfg.ignore_case {
                        true  => cap.to_ascii_lowercase(),
                        false => cap.to_string(),
                    };
                    let found = match map.get_mut(&word) {
                        Some(count) => { *count = *count + 1; true }
                        None => false,
                    };
                    if !found {
                        map.insert(word, 1);
                    }
                }
            }
        }
    }

    // Write counts
    for (k, v) in map.iter() {
        let line = format!("{}\t{}\n", v, k);
        try!(writer.write(line.as_bytes()));
    }
    Ok(())
}

#[cfg(not(test))]
fn main() {
    let cfg = match config::get_config(std::os::args()) {
        Ok(c) => c,
        Err(usage) => {
            println!("{}", usage);
            return;
        }
    };
    do_work(&cfg).unwrap();
}

#[test]
fn test_do_work() {
    let bad_filename = "/..no-such-file..";
    let cfg = config::Config {
        input: vec![bad_filename.to_string()],
        output: None,
        ignore_case: false,
    };
    match do_work(&cfg) {
        // should fail for bad input file (couldn't open file ... path=/..no-such-file..; ...)
        Err(e) => assert!(format!("{}", e).as_slice().contains(bad_filename), format!("{}", e)),
        _ => panic!()
    }
}

<commit_msg>Use collections::HashMap for fair comparison with the Nim version<commit_after>// Uncomment the following line to disable unstable warnings:
// #![allow(unstable)]

extern crate regex;
use regex::Regex;
use std::ascii::AsciiExt;
use std::collections;
use std::io;
use std::io::{BufferedReader, File, IoResult};

pub mod config;
pub mod btree_map;

fn do_work(cfg: &config::Config) -> IoResult<()> {
    // Open input and output files
    let mut readers = vec![];
    if cfg.input.is_empty() {
        readers.push(BufferedReader::new(Box::new(io::stdin()) as Box<Reader>));
    } else {
        for name in cfg.input.iter() {
            let file = try!(File::open(&Path::new(name.as_slice())));
            readers.push(BufferedReader::new(Box::new(file) as Box<Reader>));
        }
    }
    let mut writer = match cfg.output {
        Some(ref x) => { Box::new(try!(File::create(&Path::new(x.as_slice())))) as Box<Writer> }
        None => { Box::new(io::stdout()) as Box<Writer> }
    };

    // Parse words
    let mut map = collections::HashMap::<String, u32>::new();
    // let mut map = btree_map::BTreeMap::<String, u32>::new();
    let re = Regex::new(r"\w+").unwrap();
    for reader in readers.iter_mut() {
        for line in reader.lines() {
            for caps in re.captures_iter(line.unwrap().as_slice()) {
                if let Some(cap) = caps.at(0) {
                    let word = match cfg.ignore_case {
                        true  => cap.to_ascii_lowercase(),
                        false => cap.to_string(),
                    };
                    let found = match map.get_mut(&word) {
                        Some(count) => { *count = *count + 1; true }
                        None => false,
                    };
                    if !found {
                        map.insert(word, 1);
                    }
                }
            }
        }
    }

    // Write counts
    let mut words: Vec<&String> = map.keys().collect();
    words.sort();
    for word in words.iter() {
        if let Some(count) = map.get(*word) {
            let line = format!("{}\t{}\n", count, word);
            try!(writer.write(line.as_bytes()));
        }
    }
    Ok(())
}

#[cfg(not(test))]
fn main() {
    let cfg = match config::get_config(std::os::args()) {
        Ok(c) => c,
        Err(usage) => {
            println!("{}", usage);
            return;
        }
    };
    do_work(&cfg).unwrap();
}

#[test]
fn test_do_work() {
    let bad_filename = "/..no-such-file..";
    let cfg = config::Config {
        input: vec![bad_filename.to_string()],
        output: None,
        ignore_case: false,
    };
    match do_work(&cfg) {
        // should fail for bad input file (couldn't open file ... path=/..no-such-file..; ...)
        Err(e) => assert!(format!("{}", e).as_slice().contains(bad_filename), format!("{}", e)),
        _ => panic!()
    }
}

<|endoftext|>


<commit_before>pub mod bitread;
pub mod byteread;
pub mod bytewrite;

<commit_msg>bitstream: Add tagl and tagb macros<commit_after>pub mod bitread;
pub mod byteread;
pub mod bytewrite;

#[macro_export]
macro_rules! tagl {
    ($a:expr, $b:expr, $c:expr, $d:expr) => {
        ($a as u32) |
        ($b as u32) << 8 |
        ($c as u32) << 16 |
        ($d as u32) << 24
    }
}

#[macro_export]
macro_rules! tagb {
    ($a:expr, $b:expr, $c:expr, $d:expr) => {
        tagl!($d, $c, $b, $a)
    }
}

// TODO: write meaningful tests.
#[cfg(test)]
mod test {
    #[test]
    fn tags() {
        assert_eq!(tagl!('a', 'b', 'c', 'd'), 1684234849u32);
        assert_eq!(tagb!('a', 'b', 'c', 'd'), 1633837924u32);
    }
}
<|endoftext|>


<commit_before>use super::{ASTNode, SymbolTable};

use std::rc::Rc;
use std::borrow::Borrow;
use std::hash::Hash;

// pub type STCell<'a> = Rc<RefCell<SymbolTable<'a>>>;

pub struct Annotated<'a, T> where T: ASTNode {
    node: T, scope: Rc<SymbolTable<'a>>
}

impl<'a, T> Annotated<'a, T> where T: ASTNode {

    /// Get the type signature associated with the given name.
    ///
    /// This returns a borrowed reference to the type signature
    /// associated with that name in the current scope. The argument
    /// can be any type `Q` such that `String: Borrow<Q>` (i.e.
    /// you can pass an `&str` to this function).
    pub fn get_type<Q: ?Sized>(&self, name: &Q) -> Option<&Type>
    where String: Borrow<Q>, Q: Hash + Eq {
        self.scope.get(name)
    }

    /// Check if the given name is defined in this scope.
    ///
    /// The argument can be any type `Q` such that `String: Borrow<Q>`
    /// (i.e. you can pass an `&str` to this function).
    pub fn is_defined_here<Q: ?Sized>(&self, name: &Q) -> bool
    where String: Borrow<Q>, Q: Hash + Eq {
        self.scope.contains_key(name)
    }

}

#[derive(Debug, Clone)]
pub enum Type {
    /// Reference types
    Ref(Reference),
    /// Primitive types
    Prim(Primitive),
    /// An algebraic data type.
    ///
    /// Represented as a vector of variants.
    Algebraic(Vec<Type>),
    /// A function.
    ///
    /// Represented as a vector of parameters and a return type.
    Function { params: Vec<Type>
             , rt: Rc<Type> },
    /// A unique symbol type (`'symbol` syntax)
    Symbol(String)
}

/// Reference types (pointers)
///
/// TODO: how will lifetime analysis actually work?
#[derive(Debug, Clone)]
pub enum Reference {
    /// A reference borrowed from another scope.
    ///
    /// Semantically similar to Rust's `&`-pointers.
    ///
    /// TODO: should this track where it was borrowed from?
    /// (can we even perform this analysis at this stage?)
    Borrowed(Rc<Type>),
    /// A moved reference from another scope
    ///
    /// TODO: should this track where it was moved from?
    /// (can we even perform this analysis at this stage?)
    Moved(Rc<Type>),
    /// A unique (i.e. boxed) reference.
    Unique(Rc<Type>),
    /// A raw (unsafe) reference.
    ///
    /// Unfortunately we have to have this because of
    /// reasons (i.e, FFI).
    Raw(Rc<Type>)
}

/// Language primitive types
///
/// TODO: add some form of provable-refinement (i.e. we know that some value
/// is not just a bool at compile time but that it's true/false, or we know
/// some value is not just a number but the number 1382, or whatever).
#[derive(Debug, Clone, Copy)]
pub enum Primitive { Int
                   , Uint
                   , Byte
                   , Char
                   , Str
                   , Bool
                   , Float
                   , Double
                   // TODO: finish
                   }
<commit_msg>Implemented ops::Deref for Annotated Still need to figure out how our compilation walk will handle annotated nodes. This is maybe the wrong way to do it...<commit_after>use super::{ASTNode, SymbolTable};

use std::rc::Rc;
use std::borrow::Borrow;
use std::hash::Hash;
use std::ops;

// pub type STCell<'a> = Rc<RefCell<SymbolTable<'a>>>;

pub struct Annotated<'a, T> where T: ASTNode {
    node: T, scope: Rc<SymbolTable<'a>>
}

impl<'a, T> Annotated<'a, T> where T: ASTNode {

    /// Get the type signature associated with the given name.
    ///
    /// This returns a borrowed reference to the type signature
    /// associated with that name in the current scope. The argument
    /// can be any type `Q` such that `String: Borrow<Q>` (i.e.
    /// you can pass an `&str` to this function).
    pub fn get_type<Q: ?Sized>(&self, name: &Q) -> Option<&Type>
    where String: Borrow<Q>, Q: Hash + Eq {
        self.scope.get(name)
    }

    /// Check if the given name is defined in this scope.
    ///
    /// The argument can be any type `Q` such that `String: Borrow<Q>`
    /// (i.e. you can pass an `&str` to this function).
    pub fn is_defined_here<Q: ?Sized>(&self, name: &Q) -> bool
    where String: Borrow<Q>, Q: Hash + Eq {
        self.scope.contains_key(name)
    }

}

impl<'a, T> ops::Deref for Annotated<'a, T>
where T: ASTNode {
    type Target = T;
    fn deref(&self) -> &T { &self.node }
}

#[derive(Debug, Clone)]
pub enum Type {
    /// Reference types
    Ref(Reference),
    /// Primitive types
    Prim(Primitive),
    /// An algebraic data type.
    ///
    /// Represented as a vector of variants.
    Algebraic(Vec<Type>),
    /// A function.
    ///
    /// Represented as a vector of parameters and a return type.
    Function { params: Vec<Type>
             , rt: Rc<Type> },
    /// A unique symbol type (`'symbol` syntax)
    Symbol(String)
}

/// Reference types (pointers)
///
/// TODO: how will lifetime analysis actually work?
#[derive(Debug, Clone)]
pub enum Reference {
    /// A reference borrowed from another scope.
    ///
    /// Semantically similar to Rust's `&`-pointers.
    ///
    /// TODO: should this track where it was borrowed from?
    /// (can we even perform this analysis at this stage?)
    Borrowed(Rc<Type>),
    /// A moved reference from another scope
    ///
    /// TODO: should this track where it was moved from?
    /// (can we even perform this analysis at this stage?)
    Moved(Rc<Type>),
    /// A unique (i.e. boxed) reference.
    Unique(Rc<Type>),
    /// A raw (unsafe) reference.
    ///
    /// Unfortunately we have to have this because of
    /// reasons (i.e, FFI).
    Raw(Rc<Type>)
}

/// Language primitive types
///
/// TODO: add some form of provable-refinement (i.e. we know that some value
/// is not just a bool at compile time but that it's true/false, or we know
/// some value is not just a number but the number 1382, or whatever).
#[derive(Debug, Clone, Copy)]
pub enum Primitive { Int
                   , Uint
                   , Byte
                   , Char
                   , Str
                   , Bool
                   , Float
                   , Double
                   // TODO: finish
                   }
<|endoftext|>


<commit_before>//! ARMv8 intrinsics.
//!
//! The reference is [ARMv8-A Reference Manual][armv8].
//!
//! [armv8]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.
//! ddi0487a.k_10775/index.html

#[cfg(test)]
use stdsimd_test::assert_instr;

/// Reverse the order of the bytes.
#[inline(always)]
#[cfg_attr(test, assert_instr(rev))]
pub unsafe fn _rev_u64(x: u64) -> u64 {
    x.swap_bytes() as u64
}

/// Count Leading Zeros.
#[inline(always)]
#[cfg_attr(test, assert_instr(clz))]
pub unsafe fn _clz_u64(x: u64) -> u64 {
    x.leading_zeros() as u64
}

#[allow(dead_code)]
extern "C" {
    #[link_name = "llvm.bitreverse.i64"]
    fn rbit_u64(i: i64) -> i64;
}

/// Reverse the bit order.
#[inline(always)]
#[cfg_attr(test, assert_instr(rbit))]
pub unsafe fn _rbit_u64(x: u64) -> u64 {
    rbit_u64(x as i64) as u64
}

/// Counts the leading most significant bits set.
///
/// When all bits of the operand are set it returns the size of the operand in
/// bits.
#[inline(always)]
#[cfg_attr(test, assert_instr(cls))]
pub unsafe fn _cls_u32(x: u32) -> u32 {
    u32::leading_zeros(((((((x as i32) >> 31) as u32) ^ x) << 1) | 1)) as u32
}

/// Counts the leading most significant bits set.
///
/// When all bits of the operand are set it returns the size of the operand in
/// bits.
#[inline(always)]
#[cfg_attr(test, assert_instr(cls))]
pub unsafe fn _cls_u64(x: u64) -> u64 {
    u64::leading_zeros(((((((x as i64) >> 63) as u64) ^ x) << 1) | 1)) as u64
}

#[cfg(test)]
mod tests {
    use aarch64::v8;

    #[test]
    fn _rev_u64() {
        unsafe {
            assert_eq!(
                v8::_rev_u64(0b0000_0000_1111_1111_0000_0000_1111_1111_u64),
                0b1111_1111_0000_0000_1111_1111_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_u64
            );
        }
    }

    #[test]
    fn _clz_u64() {
        unsafe {
            assert_eq!(v8::_clz_u64(0b0000_1010u64), 60u64);
        }
    }

    #[test]
    fn _rbit_u64() {
        unsafe {
            assert_eq!(
                v8::_rbit_u64(0b0000_0000_1111_1101_0000_0000_1111_1111_u64),
                0b1111_1111_0000_0000_1011_1111_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_u64
            );
        }
    }

    #[test]
    fn _cls_u32() {
        unsafe {
            assert_eq!(
                v8::_cls_u32(0b1111_1111_1111_1111_0000_0000_1111_1111_u32),
                15_u32
            );
        }
    }

    #[test]
    fn _cls_u64() {
        unsafe {
            assert_eq!(
                v8::_cls_u64(
                    0b1111_1111_1111_1111_0000_0000_1111_1111_0000_0000_0000_0000_0000_0000_0000_0000_u64
                ),
                15_u64
            );
        }
    }
}
<commit_msg>Fix a lint warning on aarch64<commit_after>//! ARMv8 intrinsics.
//!
//! The reference is [ARMv8-A Reference Manual][armv8].
//!
//! [armv8]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.
//! ddi0487a.k_10775/index.html

#[cfg(test)]
use stdsimd_test::assert_instr;

/// Reverse the order of the bytes.
#[inline(always)]
#[cfg_attr(test, assert_instr(rev))]
pub unsafe fn _rev_u64(x: u64) -> u64 {
    x.swap_bytes() as u64
}

/// Count Leading Zeros.
#[inline(always)]
#[cfg_attr(test, assert_instr(clz))]
pub unsafe fn _clz_u64(x: u64) -> u64 {
    x.leading_zeros() as u64
}

#[allow(dead_code)]
extern "C" {
    #[link_name = "llvm.bitreverse.i64"]
    fn rbit_u64(i: i64) -> i64;
}

/// Reverse the bit order.
#[inline(always)]
#[cfg_attr(test, assert_instr(rbit))]
pub unsafe fn _rbit_u64(x: u64) -> u64 {
    rbit_u64(x as i64) as u64
}

/// Counts the leading most significant bits set.
///
/// When all bits of the operand are set it returns the size of the operand in
/// bits.
#[inline(always)]
#[cfg_attr(test, assert_instr(cls))]
pub unsafe fn _cls_u32(x: u32) -> u32 {
    u32::leading_zeros((((((x as i32) >> 31) as u32) ^ x) << 1) | 1) as u32
}

/// Counts the leading most significant bits set.
///
/// When all bits of the operand are set it returns the size of the operand in
/// bits.
#[inline(always)]
#[cfg_attr(test, assert_instr(cls))]
pub unsafe fn _cls_u64(x: u64) -> u64 {
    u64::leading_zeros((((((x as i64) >> 63) as u64) ^ x) << 1) | 1) as u64
}

#[cfg(test)]
mod tests {
    use aarch64::v8;

    #[test]
    fn _rev_u64() {
        unsafe {
            assert_eq!(
                v8::_rev_u64(0b0000_0000_1111_1111_0000_0000_1111_1111_u64),
                0b1111_1111_0000_0000_1111_1111_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_u64
            );
        }
    }

    #[test]
    fn _clz_u64() {
        unsafe {
            assert_eq!(v8::_clz_u64(0b0000_1010u64), 60u64);
        }
    }

    #[test]
    fn _rbit_u64() {
        unsafe {
            assert_eq!(
                v8::_rbit_u64(0b0000_0000_1111_1101_0000_0000_1111_1111_u64),
                0b1111_1111_0000_0000_1011_1111_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_u64
            );
        }
    }

    #[test]
    fn _cls_u32() {
        unsafe {
            assert_eq!(
                v8::_cls_u32(0b1111_1111_1111_1111_0000_0000_1111_1111_u32),
                15_u32
            );
        }
    }

    #[test]
    fn _cls_u64() {
        unsafe {
            assert_eq!(
                v8::_cls_u64(
                    0b1111_1111_1111_1111_0000_0000_1111_1111_0000_0000_0000_0000_0000_0000_0000_0000_u64
                ),
                15_u64
            );
        }
    }
}
<|endoftext|>


<commit_before>extern crate luthor;

use std::rc::Rc;
use std::cell::RefCell;
use std::str::from_utf8;
use std::fs::File;
use std::io;
use std::io::{Read, Write};
use std::path::PathBuf;
use super::GapBuffer;
use super::gap_buffer;
use super::Position;
use super::Range;
use super::Cursor;
use super::type_detection;
use self::luthor::token::{Token, Category};
use self::luthor::lexers;

/// A UTF-8 buffer with bounds-checked cursor management and persistence.
pub struct Buffer {
    data: Rc<RefCell<GapBuffer>>,
    lexer: Option<fn(&str) -> Vec<Token>>,
    pub path: Option<PathBuf>,
    pub cursor: Cursor,
}

impl Buffer {
    /// Returns the contents of the buffer as a string.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::new();
    /// buffer.insert("scribe");
    /// assert_eq!(buffer.data(), "scribe");
    /// ```
    pub fn data(&self) -> String {
        self.data.borrow().to_string()
    }

    /// Writes the contents of the buffer to its path.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::path::PathBuf;
    /// # use std::path::Path;
    /// # use std::fs::File;
    /// # use std::io::Read;
    ///
    /// // Set up a buffer and point it to a path.
    /// let mut buffer = scribe::buffer::new();
    /// let write_path = PathBuf::new("my_doc");
    /// buffer.path = Some(write_path.clone());
    ///
    /// // Put some data into the buffer and save it.
    /// buffer.insert("scribe");
    /// buffer.save();
    ///
    /// # let mut saved_data = String::new();
    /// # File::open(Path::new("my_doc")).unwrap().
    /// #   read_to_string(&mut saved_data).unwrap();
    /// # assert_eq!(saved_data, "scribe");
    ///
    /// # std::fs::remove_file(&write_path);
    /// ```
    pub fn save(&self) -> Option<io::Error> {
        let path = match self.path.clone() {
            Some(p) => p,
            None => PathBuf::new(""),
        };

        // Try to open and write to the file, returning any errors encountered.
        let mut file = match File::create(&path) {
            Ok(f) => f,
            Err(error) => return Some(error),
        };

        // We use to_string here because we don't want to write the gap contents.
        match file.write_all(self.data().to_string().as_bytes()) {
            Ok(_) => (),
            Err(error) => return Some(error),
        }

        return None
    }

    /// Inserts `data` into the buffer at the cursor position.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::new();
    /// buffer.insert("scribe");
    /// assert_eq!(buffer.data(), "scribe");
    /// ```
    pub fn insert(&mut self, data: &str) {
        self.data.borrow_mut().insert(data, &self.cursor);
    }

    /// Deletes a character at the cursor position. If at the end
    /// of the current line, it'll try to delete a newline character
    /// (joining the lines), succeeding if there's a line below.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::new();
    /// buffer.insert("scribe");
    /// buffer.delete();
    /// assert_eq!(buffer.data(), "cribe");
    /// ```
    pub fn delete(&mut self) {
        // We need to specify a range to delete, so start at
        // the current offset and delete the character to the right.
        let mut end = Position{ line: self.cursor.line, offset: self.cursor.offset + 1 };

        // If there isn't a character to the right,
        // delete the newline by jumping to the start
        // of the next line. If it doesn't exist, that's okay;
        // these values are bounds-checked by delete() anyway.
        if !self.data.borrow().in_bounds(&end) {
            end.line += 1;
            end.offset = 0;
        }

        self.data.borrow_mut().delete(&Range{ start: *self.cursor, end: end});
    }

    /// Produces a set of tokens based on the buffer data
    /// suitable for colorized display, using a lexer for the
    /// buffer data's language and/or format. If a lexer is not
    /// available, the set will consist of a single text-category token.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::new();
    /// buffer.insert("scribe");
    ///
    /// // Build the buffer data string back by combining its token lexemes.
    /// let mut data = String::new();
    /// for token in buffer.tokens().iter() {
    ///     data.push_str(token.lexeme.as_slice());
    /// }
    /// assert_eq!(data, "scribe");
    /// ```
    pub fn tokens(&self) -> Vec<Token> {
        match self.lexer {
            Some(lexer) => lexer(&self.data()),
            None => vec![Token{ lexeme: self.data(), category: Category::Text }],
        }
    }

    /// Returns the file name portion of the buffer's path, if
    /// the path is set and its file name is a valid UTF-8 sequence.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::path::PathBuf;
    ///
    /// let buffer = scribe::buffer::from_file(PathBuf::new("tests/sample/file")).unwrap();
    /// assert_eq!(buffer.file_name().unwrap(), "file");
    /// ```
    pub fn file_name(&self) -> Option<String> {
        match self.path {
            Some(ref path) => {
                match path.file_name() {
                    Some(file_name) => {
                        match file_name.to_str() {
                            Some(utf8_file_name) => Some(utf8_file_name.to_string()),
                            None => None,
                        }
                    },
                    None => None,
                }
            },
            None => None,
        }
    }
}

/// Creates a new empty buffer. The buffer's cursor is set to the beginning of the buffer.
///
/// # Examples
///
/// ```
/// let buffer = scribe::buffer::new();
/// # assert_eq!(buffer.cursor.line, 0);
/// # assert_eq!(buffer.cursor.offset, 0);
/// ```
pub fn new() -> Buffer {
    let data = Rc::new(RefCell::new(gap_buffer::new(String::new())));
    let cursor = Cursor{ data: data.clone(), position: Position{ line: 0, offset: 0 }};

    Buffer{ data: data.clone(), path: None, cursor: cursor, lexer: None }
}

/// Creates a new buffer by reading the UTF-8 interpreted file contents of the specified path.
/// The buffer's cursor is set to the beginning of the buffer. The buffer data's type will be
/// inferred based on its extension, and an appropriate lexer will be used, if available (see
/// tokens method for further information on why this happens).
///
/// # Examples
///
/// ```
/// use std::path::PathBuf;
///
/// let buffer = scribe::buffer::from_file(PathBuf::new("tests/sample/file")).unwrap();
/// assert_eq!(buffer.data(), "it works!\n");
/// # assert_eq!(buffer.cursor.line, 0);
/// # assert_eq!(buffer.cursor.offset, 0);
/// ```
pub fn from_file(path: PathBuf) -> io::Result<Buffer> {
    // Try to open and read the file, returning any errors encountered.
    let mut file = match File::open(path.clone()) {
        Ok(f) => f,
        Err(error) => return Err(error),
    };
    let mut data = String::new();
    match file.read_to_string(&mut data) {
        Ok(_) => (),
        Err(error) => return Err(error),
    };

    let data = Rc::new(RefCell::new(gap_buffer::new(data)));
    let cursor = Cursor{ data: data.clone(), position: Position{ line: 0, offset: 0 }};

    // Detect the file type and use its corresponding lexer, if available.
    let lexer = match type_detection::from_path(&path) {
        Some(type_detection::Type::JSON) => Some(lexers::json::lex as fn(&str) -> Vec<Token>),
        Some(type_detection::Type::XML) => Some(lexers::xml::lex as fn(&str) -> Vec<Token>),
        _ => None,
    };

    // Create a new buffer using the loaded data, path, and other defaults.
    Ok(Buffer{ data: data.clone(), path: Some(path), cursor: cursor, lexer: lexer })
}

#[cfg(test)]
mod tests {
    use super::new;
    use super::luthor::token::{Token, Category};

    fn placeholder_lexer(_: &str) -> Vec<Token> {
        vec![Token{ lexeme: "lexer".to_string(), category: Category::Text }]
    }

    #[test]
    fn tokens_returns_one_text_token_when_no_lexer_is_set() {
        let mut buffer = new();
        buffer.insert("scribe");
        let expected_tokens = vec![Token{ lexeme: "scribe".to_string(), category: Category::Text }];
        assert_eq!(buffer.tokens(), expected_tokens);
    }

    #[test]
    fn tokens_returns_result_of_lexer_when_set() {
        let mut buffer = new();
        let expected_tokens = placeholder_lexer("scribe");
        buffer.lexer = Some(placeholder_lexer);
        assert_eq!(buffer.tokens(), expected_tokens);
    }

    #[test]
    fn delete_joins_lines_when_invoked_at_end_of_line() {
        let mut buffer = new();
        buffer.insert("scribe\n library");
        buffer.cursor.move_to_end_of_line();
        buffer.delete();
        assert_eq!(buffer.data(), "scribe library");
    }

    #[test]
    fn delete_does_nothing_when_invoked_at_the_end_of_the_document() {
        let mut buffer = new();
        buffer.insert("scribe\n library");
        buffer.cursor.move_down();
        buffer.cursor.move_to_end_of_line();
        buffer.delete();
        assert_eq!(buffer.data(), "scribe\n library");
    }
}
<commit_msg>Use new String -> &str coercion.<commit_after>extern crate luthor;

use std::rc::Rc;
use std::cell::RefCell;
use std::str::from_utf8;
use std::fs::File;
use std::io;
use std::io::{Read, Write};
use std::path::PathBuf;
use super::GapBuffer;
use super::gap_buffer;
use super::Position;
use super::Range;
use super::Cursor;
use super::type_detection;
use self::luthor::token::{Token, Category};
use self::luthor::lexers;

/// A UTF-8 buffer with bounds-checked cursor management and persistence.
pub struct Buffer {
    data: Rc<RefCell<GapBuffer>>,
    lexer: Option<fn(&str) -> Vec<Token>>,
    pub path: Option<PathBuf>,
    pub cursor: Cursor,
}

impl Buffer {
    /// Returns the contents of the buffer as a string.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::new();
    /// buffer.insert("scribe");
    /// assert_eq!(buffer.data(), "scribe");
    /// ```
    pub fn data(&self) -> String {
        self.data.borrow().to_string()
    }

    /// Writes the contents of the buffer to its path.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::path::PathBuf;
    /// # use std::path::Path;
    /// # use std::fs::File;
    /// # use std::io::Read;
    ///
    /// // Set up a buffer and point it to a path.
    /// let mut buffer = scribe::buffer::new();
    /// let write_path = PathBuf::new("my_doc");
    /// buffer.path = Some(write_path.clone());
    ///
    /// // Put some data into the buffer and save it.
    /// buffer.insert("scribe");
    /// buffer.save();
    ///
    /// # let mut saved_data = String::new();
    /// # File::open(Path::new("my_doc")).unwrap().
    /// #   read_to_string(&mut saved_data).unwrap();
    /// # assert_eq!(saved_data, "scribe");
    ///
    /// # std::fs::remove_file(&write_path);
    /// ```
    pub fn save(&self) -> Option<io::Error> {
        let path = match self.path.clone() {
            Some(p) => p,
            None => PathBuf::new(""),
        };

        // Try to open and write to the file, returning any errors encountered.
        let mut file = match File::create(&path) {
            Ok(f) => f,
            Err(error) => return Some(error),
        };

        // We use to_string here because we don't want to write the gap contents.
        match file.write_all(self.data().to_string().as_bytes()) {
            Ok(_) => (),
            Err(error) => return Some(error),
        }

        return None
    }

    /// Inserts `data` into the buffer at the cursor position.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::new();
    /// buffer.insert("scribe");
    /// assert_eq!(buffer.data(), "scribe");
    /// ```
    pub fn insert(&mut self, data: &str) {
        self.data.borrow_mut().insert(data, &self.cursor);
    }

    /// Deletes a character at the cursor position. If at the end
    /// of the current line, it'll try to delete a newline character
    /// (joining the lines), succeeding if there's a line below.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::new();
    /// buffer.insert("scribe");
    /// buffer.delete();
    /// assert_eq!(buffer.data(), "cribe");
    /// ```
    pub fn delete(&mut self) {
        // We need to specify a range to delete, so start at
        // the current offset and delete the character to the right.
        let mut end = Position{ line: self.cursor.line, offset: self.cursor.offset + 1 };

        // If there isn't a character to the right,
        // delete the newline by jumping to the start
        // of the next line. If it doesn't exist, that's okay;
        // these values are bounds-checked by delete() anyway.
        if !self.data.borrow().in_bounds(&end) {
            end.line += 1;
            end.offset = 0;
        }

        self.data.borrow_mut().delete(&Range{ start: *self.cursor, end: end});
    }

    /// Produces a set of tokens based on the buffer data
    /// suitable for colorized display, using a lexer for the
    /// buffer data's language and/or format. If a lexer is not
    /// available, the set will consist of a single text-category token.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::new();
    /// buffer.insert("scribe");
    ///
    /// // Build the buffer data string back by combining its token lexemes.
    /// let mut data = String::new();
    /// for token in buffer.tokens().iter() {
    ///     data.push_str(&token.lexeme);
    /// }
    /// assert_eq!(data, "scribe");
    /// ```
    pub fn tokens(&self) -> Vec<Token> {
        match self.lexer {
            Some(lexer) => lexer(&self.data()),
            None => vec![Token{ lexeme: self.data(), category: Category::Text }],
        }
    }

    /// Returns the file name portion of the buffer's path, if
    /// the path is set and its file name is a valid UTF-8 sequence.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::path::PathBuf;
    ///
    /// let buffer = scribe::buffer::from_file(PathBuf::new("tests/sample/file")).unwrap();
    /// assert_eq!(buffer.file_name().unwrap(), "file");
    /// ```
    pub fn file_name(&self) -> Option<String> {
        match self.path {
            Some(ref path) => {
                match path.file_name() {
                    Some(file_name) => {
                        match file_name.to_str() {
                            Some(utf8_file_name) => Some(utf8_file_name.to_string()),
                            None => None,
                        }
                    },
                    None => None,
                }
            },
            None => None,
        }
    }
}

/// Creates a new empty buffer. The buffer's cursor is set to the beginning of the buffer.
///
/// # Examples
///
/// ```
/// let buffer = scribe::buffer::new();
/// # assert_eq!(buffer.cursor.line, 0);
/// # assert_eq!(buffer.cursor.offset, 0);
/// ```
pub fn new() -> Buffer {
    let data = Rc::new(RefCell::new(gap_buffer::new(String::new())));
    let cursor = Cursor{ data: data.clone(), position: Position{ line: 0, offset: 0 }};

    Buffer{ data: data.clone(), path: None, cursor: cursor, lexer: None }
}

/// Creates a new buffer by reading the UTF-8 interpreted file contents of the specified path.
/// The buffer's cursor is set to the beginning of the buffer. The buffer data's type will be
/// inferred based on its extension, and an appropriate lexer will be used, if available (see
/// tokens method for further information on why this happens).
///
/// # Examples
///
/// ```
/// use std::path::PathBuf;
///
/// let buffer = scribe::buffer::from_file(PathBuf::new("tests/sample/file")).unwrap();
/// assert_eq!(buffer.data(), "it works!\n");
/// # assert_eq!(buffer.cursor.line, 0);
/// # assert_eq!(buffer.cursor.offset, 0);
/// ```
pub fn from_file(path: PathBuf) -> io::Result<Buffer> {
    // Try to open and read the file, returning any errors encountered.
    let mut file = match File::open(path.clone()) {
        Ok(f) => f,
        Err(error) => return Err(error),
    };
    let mut data = String::new();
    match file.read_to_string(&mut data) {
        Ok(_) => (),
        Err(error) => return Err(error),
    };

    let data = Rc::new(RefCell::new(gap_buffer::new(data)));
    let cursor = Cursor{ data: data.clone(), position: Position{ line: 0, offset: 0 }};

    // Detect the file type and use its corresponding lexer, if available.
    let lexer = match type_detection::from_path(&path) {
        Some(type_detection::Type::JSON) => Some(lexers::json::lex as fn(&str) -> Vec<Token>),
        Some(type_detection::Type::XML) => Some(lexers::xml::lex as fn(&str) -> Vec<Token>),
        _ => None,
    };

    // Create a new buffer using the loaded data, path, and other defaults.
    Ok(Buffer{ data: data.clone(), path: Some(path), cursor: cursor, lexer: lexer })
}

#[cfg(test)]
mod tests {
    use super::new;
    use super::luthor::token::{Token, Category};

    fn placeholder_lexer(_: &str) -> Vec<Token> {
        vec![Token{ lexeme: "lexer".to_string(), category: Category::Text }]
    }

    #[test]
    fn tokens_returns_one_text_token_when_no_lexer_is_set() {
        let mut buffer = new();
        buffer.insert("scribe");
        let expected_tokens = vec![Token{ lexeme: "scribe".to_string(), category: Category::Text }];
        assert_eq!(buffer.tokens(), expected_tokens);
    }

    #[test]
    fn tokens_returns_result_of_lexer_when_set() {
        let mut buffer = new();
        let expected_tokens = placeholder_lexer("scribe");
        buffer.lexer = Some(placeholder_lexer);
        assert_eq!(buffer.tokens(), expected_tokens);
    }

    #[test]
    fn delete_joins_lines_when_invoked_at_end_of_line() {
        let mut buffer = new();
        buffer.insert("scribe\n library");
        buffer.cursor.move_to_end_of_line();
        buffer.delete();
        assert_eq!(buffer.data(), "scribe library");
    }

    #[test]
    fn delete_does_nothing_when_invoked_at_the_end_of_the_document() {
        let mut buffer = new();
        buffer.insert("scribe\n library");
        buffer.cursor.move_down();
        buffer.cursor.move_to_end_of_line();
        buffer.delete();
        assert_eq!(buffer.data(), "scribe\n library");
    }
}
<|endoftext|>