<commit_before>use std::{
    hash::Hash,
    iter::{from_fn, FromIterator},
};

use indexmap::IndexSet;

use crate::{
    Direction::Outgoing,
    visit::{
        GraphBase,
        IntoNeighborsDirected,
        NodeCount,
    },
};

/// Returns iterator that produces all simple paths from `from` node to `to`, which contains at least `min_intermidiate_nodes` nodes
/// and at most `max_intermidiate_nodes`, if given, limited by graph's order otherwise
/// Simple path is path without repetitions
/// Algorithm is adopted from https://networkx.github.io/documentation/stable/reference/algorithms/generated/networkx.algorithms.simple_paths.all_simple_paths.html
pub fn all_simple_paths<'g, TargetColl: 'g, G>(graph: &'g G,
                                               from: G::NodeId,
                                               to: G::NodeId,
                                               min_intermidiate_nodes: usize,
                                               max_intermidiate_nodes: Option<usize>) -> impl Iterator<Item=TargetColl> + 'g
    where G: NodeCount,
          G: GraphBase<NodeId=<&'g G as GraphBase>::NodeId>,
          &'g G: IntoNeighborsDirected,
          G::NodeId: Eq + Hash,
          TargetColl: FromIterator<G::NodeId>
{
    // how many nodes are allowed in simple path up to target node
    // it is min/max allowed path length minus one, because it is more appropriate when implementing lookahead
    // than constantly add 1 to length of current path
    let max_length = if let Some(l) = max_intermidiate_nodes {
        l + 1
    } else {
        graph.node_count() - 1
    };

    let min_length = min_intermidiate_nodes + 1;

    // list of visited nodes
    let mut visited: IndexSet<G::NodeId> = IndexSet::from_iter(Some(from));
    // list of childs of currently exploring path nodes,
    // last elem is list of childs of last visited node
    let mut stack = vec![graph.neighbors_directed(from, Outgoing)];

    from_fn(move || {
        while let Some(children) = stack.last_mut() {
            if let Some(child) = children.next() {
                if visited.len() < max_length {
                    if child == to {
                        if visited.len() >= min_length {
                            let path = visited.iter().cloned().chain(Some(to)).collect::<TargetColl>();
                            return Some(path);
                        }
                    } else if !visited.contains(&child) {
                        visited.insert(child);
                        stack.push(graph.neighbors_directed(child, Outgoing));
                    }
                } else {
                    if (child == to || children.any(|v| v == to)) && visited.len() >= min_length {
                        let path = visited.iter().cloned().chain(Some(to)).collect::<TargetColl>();
                        return Some(path);
                    }
                    stack.pop();
                    visited.pop();
                }
            } else {
                stack.pop();
                visited.pop();
            }
        }
        None
    })
}

#[cfg(test)]
mod test {
    use std::{
        collections::HashSet,
        iter::FromIterator,
    };

    use itertools::assert_equal;

    use crate::{
        dot::Dot,
        prelude::DiGraph,
    };

    use super::all_simple_paths;

    #[test]
    fn test_all_simple_paths() {
        let graph = DiGraph::<i32, i32, _>::from_edges(&[
            (0, 1),
            (0, 2),
            (0, 3),
            (1, 2),
            (1, 3),
            (2, 3),
            (2, 4),
            (3, 2),
            (3, 4),
            (4, 2),
            (4, 5),
            (5, 2),
            (5, 3)
        ]);

        let expexted_simple_paths_0_to_5 = vec![
            vec![0usize, 1, 2, 3, 4, 5],
            vec![0, 1, 2, 4, 5],
            vec![0, 1, 3, 2, 4, 5],
            vec![0, 1, 3, 4, 5],
            vec![0, 2, 3, 4, 5],
            vec![0, 2, 4, 5],
            vec![0, 3, 2, 4, 5],
            vec![0, 3, 4, 5],
        ];

        println!("{}", Dot::new(&graph));
        let actual_simple_paths_0_to_5: HashSet<Vec<_>> = all_simple_paths(&graph, 0u32.into(), 5u32.into(), 0, None)
            .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
            .collect();
        assert_eq!(actual_simple_paths_0_to_5.len(), 8);
        assert_eq!(HashSet::from_iter(expexted_simple_paths_0_to_5), actual_simple_paths_0_to_5);
    }

    #[test]
    fn test_one_simple_path() {
        let graph = DiGraph::<i32, i32, _>::from_edges(&[
            (0, 1),
            (2, 1)
        ]);

        let expexted_simple_paths_0_to_1 = &[
            vec![0usize, 1],
        ];
        println!("{}", Dot::new(&graph));
        let actual_simple_paths_0_to_1: Vec<Vec<_>> = all_simple_paths(&graph, 0u32.into(), 1u32.into(), 0, None)
            .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
            .collect();

        assert_eq!(actual_simple_paths_0_to_1.len(), 1);
        assert_equal(expexted_simple_paths_0_to_1, &actual_simple_paths_0_to_1);
    }

    #[test]
    fn test_no_simple_paths() {
        let graph = DiGraph::<i32, i32, _>::from_edges(&[
            (0, 1),
            (2, 1)
        ]);

        println!("{}", Dot::new(&graph));
        let actual_simple_paths_0_to_2: Vec<Vec<_>> = all_simple_paths(&graph, 0u32.into(), 2u32.into(), 0, None)
            .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
            .collect();

        assert_eq!(actual_simple_paths_0_to_2.len(), 0);
    }
}
<commit_msg>Get rid of ref in signature<commit_after>use std::{
    hash::Hash,
    iter::{from_fn, FromIterator},
};

use indexmap::IndexSet;

use crate::{
    Direction::Outgoing,
    visit::{
        IntoNeighborsDirected,
        NodeCount,
    },
};

/// Returns iterator that produces all simple paths from `from` node to `to`, which contains at least `min_intermidiate_nodes` nodes
/// and at most `max_intermidiate_nodes`, if given, limited by graph's order otherwise
/// Simple path is path without repetitions
/// Algorithm is adopted from https://networkx.github.io/documentation/stable/reference/algorithms/generated/networkx.algorithms.simple_paths.all_simple_paths.html
pub fn all_simple_paths<TargetColl, G>(graph: G,
                                       from: G::NodeId,
                                       to: G::NodeId,
                                       min_intermidiate_nodes: usize,
                                       max_intermidiate_nodes: Option<usize>) -> impl Iterator<Item=TargetColl>
    where G: NodeCount,
          G: IntoNeighborsDirected,
          G::NodeId: Eq + Hash,
          TargetColl: FromIterator<G::NodeId>
{
    // how many nodes are allowed in simple path up to target node
    // it is min/max allowed path length minus one, because it is more appropriate when implementing lookahead
    // than constantly add 1 to length of current path
    let max_length = if let Some(l) = max_intermidiate_nodes {
        l + 1
    } else {
        graph.node_count() - 1
    };

    let min_length = min_intermidiate_nodes + 1;

    // list of visited nodes
    let mut visited: IndexSet<G::NodeId> = IndexSet::from_iter(Some(from));
    // list of childs of currently exploring path nodes,
    // last elem is list of childs of last visited node
    let mut stack = vec![graph.neighbors_directed(from, Outgoing)];

    from_fn(move || {
        while let Some(children) = stack.last_mut() {
            if let Some(child) = children.next() {
                if visited.len() < max_length {
                    if child == to {
                        if visited.len() >= min_length {
                            let path = visited.iter().cloned().chain(Some(to)).collect::<TargetColl>();
                            return Some(path);
                        }
                    } else if !visited.contains(&child) {
                        visited.insert(child);
                        stack.push(graph.neighbors_directed(child, Outgoing));
                    }
                } else {
                    if (child == to || children.any(|v| v == to)) && visited.len() >= min_length {
                        let path = visited.iter().cloned().chain(Some(to)).collect::<TargetColl>();
                        return Some(path);
                    }
                    stack.pop();
                    visited.pop();
                }
            } else {
                stack.pop();
                visited.pop();
            }
        }
        None
    })
}

#[cfg(test)]
mod test {
    use std::{
        collections::HashSet,
        iter::FromIterator,
    };

    use itertools::assert_equal;

    use crate::{
        dot::Dot,
        prelude::DiGraph,
    };

    use super::all_simple_paths;

    #[test]
    fn test_all_simple_paths() {
        let graph = DiGraph::<i32, i32, _>::from_edges(&[
            (0, 1),
            (0, 2),
            (0, 3),
            (1, 2),
            (1, 3),
            (2, 3),
            (2, 4),
            (3, 2),
            (3, 4),
            (4, 2),
            (4, 5),
            (5, 2),
            (5, 3)
        ]);

        let expexted_simple_paths_0_to_5 = vec![
            vec![0usize, 1, 2, 3, 4, 5],
            vec![0, 1, 2, 4, 5],
            vec![0, 1, 3, 2, 4, 5],
            vec![0, 1, 3, 4, 5],
            vec![0, 2, 3, 4, 5],
            vec![0, 2, 4, 5],
            vec![0, 3, 2, 4, 5],
            vec![0, 3, 4, 5],
        ];

        println!("{}", Dot::new(&graph));
        let actual_simple_paths_0_to_5: HashSet<Vec<_>> = all_simple_paths(&graph, 0u32.into(), 5u32.into(), 0, None)
            .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
            .collect();
        assert_eq!(actual_simple_paths_0_to_5.len(), 8);
        assert_eq!(HashSet::from_iter(expexted_simple_paths_0_to_5), actual_simple_paths_0_to_5);
    }

    #[test]
    fn test_one_simple_path() {
        let graph = DiGraph::<i32, i32, _>::from_edges(&[
            (0, 1),
            (2, 1)
        ]);

        let expexted_simple_paths_0_to_1 = &[
            vec![0usize, 1],
        ];
        println!("{}", Dot::new(&graph));
        let actual_simple_paths_0_to_1: Vec<Vec<_>> = all_simple_paths(&graph, 0u32.into(), 1u32.into(), 0, None)
            .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
            .collect();

        assert_eq!(actual_simple_paths_0_to_1.len(), 1);
        assert_equal(expexted_simple_paths_0_to_1, &actual_simple_paths_0_to_1);
    }

    #[test]
    fn test_no_simple_paths() {
        let graph = DiGraph::<i32, i32, _>::from_edges(&[
            (0, 1),
            (2, 1)
        ]);

        println!("{}", Dot::new(&graph));
        let actual_simple_paths_0_to_2: Vec<Vec<_>> = all_simple_paths(&graph, 0u32.into(), 2u32.into(), 0, None)
            .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
            .collect();

        assert_eq!(actual_simple_paths_0_to_2.len(), 0);
    }
}
<|endoftext|>


<commit_before>use libc::{self, c_int};

#[macro_use]
pub mod dlsym;

#[cfg(any(target_os = "linux", target_os = "android"))]
mod epoll;

#[cfg(any(target_os = "linux", target_os = "android"))]
pub use self::epoll::{Events, Selector};

#[cfg(any(target_os = "bitrig", target_os = "dragonfly",
          target_os = "freebsd", target_os = "ios", target_os = "macos",
          target_os = "netbsd", target_os = "openbsd"))]
mod kqueue;

#[cfg(any(target_os = "bitrig", target_os = "dragonfly",
          target_os = "freebsd", target_os = "ios", target_os = "macos",
          target_os = "netbsd", target_os = "openbsd"))]
pub use self::kqueue::{Events, Selector};

mod awakener;
mod eventedfd;
mod io;
mod ready;
mod tcp;
mod udp;

#[cfg(feature = "with-deprecated")]
mod uds;

pub use self::awakener::Awakener;
pub use self::eventedfd::EventedFd;
pub use self::io::{Io, set_nonblock};
pub use self::ready::{UnixReady, READY_ALL};
pub use self::tcp::{TcpStream, TcpListener};
pub use self::udp::UdpSocket;

#[cfg(feature = "with-deprecated")]
pub use self::uds::UnixSocket;

pub use iovec::IoVec;

use std::os::unix::io::FromRawFd;

pub fn pipe() -> ::io::Result<(Io, Io)> {
    // Use pipe2 for atomically setting O_CLOEXEC if we can, but otherwise
    // just fall back to using `pipe`.
    dlsym!(fn pipe2(*mut c_int, c_int) -> c_int);

    let mut pipes = [0; 2];
    let flags = libc::O_NONBLOCK | libc::O_CLOEXEC;
    unsafe {
        match pipe2.get() {
            Some(pipe2_fn) => {
                cvt(pipe2_fn(pipes.as_mut_ptr(), flags))?;
            }
            None => {
                cvt(libc::pipe(pipes.as_mut_ptr()))?;
                libc::fcntl(pipes[0], libc::F_SETFL, flags);
                libc::fcntl(pipes[1], libc::F_SETFL, flags);
            }
        }
    }

    unsafe {
        Ok((Io::from_raw_fd(pipes[0]), Io::from_raw_fd(pipes[1])))
    }
}

trait IsMinusOne {
    fn is_minus_one(&self) -> bool;
}

impl IsMinusOne for i32 {
    fn is_minus_one(&self) -> bool { *self == -1 }
}
impl IsMinusOne for isize {
    fn is_minus_one(&self) -> bool { *self == -1 }
}

fn cvt<T: IsMinusOne>(t: T) -> ::io::Result<T> {
    use std::io;

    if t.is_minus_one() {
        Err(io::Error::last_os_error())
    } else {
        Ok(t)
    }
}
<commit_msg>Illumos support (#807)<commit_after>use libc::{self, c_int};

#[macro_use]
pub mod dlsym;

#[cfg(any(target_os = "linux", target_os = "android", target_os = "solaris"))]
mod epoll;

#[cfg(any(target_os = "linux", target_os = "android", target_os = "solaris"))]
pub use self::epoll::{Events, Selector};

#[cfg(any(target_os = "bitrig", target_os = "dragonfly",
          target_os = "freebsd", target_os = "ios", target_os = "macos",
          target_os = "netbsd", target_os = "openbsd"))]
mod kqueue;

#[cfg(any(target_os = "bitrig", target_os = "dragonfly",
          target_os = "freebsd", target_os = "ios", target_os = "macos",
          target_os = "netbsd", target_os = "openbsd"))]
pub use self::kqueue::{Events, Selector};

mod awakener;
mod eventedfd;
mod io;
mod ready;
mod tcp;
mod udp;

#[cfg(feature = "with-deprecated")]
mod uds;

pub use self::awakener::Awakener;
pub use self::eventedfd::EventedFd;
pub use self::io::{Io, set_nonblock};
pub use self::ready::{UnixReady, READY_ALL};
pub use self::tcp::{TcpStream, TcpListener};
pub use self::udp::UdpSocket;

#[cfg(feature = "with-deprecated")]
pub use self::uds::UnixSocket;

pub use iovec::IoVec;

use std::os::unix::io::FromRawFd;

pub fn pipe() -> ::io::Result<(Io, Io)> {
    // Use pipe2 for atomically setting O_CLOEXEC if we can, but otherwise
    // just fall back to using `pipe`.
    dlsym!(fn pipe2(*mut c_int, c_int) -> c_int);

    let mut pipes = [0; 2];
    let flags = libc::O_NONBLOCK | libc::O_CLOEXEC;
    unsafe {
        match pipe2.get() {
            Some(pipe2_fn) => {
                cvt(pipe2_fn(pipes.as_mut_ptr(), flags))?;
            }
            None => {
                cvt(libc::pipe(pipes.as_mut_ptr()))?;
                libc::fcntl(pipes[0], libc::F_SETFL, flags);
                libc::fcntl(pipes[1], libc::F_SETFL, flags);
            }
        }
    }

    unsafe {
        Ok((Io::from_raw_fd(pipes[0]), Io::from_raw_fd(pipes[1])))
    }
}

trait IsMinusOne {
    fn is_minus_one(&self) -> bool;
}

impl IsMinusOne for i32 {
    fn is_minus_one(&self) -> bool { *self == -1 }
}
impl IsMinusOne for isize {
    fn is_minus_one(&self) -> bool { *self == -1 }
}

fn cvt<T: IsMinusOne>(t: T) -> ::io::Result<T> {
    use std::io;

    if t.is_minus_one() {
        Err(io::Error::last_os_error())
    } else {
        Ok(t)
    }
}
<|endoftext|>


<commit_before>use super::{Null, Value, ValueRef};
use Result;

/// `ToSqlOutput` represents the possible output types for implementors of the `ToSql` trait.
#[derive(Clone,Debug,PartialEq)]
pub enum ToSqlOutput<'a> {
    /// A borrowed SQLite-representable value.
    Borrowed(ValueRef<'a>),

    /// An owned SQLite-representable value.
    Owned(Value),

    /// A BLOB of the given length that is filled with zeroes.
    #[cfg(feature = "blob")]
    ZeroBlob(i32),
}

impl<'a, T: ?Sized> From<&'a T> for ToSqlOutput<'a>
    where &'a T: Into<ValueRef<'a>>
{
    fn from(t: &'a T) -> Self {
        ToSqlOutput::Borrowed(t.into())
    }
}

impl<'a, T: Into<Value>> From<T> for ToSqlOutput<'a> {
    fn from(t: T) -> Self {
        ToSqlOutput::Owned(t.into())
    }
}

impl<'a> ToSql for ToSqlOutput<'a> {
    fn to_sql(&self) -> Result<ToSqlOutput> {
        Ok(match *self {
               ToSqlOutput::Borrowed(v) => ToSqlOutput::Borrowed(v),
               ToSqlOutput::Owned(ref v) => ToSqlOutput::Borrowed(ValueRef::from(v)),

               #[cfg(feature = "blob")]
            ToSqlOutput::ZeroBlob(i) => ToSqlOutput::ZeroBlob(i),
           })
    }
}

/// A trait for types that can be converted into SQLite values.
pub trait ToSql {
    fn to_sql(&self) -> Result<ToSqlOutput>;
}

// We should be able to use a generic impl like this:
//
// impl<T: Copy> ToSql for T where T: Into<Value> {
//     fn to_sql(&self) -> Result<ToSqlOutput> {
//         Ok(ToSqlOutput::from((*self).into()))
//     }
// }
//
// instead of the following macro, but this runs afoul of
// https://github.com/rust-lang/rust/issues/30191 and reports conflicting
// implementations even when there aren't any.

macro_rules! to_sql_self(
    ($t:ty) => (
        impl ToSql for $t {
            fn to_sql(&self) -> Result<ToSqlOutput> {
                Ok(ToSqlOutput::from(*self))
            }
        }
    )
);

to_sql_self!(Null);
to_sql_self!(bool);
to_sql_self!(i8);
to_sql_self!(i16);
to_sql_self!(i32);
to_sql_self!(i64);
to_sql_self!(isize);
to_sql_self!(u8);
to_sql_self!(u16);
to_sql_self!(u32);
to_sql_self!(f64);

impl<'a, T: ?Sized> ToSql for &'a T
    where &'a T: Into<ToSqlOutput<'a>>
{
    fn to_sql(&self) -> Result<ToSqlOutput> {
        Ok((*self).into())
    }
}

impl ToSql for String {
    fn to_sql(&self) -> Result<ToSqlOutput> {
        Ok(ToSqlOutput::from(self.as_str()))
    }
}

impl ToSql for str {
    fn to_sql(&self) -> Result<ToSqlOutput> {
        Ok(ToSqlOutput::from(self))
    }
}

impl ToSql for Vec<u8> {
    fn to_sql(&self) -> Result<ToSqlOutput> {
        Ok(ToSqlOutput::from(self.as_slice()))
    }
}

impl ToSql for [u8] {
    fn to_sql(&self) -> Result<ToSqlOutput> {
        Ok(ToSqlOutput::from(self))
    }
}

impl ToSql for Value {
    fn to_sql(&self) -> Result<ToSqlOutput> {
        Ok(ToSqlOutput::from(self))
    }
}

impl<T: ToSql> ToSql for Option<T> {
    fn to_sql(&self) -> Result<ToSqlOutput> {
        match *self {
            None => Ok(ToSqlOutput::from(Null)),
            Some(ref t) => t.to_sql(),
        }
    }
}

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

    fn is_to_sql<T: ToSql>() {}

    #[test]
    fn test_integral_types() {
        is_to_sql::<i8>();
        is_to_sql::<i16>();
        is_to_sql::<i32>();
        is_to_sql::<i64>();
        is_to_sql::<u8>();
        is_to_sql::<u16>();
        is_to_sql::<u32>();
    }
}
<commit_msg>Remove potentially conflicting impl of ToSqlOutput.<commit_after>use super::{Null, Value, ValueRef};
use Result;

/// `ToSqlOutput` represents the possible output types for implementors of the `ToSql` trait.
#[derive(Clone,Debug,PartialEq)]
pub enum ToSqlOutput<'a> {
    /// A borrowed SQLite-representable value.
    Borrowed(ValueRef<'a>),

    /// An owned SQLite-representable value.
    Owned(Value),

    /// A BLOB of the given length that is filled with zeroes.
    #[cfg(feature = "blob")]
    ZeroBlob(i32),
}

// Generically allow any type that can be converted into a ValueRef
// to be converted into a ToSqlOutput as well.
impl<'a, T: ?Sized> From<&'a T> for ToSqlOutput<'a>
    where &'a T: Into<ValueRef<'a>>
{
    fn from(t: &'a T) -> Self {
        ToSqlOutput::Borrowed(t.into())
    }
}

// We cannot also generically allow any type that can be converted
// into a Value to be converted into a ToSqlOutput because of
// coherence rules (https://github.com/rust-lang/rust/pull/46192),
// so we'll manually implement it for all the types we know can
// be converted into Values.
macro_rules! from_value(
    ($t:ty) => (
        impl<'a> From<$t> for ToSqlOutput<'a> {
            fn from(t: $t) -> Self { ToSqlOutput::Owned(t.into())}
        }
    )
);
from_value!(String);
from_value!(Null);
from_value!(bool);
from_value!(i8);
from_value!(i16);
from_value!(i32);
from_value!(i64);
from_value!(isize);
from_value!(u8);
from_value!(u16);
from_value!(u32);
from_value!(f64);
from_value!(Vec<u8>);

impl<'a> ToSql for ToSqlOutput<'a> {
    fn to_sql(&self) -> Result<ToSqlOutput> {
        Ok(match *self {
               ToSqlOutput::Borrowed(v) => ToSqlOutput::Borrowed(v),
               ToSqlOutput::Owned(ref v) => ToSqlOutput::Borrowed(ValueRef::from(v)),

               #[cfg(feature = "blob")]
            ToSqlOutput::ZeroBlob(i) => ToSqlOutput::ZeroBlob(i),
           })
    }
}

/// A trait for types that can be converted into SQLite values.
pub trait ToSql {
    fn to_sql(&self) -> Result<ToSqlOutput>;
}

// We should be able to use a generic impl like this:
//
// impl<T: Copy> ToSql for T where T: Into<Value> {
//     fn to_sql(&self) -> Result<ToSqlOutput> {
//         Ok(ToSqlOutput::from((*self).into()))
//     }
// }
//
// instead of the following macro, but this runs afoul of
// https://github.com/rust-lang/rust/issues/30191 and reports conflicting
// implementations even when there aren't any.

macro_rules! to_sql_self(
    ($t:ty) => (
        impl ToSql for $t {
            fn to_sql(&self) -> Result<ToSqlOutput> {
                Ok(ToSqlOutput::from(*self))
            }
        }
    )
);

to_sql_self!(Null);
to_sql_self!(bool);
to_sql_self!(i8);
to_sql_self!(i16);
to_sql_self!(i32);
to_sql_self!(i64);
to_sql_self!(isize);
to_sql_self!(u8);
to_sql_self!(u16);
to_sql_self!(u32);
to_sql_self!(f64);

impl<'a, T: ?Sized> ToSql for &'a T
    where &'a T: Into<ToSqlOutput<'a>>
{
    fn to_sql(&self) -> Result<ToSqlOutput> {
        Ok((*self).into())
    }
}

impl ToSql for String {
    fn to_sql(&self) -> Result<ToSqlOutput> {
        Ok(ToSqlOutput::from(self.as_str()))
    }
}

impl ToSql for str {
    fn to_sql(&self) -> Result<ToSqlOutput> {
        Ok(ToSqlOutput::from(self))
    }
}

impl ToSql for Vec<u8> {
    fn to_sql(&self) -> Result<ToSqlOutput> {
        Ok(ToSqlOutput::from(self.as_slice()))
    }
}

impl ToSql for [u8] {
    fn to_sql(&self) -> Result<ToSqlOutput> {
        Ok(ToSqlOutput::from(self))
    }
}

impl ToSql for Value {
    fn to_sql(&self) -> Result<ToSqlOutput> {
        Ok(ToSqlOutput::from(self))
    }
}

impl<T: ToSql> ToSql for Option<T> {
    fn to_sql(&self) -> Result<ToSqlOutput> {
        match *self {
            None => Ok(ToSqlOutput::from(Null)),
            Some(ref t) => t.to_sql(),
        }
    }
}

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

    fn is_to_sql<T: ToSql>() {}

    #[test]
    fn test_integral_types() {
        is_to_sql::<i8>();
        is_to_sql::<i16>();
        is_to_sql::<i32>();
        is_to_sql::<i64>();
        is_to_sql::<u8>();
        is_to_sql::<u16>();
        is_to_sql::<u32>();
    }
}
<|endoftext|>


<commit_before>pub mod auto_reply;
pub mod delete_all_messages;
pub mod reaction;
pub mod timeout_role;

use lalafell::commands::prelude::*;

use serenity::model::id::{UserId, GuildId};

#[derive(Default)]
pub struct ServerCommand;

impl<'a> ServerCommand {
  pub fn run(&self, author: UserId, guild: GuildId, params: Params) -> CommandResult<'a> {
    struct SubCommands {
      auto_reply: auto_reply::AutoReplyCommand,
      delete_all_messages: delete_all_messages::DeleteAllMessagesCommand,
      reaction: reaction::ReactionCommand,
      timeout_role: timeout_role::TimeoutRoleCommand
    }

    const SUBCOMMANDS: SubCommands = SubCommands {
      auto_reply: auto_reply::AutoReplyCommand,
      delete_all_messages: delete_all_messages::DeleteAllMessagesCommand,
      reaction: reaction::ReactionCommand,
      timeout_role: timeout_role::TimeoutRoleCommand
    };

    match params {
      Params::AutoReply(p) => SUBCOMMANDS.auto_reply.run(author, guild, p),
      Params::DeleteAllMessages(p) => SUBCOMMANDS.delete_all_messages.run(author, guild, p),
      Params::Reaction(p) => SUBCOMMANDS.reaction.run(author, guild, p),
      Params::TimeoutRole(p) => SUBCOMMANDS.timeout_role.run(author, guild, p)
    }
  }
}

#[derive(Debug, StructOpt)]
#[structopt(about = "Configure server settings.")]
pub enum Params {
  #[structopt(name = "autoreply", alias = "ar", about = "Manage auto-reply settings")]
  #[structopt(raw(template = "::lalafell::commands::TEMPLATE"))]
  AutoReply(auto_reply::Params),

  #[structopt(name = "deleteallmessages", alias = "dam", about = "Manage channel message deletion settings")]
  #[structopt(raw(aliases = r#"&["dam", "dams"]"#))]
  #[structopt(raw(template = "::lalafell::commands::TEMPLATE"))]
  DeleteAllMessages(delete_all_messages::Params),

  #[structopt(name = "reaction", alias = "reactions", about = "Manage reaction role settings")]
  #[structopt(raw(template = "::lalafell::commands::TEMPLATE"))]
  Reaction(reaction::Params),

  #[structopt(name = "timeoutrole", about = "Manage the timeout role")]
  #[structopt(raw(template = "::lalafell::commands::TEMPLATE"))]
  TimeoutRole(timeout_role::Params)
}
<commit_msg>fix: require args for subcommands<commit_after>pub mod auto_reply;
pub mod delete_all_messages;
pub mod reaction;
pub mod timeout_role;

use lalafell::commands::prelude::*;

use serenity::model::id::{UserId, GuildId};

#[derive(Default)]
pub struct ServerCommand;

impl<'a> ServerCommand {
  pub fn run(&self, author: UserId, guild: GuildId, params: Params) -> CommandResult<'a> {
    struct SubCommands {
      auto_reply: auto_reply::AutoReplyCommand,
      delete_all_messages: delete_all_messages::DeleteAllMessagesCommand,
      reaction: reaction::ReactionCommand,
      timeout_role: timeout_role::TimeoutRoleCommand
    }

    const SUBCOMMANDS: SubCommands = SubCommands {
      auto_reply: auto_reply::AutoReplyCommand,
      delete_all_messages: delete_all_messages::DeleteAllMessagesCommand,
      reaction: reaction::ReactionCommand,
      timeout_role: timeout_role::TimeoutRoleCommand
    };

    match params {
      Params::AutoReply(p) => SUBCOMMANDS.auto_reply.run(author, guild, p),
      Params::DeleteAllMessages(p) => SUBCOMMANDS.delete_all_messages.run(author, guild, p),
      Params::Reaction(p) => SUBCOMMANDS.reaction.run(author, guild, p),
      Params::TimeoutRole(p) => SUBCOMMANDS.timeout_role.run(author, guild, p)
    }
  }
}

#[derive(Debug, StructOpt)]
#[structopt(about = "Configure server settings.")]
pub enum Params {
  #[structopt(name = "autoreply", alias = "ar", about = "Manage auto-reply settings")]
  #[structopt(raw(setting = "::structopt::clap::AppSettings::ArgRequiredElseHelp"))]
  #[structopt(raw(template = "::lalafell::commands::TEMPLATE"))]
  AutoReply(auto_reply::Params),

  #[structopt(name = "deleteallmessages", alias = "dam", about = "Manage channel message deletion settings")]
  #[structopt(raw(aliases = r#"&["dam", "dams"]"#))]
  #[structopt(raw(setting = "::structopt::clap::AppSettings::ArgRequiredElseHelp"))]
  #[structopt(raw(template = "::lalafell::commands::TEMPLATE"))]
  DeleteAllMessages(delete_all_messages::Params),

  #[structopt(name = "reaction", alias = "reactions", about = "Manage reaction role settings")]
  #[structopt(raw(setting = "::structopt::clap::AppSettings::ArgRequiredElseHelp"))]
  #[structopt(raw(template = "::lalafell::commands::TEMPLATE"))]
  Reaction(reaction::Params),

  #[structopt(name = "timeoutrole", about = "Manage the timeout role")]
  #[structopt(raw(template = "::lalafell::commands::TEMPLATE"))]
  TimeoutRole(timeout_role::Params)
}
<|endoftext|>


<commit_before>use std::io::{self, Write, Read};
use core::*;
use core::iter::*;
use core::mem::*;
use core::sync::atomic::*;
use std::sync::RwLock;
use xen::arch::mem::*;
use xen::event_channels::*;
use xen::start_info::start_info_page;
use alloc::raw_vec::RawVec;
use collections::{String, Vec};
use xen::console_io::STDOUT;

pub static XENSTORE: RwLock<Option<XenStore<'static>>> = RwLock::new(Option::None);

pub struct XenStore<'a> {
    interface: &'a mut xenstore_domain_interface,
    event_channel: EventChannel
}

static mut req_counter : AtomicIsize = AtomicIsize::new(1);

#[repr(C)]
struct xenstore_domain_interface {
    req: [u8; XENSTORE_RING_SIZE],
    rsp: [u8; XENSTORE_RING_SIZE],
    req_cons: u32,
    req_prod: u32,
    rsp_cons: u32,
    rsp_prod: u32
}

const XENSTORE_RING_SIZE : usize = 1024;

impl Write for xenstore_domain_interface {
    //Listing 8.4 in The Definitive Guide to the Xen Hypervisor
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        if buf.len() > XENSTORE_RING_SIZE {
            Result::Err(io::Error::new(io::ErrorKind::InvalidData, "Too much data!"))
        } else {
            let mut i = self.req_prod;
            let result = buf.len();

            for &b in buf {
                while {
                    let data = i - self.req_cons;
                    mb();
                    data >= (XENSTORE_RING_SIZE as u32)
                } {}
                let ring_index = mod_ring_size(i) as usize;
                self.req[ring_index] = b;
                i = i + 1;
            }

            wmb();
            self.req_prod = i;
            Ok(result)
        }
    }
}

impl Read for xenstore_domain_interface {
    //Listing 8.5 in The Definitive Guide to the Xen Hypervisor
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let mut i = self.rsp_cons;
        let result = buf.len();

        for b in buf {
            while {
                let data = self.rsp_prod - i;
                mb();
                data == 0
            } {}
            let ring_index = mod_ring_size(i) as usize;
            *b = self.rsp[ring_index];
            i = i + 1;
        }
        self.rsp_cons = i;
        Ok(result)
    }
}

impl xenstore_domain_interface {
    //Listing 8.6 in The Definitive Guide to the Xen Hypervisor
    unsafe fn ignore(&mut self, bytes: usize) {
        use std::io::Read;
        if bytes != 0 {
            let vec = RawVec::<u8>::with_capacity(bytes);
            let slice = slice::from_raw_parts_mut(vec.ptr(), bytes);
            let _ignored = self.read(slice);
        }
    }
}

impl<'a> XenStore<'a> {
    unsafe fn send(&mut self, type_: xsd_sockmsg_type, params: &[&str]) -> io::Result<(xsd_sockmsg_type, String)> {
        use core::fmt::Write;
        let req_id = req_counter.fetch_add(1, Ordering::Relaxed) as u32;
        // params are passed null-terminated
        let len = params.iter().fold (0, |acc, &x| acc + x.len() + 1) as u32;
        let msg = xsd_sockmsg {
            type_: type_,
            req_id: req_id,
            tx_id: 0,
            len: len
        };
        writeln!(STDOUT, "Sending {:?}: {:?}", msg, params).unwrap();
        let msg_slice = slice::from_raw_parts(&msg as *const _ as *const u8, size_of::<xsd_sockmsg>());
        try!(self.interface.write(msg_slice));

        for p in params {
            try!(self.interface.write(p.as_bytes()));
            try!(self.interface.write("\0".as_bytes()));
        }

        self.event_channel.notify();

        let mut response: xsd_sockmsg = uninitialized();
        let response_slice = slice::from_raw_parts_mut(&mut response as *mut _ as *mut u8, size_of::<xsd_sockmsg>());
        try!(self.interface.read(response_slice));

        match (response.req_id, response.tx_id) {
            (req_id, 0) if req_id == msg.req_id => {
                let mut result_vec = Vec::with_capacity(response.len as usize);
                result_vec.resize(response.len as usize, 0);
                self.interface.read(result_vec.as_mut_slice()).ok();
                let result = String::from_utf8(result_vec).unwrap();
                writeln!(STDOUT, "Receiving {:?}: {:?}", response, result).unwrap();
                Result::Ok((response.type_, result))
            }
            (_, 0) => {
                Result::Err(io::Error::new(
                    io::ErrorKind::Other,
                    format!("Received a reply with a non-zero transaction ID (expected 0, actual {})",  msg.req_id)
                ))
            }
            (req_id, _) => {
                Result::Err(io::Error::new(
                    io::ErrorKind::Other,
                    format!("Received a reply for the wrong request ID (expected {}, actual {})", req_id, msg.req_id)
                ))
            }
        }
    }

    //Listing 8.7 in The Definitive Guide to the Xen Hypervisor
    pub unsafe fn write(&mut self, key: &str, value: &str) -> io::Result<()> {
        use core::fmt::Write;
        let result = try!(self.send(xsd_sockmsg_type::Write, &[key, value]));

        match result {
            (xsd_sockmsg_type::Error, ref s) if s == "EACCES\0" => {
                Result::Err(io::Error::new(
                    io::ErrorKind::PermissionDenied,
                    format!("Can't write to key {}: access denied", key)
                ))
            }
            (xsd_sockmsg_type::Error, s) => {
                Result::Err(io::Error::new(
                    io::ErrorKind::Other,
                    format!("Generic xenstore write error {}", s)
                ))
            }
            _ => { Result::Ok(()) }
        }
    }

    //Listing 8.8 in The Definitive Guide to the Xen Hypervisor
    pub unsafe fn read(&mut self, key: &str) -> io::Result<Option<String>> {
        use core::fmt::Write;
        let result = try!(self.send(xsd_sockmsg_type::Read, &[key]));

        match result {
            (xsd_sockmsg_type::Error, ref s) if s == "ENOENT\0" => { Result::Ok(None) }
            (xsd_sockmsg_type::Error, s) => {
                Result::Err(io::Error::new(
                    io::ErrorKind::Other,
                    format!("Generic xenstore read error {}", s)
                ))
            }
            (_, s) => { Result::Ok(Some(s)) }
        }
    }

    pub unsafe fn get_permissions(&mut self, key: &str) -> io::Result<String> {
        use core::fmt::Write;
        let result = try!(self.send(xsd_sockmsg_type::GetPerms, &[key]));

        match result {
            (xsd_sockmsg_type::Error, s) => {
                Result::Err(io::Error::new(
                    io::ErrorKind::Other,
                    format!("Generic xenstore read error {}", s)
                ))
            }
            (_, s) => { Result::Ok(s) }
        }
    }
}

fn mod_ring_size(i: u32) -> u32 {
    i & ((XENSTORE_RING_SIZE as u32) - 1)
}

#[repr(C)]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug)]
struct xsd_sockmsg {
    type_: xsd_sockmsg_type,
    req_id: u32,
    tx_id: u32,
    len: u32
}

#[repr(u32)]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug)]
enum xsd_sockmsg_type {
    Debug       = 0,
    Directory   = 1,
    Read        = 2,
    GetPerms    = 3,
    Watch       = 4,
    Unwatch     = 5,
    TransactionStart = 6,
    TransactionEnd = 7,
    Introduce   = 8,
    Release     = 9,
    GetDomainPath = 10,
    Write       = 11,
    Mkdir       = 12,
    Rm          = 13,
    SetPerms    = 14,
    WatchEvent  = 15,
    Error       = 16,
    IsDomainIntroduced = 17,
    Resume      = 18,
    SetTarget   = 19,
    Restrict    = 20,
    ResetWatches  = 21,

    Invalid     = 0xffff /* Guaranteed to remain an invalid type */
}

pub unsafe fn initialize() {
    let xenstore_ptr = XENSTORE.write();
    *xenstore_ptr = Some (XenStore {
        interface: &mut *(mfn_to_virt(start_info_page.store_mfn) as *mut _),
        event_channel: EventChannel(start_info_page.store_evtchn)
    });
}
<commit_msg>remove print statements in xenstore<commit_after>use std::io::{self, Write, Read};
use core::*;
use core::iter::*;
use core::mem::*;
use core::sync::atomic::*;
use std::sync::RwLock;
use xen::arch::mem::*;
use xen::event_channels::*;
use xen::start_info::start_info_page;
use alloc::raw_vec::RawVec;
use collections::{String, Vec};
use xen::console_io::STDOUT;

pub static XENSTORE: RwLock<Option<XenStore<'static>>> = RwLock::new(Option::None);

pub struct XenStore<'a> {
    interface: &'a mut xenstore_domain_interface,
    event_channel: EventChannel
}

static mut req_counter : AtomicIsize = AtomicIsize::new(1);

#[repr(C)]
struct xenstore_domain_interface {
    req: [u8; XENSTORE_RING_SIZE],
    rsp: [u8; XENSTORE_RING_SIZE],
    req_cons: u32,
    req_prod: u32,
    rsp_cons: u32,
    rsp_prod: u32
}

const XENSTORE_RING_SIZE : usize = 1024;

impl Write for xenstore_domain_interface {
    //Listing 8.4 in The Definitive Guide to the Xen Hypervisor
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        if buf.len() > XENSTORE_RING_SIZE {
            Result::Err(io::Error::new(io::ErrorKind::InvalidData, "Too much data!"))
        } else {
            let mut i = self.req_prod;
            let result = buf.len();

            for &b in buf {
                while {
                    let data = i - self.req_cons;
                    mb();
                    data >= (XENSTORE_RING_SIZE as u32)
                } {}
                let ring_index = mod_ring_size(i) as usize;
                self.req[ring_index] = b;
                i = i + 1;
            }

            wmb();
            self.req_prod = i;
            Ok(result)
        }
    }
}

impl Read for xenstore_domain_interface {
    //Listing 8.5 in The Definitive Guide to the Xen Hypervisor
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let mut i = self.rsp_cons;
        let result = buf.len();

        for b in buf {
            while {
                let data = self.rsp_prod - i;
                mb();
                data == 0
            } {}
            let ring_index = mod_ring_size(i) as usize;
            *b = self.rsp[ring_index];
            i = i + 1;
        }
        self.rsp_cons = i;
        Ok(result)
    }
}

impl xenstore_domain_interface {
    //Listing 8.6 in The Definitive Guide to the Xen Hypervisor
    unsafe fn ignore(&mut self, bytes: usize) {
        use std::io::Read;
        if bytes != 0 {
            let vec = RawVec::<u8>::with_capacity(bytes);
            let slice = slice::from_raw_parts_mut(vec.ptr(), bytes);
            let _ignored = self.read(slice);
        }
    }
}

impl<'a> XenStore<'a> {
    unsafe fn send(&mut self, type_: xsd_sockmsg_type, params: &[&str]) -> io::Result<(xsd_sockmsg_type, String)> {
        use core::fmt::Write;
        let req_id = req_counter.fetch_add(1, Ordering::Relaxed) as u32;
        // params are passed null-terminated
        let len = params.iter().fold (0, |acc, &x| acc + x.len() + 1) as u32;
        let msg = xsd_sockmsg {
            type_: type_,
            req_id: req_id,
            tx_id: 0,
            len: len
        };
        let msg_slice = slice::from_raw_parts(&msg as *const _ as *const u8, size_of::<xsd_sockmsg>());
        try!(self.interface.write(msg_slice));

        for p in params {
            try!(self.interface.write(p.as_bytes()));
            try!(self.interface.write("\0".as_bytes()));
        }

        self.event_channel.notify();

        let mut response: xsd_sockmsg = uninitialized();
        let response_slice = slice::from_raw_parts_mut(&mut response as *mut _ as *mut u8, size_of::<xsd_sockmsg>());
        try!(self.interface.read(response_slice));

        match (response.req_id, response.tx_id) {
            (req_id, 0) if req_id == msg.req_id => {
                let mut result_vec = Vec::with_capacity(response.len as usize);
                result_vec.resize(response.len as usize, 0);
                self.interface.read(result_vec.as_mut_slice()).ok();
                let result = String::from_utf8(result_vec).unwrap();
                Result::Ok((response.type_, result))
            }
            (_, 0) => {
                Result::Err(io::Error::new(
                    io::ErrorKind::Other,
                    format!("Received a reply with a non-zero transaction ID (expected 0, actual {})",  msg.req_id)
                ))
            }
            (req_id, _) => {
                Result::Err(io::Error::new(
                    io::ErrorKind::Other,
                    format!("Received a reply for the wrong request ID (expected {}, actual {})", req_id, msg.req_id)
                ))
            }
        }
    }

    //Listing 8.7 in The Definitive Guide to the Xen Hypervisor
    pub unsafe fn write(&mut self, key: &str, value: &str) -> io::Result<()> {
        use core::fmt::Write;
        let result = try!(self.send(xsd_sockmsg_type::Write, &[key, value]));

        match result {
            (xsd_sockmsg_type::Error, ref s) if s == "EACCES\0" => {
                Result::Err(io::Error::new(
                    io::ErrorKind::PermissionDenied,
                    format!("Can't write to key {}: access denied", key)
                ))
            }
            (xsd_sockmsg_type::Error, s) => {
                Result::Err(io::Error::new(
                    io::ErrorKind::Other,
                    format!("Generic xenstore write error {}", s)
                ))
            }
            _ => { Result::Ok(()) }
        }
    }

    //Listing 8.8 in The Definitive Guide to the Xen Hypervisor
    pub unsafe fn read(&mut self, key: &str) -> io::Result<Option<String>> {
        use core::fmt::Write;
        let result = try!(self.send(xsd_sockmsg_type::Read, &[key]));

        match result {
            (xsd_sockmsg_type::Error, ref s) if s == "ENOENT\0" => { Result::Ok(None) }
            (xsd_sockmsg_type::Error, s) => {
                Result::Err(io::Error::new(
                    io::ErrorKind::Other,
                    format!("Generic xenstore read error {}", s)
                ))
            }
            (_, s) => { Result::Ok(Some(s)) }
        }
    }

    pub unsafe fn get_permissions(&mut self, key: &str) -> io::Result<String> {
        use core::fmt::Write;
        let result = try!(self.send(xsd_sockmsg_type::GetPerms, &[key]));

        match result {
            (xsd_sockmsg_type::Error, s) => {
                Result::Err(io::Error::new(
                    io::ErrorKind::Other,
                    format!("Generic xenstore read error {}", s)
                ))
            }
            (_, s) => { Result::Ok(s) }
        }
    }
}

fn mod_ring_size(i: u32) -> u32 {
    i & ((XENSTORE_RING_SIZE as u32) - 1)
}

#[repr(C)]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug)]
struct xsd_sockmsg {
    type_: xsd_sockmsg_type,
    req_id: u32,
    tx_id: u32,
    len: u32
}

#[repr(u32)]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug)]
enum xsd_sockmsg_type {
    Debug       = 0,
    Directory   = 1,
    Read        = 2,
    GetPerms    = 3,
    Watch       = 4,
    Unwatch     = 5,
    TransactionStart = 6,
    TransactionEnd = 7,
    Introduce   = 8,
    Release     = 9,
    GetDomainPath = 10,
    Write       = 11,
    Mkdir       = 12,
    Rm          = 13,
    SetPerms    = 14,
    WatchEvent  = 15,
    Error       = 16,
    IsDomainIntroduced = 17,
    Resume      = 18,
    SetTarget   = 19,
    Restrict    = 20,
    ResetWatches  = 21,

    Invalid     = 0xffff /* Guaranteed to remain an invalid type */
}

pub unsafe fn initialize() {
    let xenstore_ptr = XENSTORE.write();
    *xenstore_ptr = Some (XenStore {
        interface: &mut *(mfn_to_virt(start_info_page.store_mfn) as *mut _),
        event_channel: EventChannel(start_info_page.store_evtchn)
    });
}
<|endoftext|>


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

// The task that handles all rendering/painting.

use azure::azure_hl::{B8G8R8A8, DrawTarget, StolenGLResources};
use azure::AzFloat;
use geom::matrix2d::Matrix2D;
use geom::rect::Rect;
use geom::size::Size2D;
use layers::platform::surface::{NativePaintingGraphicsContext, NativeSurface};
use layers::platform::surface::{NativeSurfaceMethods};
use layers;
use servo_msg::compositor_msg::{Epoch, IdleRenderState, LayerBuffer, LayerBufferSet};
use servo_msg::compositor_msg::{RenderListener, RenderingRenderState};
use servo_msg::constellation_msg::{ConstellationChan, PipelineId, RendererReadyMsg};
use servo_msg::platform::surface::NativeSurfaceAzureMethods;
use servo_util::time::{ProfilerChan, profile};
use servo_util::time;

use std::comm::{Chan, Port, SharedChan};
use std::task::spawn_with;
use extra::arc::Arc;

use buffer_map::BufferMap;
use display_list::DisplayList;
use font_context::FontContext;
use opts::Opts;
use render_context::RenderContext;

pub struct RenderLayer<T> {
    display_list: Arc<DisplayList<T>>,
    size: Size2D<uint>
}

pub enum Msg<T> {
    RenderMsg(RenderLayer<T>),
    ReRenderMsg(~[BufferRequest], f32, Epoch),
    UnusedBufferMsg(~[~LayerBuffer]),
    PaintPermissionGranted,
    PaintPermissionRevoked,
    ExitMsg(Chan<()>),
}

/// A request from the compositor to the renderer for tiles that need to be (re)displayed.
#[deriving(Clone)]
pub struct BufferRequest {
    // The rect in pixels that will be drawn to the screen
    screen_rect: Rect<uint>,

    // The rect in page coordinates that this tile represents
    page_rect: Rect<f32>,
}

pub fn BufferRequest(screen_rect: Rect<uint>, page_rect: Rect<f32>) -> BufferRequest {
    BufferRequest {
        screen_rect: screen_rect,
        page_rect: page_rect,
    }
}

// FIXME(rust#9155): this should be a newtype struct, but
// generic newtypes ICE when compiled cross-crate
#[deriving(Clone)]
pub struct RenderChan<T> {
    chan: SharedChan<Msg<T>>,
}
impl<T: Send> RenderChan<T> {
    pub fn new(chan: Chan<Msg<T>>) -> RenderChan<T> {
        RenderChan {
            chan: SharedChan::new(chan),
        }
    }
}
impl<T: Send> GenericChan<Msg<T>> for RenderChan<T> {
    fn send(&self, msg: Msg<T>) {
        assert!(self.try_send(msg), "RenderChan.send: render port closed")
    }
}
impl<T: Send> GenericSmartChan<Msg<T>> for RenderChan<T> {
    fn try_send(&self, msg: Msg<T>) -> bool {
        self.chan.try_send(msg)
    }
}

/// If we're using GPU rendering, this provides the metadata needed to create a GL context that
/// is compatible with that of the main thread.
enum GraphicsContext {
    CpuGraphicsContext,
    GpuGraphicsContext,
}

pub struct RenderTask<C,T> {
    id: PipelineId,
    port: Port<Msg<T>>,
    compositor: C,
    constellation_chan: ConstellationChan,
    font_ctx: @mut FontContext,
    opts: Opts,

    /// A channel to the profiler.
    profiler_chan: ProfilerChan,

    /// The graphics context to use.
    graphics_context: GraphicsContext,

    /// The native graphics context.
    native_graphics_context: NativePaintingGraphicsContext,

    /// The layer to be rendered
    render_layer: Option<RenderLayer<T>>,

    /// Permission to send paint messages to the compositor
    paint_permission: bool,

    /// A counter for epoch messages
    epoch: Epoch,

    /// A data structure to store unused LayerBuffers
    buffer_map: BufferMap<~LayerBuffer>,
}

impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
    pub fn create(id: PipelineId,
                  port: Port<Msg<T>>,
                  compositor: C,
                  constellation_chan: ConstellationChan,
                  opts: Opts,
                  profiler_chan: ProfilerChan) {
        do spawn_with((port, compositor, constellation_chan, opts, profiler_chan))
            |(port, compositor, constellation_chan, opts, profiler_chan)| {

            let graphics_metadata = compositor.get_graphics_metadata();
            let cpu_painting = opts.cpu_painting;
            let native_graphics_context =
                    NativePaintingGraphicsContext::from_metadata(&graphics_metadata);

            // FIXME: rust/#5967
            let mut render_task = RenderTask {
                id: id,
                port: port,
                compositor: compositor,
                constellation_chan: constellation_chan,
                font_ctx: @mut FontContext::new(opts.render_backend.clone(),
                                                false,
                                                profiler_chan.clone()),
                opts: opts,
                profiler_chan: profiler_chan,

                graphics_context: if cpu_painting {
                    CpuGraphicsContext
                } else {
                    GpuGraphicsContext
                },

                native_graphics_context: native_graphics_context,

                render_layer: None,

                paint_permission: false,
                epoch: Epoch(0),
                buffer_map: BufferMap::new(10000000),
            };

            render_task.start();

            // Destroy all the buffers.
            render_task.buffer_map.clear(&render_task.native_graphics_context)
        }
    }

    fn start(&mut self) {
        debug!("render_task: beginning rendering loop");

        loop {
            match self.port.recv() {
                RenderMsg(render_layer) => {
                    if self.paint_permission {
                        self.epoch.next();
                        self.compositor.set_layer_page_size(self.id, render_layer.size, self.epoch);
                    } else {
                        self.constellation_chan.send(RendererReadyMsg(self.id));
                    }
                    self.render_layer = Some(render_layer);
                }
                ReRenderMsg(tiles, scale, epoch) => {
                    if self.epoch == epoch {
                        self.render(tiles, scale);
                    } else {
                        debug!("renderer epoch mismatch: {:?} != {:?}", self.epoch, epoch);
                    }
                }
                UnusedBufferMsg(unused_buffers) => {
                    // move_rev_iter is more efficient
                    for buffer in unused_buffers.move_rev_iter() {
                        self.buffer_map.insert(&self.native_graphics_context, buffer);
                    }
                }
                PaintPermissionGranted => {
                    self.paint_permission = true;
                    match self.render_layer {
                        Some(ref render_layer) => {
                            self.epoch.next();
                            self.compositor.set_layer_page_size(self.id, render_layer.size, self.epoch);
                        }
                        None => {}
                    }
                }
                PaintPermissionRevoked => {
                    self.paint_permission = false;
                }
                ExitMsg(response_ch) => {
                    response_ch.send(());
                    break;
                }
            }
        }
    }

    fn render(&mut self, tiles: ~[BufferRequest], scale: f32) {
        // In headless mode, disable the renderer, because it makes OpenGL
        // calls.  Once we have CPU rendering we should render in CPU mode and
        // just disable texture upload.
        if self.opts.headless {
            return;
        }

        let render_layer;
        match self.render_layer {
            Some(ref r_layer) => {
                render_layer = r_layer;
            }
            _ => return, // nothing to do
        }

        self.compositor.set_render_state(RenderingRenderState);
        do time::profile(time::RenderingCategory, self.profiler_chan.clone()) {
            // FIXME: Try not to create a new array here.
            let mut new_buffers = ~[];

            // Divide up the layer into tiles.
            do time::profile(time::RenderingPrepBuffCategory, self.profiler_chan.clone()) {
                for tile in tiles.iter() {
                    let width = tile.screen_rect.size.width;
                    let height = tile.screen_rect.size.height;

                    let size = Size2D(width as i32, height as i32);
                    let draw_target = match self.graphics_context {
                        CpuGraphicsContext => {
                            DrawTarget::new(self.opts.render_backend, size, B8G8R8A8)
                        }
                        GpuGraphicsContext => {
                            // FIXME(pcwalton): Cache the components of draw targets
                            // (texture color buffer, renderbuffers) instead of recreating them.
                            let draw_target =
                                DrawTarget::new_with_fbo(self.opts.render_backend,
                                                         &self.native_graphics_context,
                                                         size,
                                                         B8G8R8A8);
                            draw_target.make_current();
                            draw_target
                        }
                    };

                    {
                        // Build the render context.
                        let ctx = RenderContext {
                            draw_target: &draw_target,
                            font_ctx: self.font_ctx,
                            opts: &self.opts,
                            page_rect: tile.page_rect,
                            screen_rect: tile.screen_rect,
                        };

                        // Apply the translation to render the tile we want.
                        let matrix: Matrix2D<AzFloat> = Matrix2D::identity();
                        let matrix = matrix.scale(scale as AzFloat, scale as AzFloat);
                        let matrix = matrix.translate(-(tile.page_rect.origin.x) as AzFloat,
                                                      -(tile.page_rect.origin.y) as AzFloat);

                        ctx.draw_target.set_transform(&matrix);

                        // Clear the buffer.
                        ctx.clear();

                        // Draw the display list.
                        do profile(time::RenderingDrawingCategory, self.profiler_chan.clone()) {
                            render_layer.display_list.get().draw_into_context(&ctx);
                            ctx.draw_target.flush();
                        }
                    }

                    // Extract the texture from the draw target and place it into its slot in the
                    // buffer. If using CPU rendering, upload it first.
                    //
                    // FIXME(pcwalton): We should supply the texture and native surface *to* the
                    // draw target in GPU rendering mode, so that it doesn't have to recreate it.
                    let buffer = match self.graphics_context {
                        CpuGraphicsContext => {
                            let buffer = match self.buffer_map.find(tile.screen_rect.size) {
                                Some(buffer) => {
                                    let mut buffer = buffer;
                                    buffer.rect = tile.page_rect;
                                    buffer.screen_pos = tile.screen_rect;
                                    buffer.resolution = scale;
                                    buffer.native_surface.mark_wont_leak();
                                    buffer
                                }
                                None => {
                                    // Create an empty native surface. We mark it as not leaking
                                    // in case it dies in transit to the compositor task.
                                    let mut native_surface: NativeSurface =
                                        layers::platform::surface::NativeSurfaceMethods::new(
                                            &self.native_graphics_context,
                                            Size2D(width as i32, height as i32),
                                            width as i32 * 4);
                                    native_surface.mark_wont_leak();

                                    ~LayerBuffer {
                                        native_surface: native_surface,
                                        rect: tile.page_rect,
                                        screen_pos: tile.screen_rect,
                                        resolution: scale,
                                        stride: (width * 4) as uint
                                    }
                                }
                            };

                            do draw_target.snapshot().get_data_surface().with_data |data| {
                                buffer.native_surface.upload(&self.native_graphics_context, data);
                                debug!("RENDERER uploading to native surface {:d}",
                                       buffer.native_surface.get_id() as int);
                            }

                            buffer
                        }
                        GpuGraphicsContext => {
                            draw_target.make_current();
                            let StolenGLResources {
                                surface: native_surface
                            } = draw_target.steal_gl_resources().unwrap();

                            // We mark the native surface as not leaking in case the surfaces
                            // die on their way to the compositor task.
                            let mut native_surface: NativeSurface =
                                NativeSurfaceAzureMethods::from_azure_surface(native_surface);
                            native_surface.mark_wont_leak();

                            ~LayerBuffer {
                                native_surface: native_surface,
                                rect: tile.page_rect,
                                screen_pos: tile.screen_rect,
                                resolution: scale,
                                stride: (width * 4) as uint
                            }
                        }
                    };

                    new_buffers.push(buffer);
                }
            }

            let layer_buffer_set = ~LayerBufferSet {
                buffers: new_buffers,
            };

            debug!("render_task: returning surface");
            if self.paint_permission {
                self.compositor.paint(self.id, layer_buffer_set, self.epoch);
            } else {
                self.constellation_chan.send(RendererReadyMsg(self.id));
            }
            self.compositor.set_render_state(IdleRenderState);
        }
    }
}

<commit_msg>Remove render() bypass for headless mode<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// The task that handles all rendering/painting.

use azure::azure_hl::{B8G8R8A8, DrawTarget, StolenGLResources};
use azure::AzFloat;
use geom::matrix2d::Matrix2D;
use geom::rect::Rect;
use geom::size::Size2D;
use layers::platform::surface::{NativePaintingGraphicsContext, NativeSurface};
use layers::platform::surface::{NativeSurfaceMethods};
use layers;
use servo_msg::compositor_msg::{Epoch, IdleRenderState, LayerBuffer, LayerBufferSet};
use servo_msg::compositor_msg::{RenderListener, RenderingRenderState};
use servo_msg::constellation_msg::{ConstellationChan, PipelineId, RendererReadyMsg};
use servo_msg::platform::surface::NativeSurfaceAzureMethods;
use servo_util::time::{ProfilerChan, profile};
use servo_util::time;

use std::comm::{Chan, Port, SharedChan};
use std::task::spawn_with;
use extra::arc::Arc;

use buffer_map::BufferMap;
use display_list::DisplayList;
use font_context::FontContext;
use opts::Opts;
use render_context::RenderContext;

pub struct RenderLayer<T> {
    display_list: Arc<DisplayList<T>>,
    size: Size2D<uint>
}

pub enum Msg<T> {
    RenderMsg(RenderLayer<T>),
    ReRenderMsg(~[BufferRequest], f32, Epoch),
    UnusedBufferMsg(~[~LayerBuffer]),
    PaintPermissionGranted,
    PaintPermissionRevoked,
    ExitMsg(Chan<()>),
}

/// A request from the compositor to the renderer for tiles that need to be (re)displayed.
#[deriving(Clone)]
pub struct BufferRequest {
    // The rect in pixels that will be drawn to the screen
    screen_rect: Rect<uint>,

    // The rect in page coordinates that this tile represents
    page_rect: Rect<f32>,
}

pub fn BufferRequest(screen_rect: Rect<uint>, page_rect: Rect<f32>) -> BufferRequest {
    BufferRequest {
        screen_rect: screen_rect,
        page_rect: page_rect,
    }
}

// FIXME(rust#9155): this should be a newtype struct, but
// generic newtypes ICE when compiled cross-crate
#[deriving(Clone)]
pub struct RenderChan<T> {
    chan: SharedChan<Msg<T>>,
}
impl<T: Send> RenderChan<T> {
    pub fn new(chan: Chan<Msg<T>>) -> RenderChan<T> {
        RenderChan {
            chan: SharedChan::new(chan),
        }
    }
}
impl<T: Send> GenericChan<Msg<T>> for RenderChan<T> {
    fn send(&self, msg: Msg<T>) {
        assert!(self.try_send(msg), "RenderChan.send: render port closed")
    }
}
impl<T: Send> GenericSmartChan<Msg<T>> for RenderChan<T> {
    fn try_send(&self, msg: Msg<T>) -> bool {
        self.chan.try_send(msg)
    }
}

/// If we're using GPU rendering, this provides the metadata needed to create a GL context that
/// is compatible with that of the main thread.
enum GraphicsContext {
    CpuGraphicsContext,
    GpuGraphicsContext,
}

pub struct RenderTask<C,T> {
    id: PipelineId,
    port: Port<Msg<T>>,
    compositor: C,
    constellation_chan: ConstellationChan,
    font_ctx: @mut FontContext,
    opts: Opts,

    /// A channel to the profiler.
    profiler_chan: ProfilerChan,

    /// The graphics context to use.
    graphics_context: GraphicsContext,

    /// The native graphics context.
    native_graphics_context: NativePaintingGraphicsContext,

    /// The layer to be rendered
    render_layer: Option<RenderLayer<T>>,

    /// Permission to send paint messages to the compositor
    paint_permission: bool,

    /// A counter for epoch messages
    epoch: Epoch,

    /// A data structure to store unused LayerBuffers
    buffer_map: BufferMap<~LayerBuffer>,
}

impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
    pub fn create(id: PipelineId,
                  port: Port<Msg<T>>,
                  compositor: C,
                  constellation_chan: ConstellationChan,
                  opts: Opts,
                  profiler_chan: ProfilerChan) {
        do spawn_with((port, compositor, constellation_chan, opts, profiler_chan))
            |(port, compositor, constellation_chan, opts, profiler_chan)| {

            let graphics_metadata = compositor.get_graphics_metadata();
            let cpu_painting = opts.cpu_painting;
            let native_graphics_context =
                    NativePaintingGraphicsContext::from_metadata(&graphics_metadata);

            // FIXME: rust/#5967
            let mut render_task = RenderTask {
                id: id,
                port: port,
                compositor: compositor,
                constellation_chan: constellation_chan,
                font_ctx: @mut FontContext::new(opts.render_backend.clone(),
                                                false,
                                                profiler_chan.clone()),
                opts: opts,
                profiler_chan: profiler_chan,

                graphics_context: if cpu_painting {
                    CpuGraphicsContext
                } else {
                    GpuGraphicsContext
                },

                native_graphics_context: native_graphics_context,

                render_layer: None,

                paint_permission: false,
                epoch: Epoch(0),
                buffer_map: BufferMap::new(10000000),
            };

            render_task.start();

            // Destroy all the buffers.
            render_task.buffer_map.clear(&render_task.native_graphics_context)
        }
    }

    fn start(&mut self) {
        debug!("render_task: beginning rendering loop");

        loop {
            match self.port.recv() {
                RenderMsg(render_layer) => {
                    if self.paint_permission {
                        self.epoch.next();
                        self.compositor.set_layer_page_size(self.id, render_layer.size, self.epoch);
                    } else {
                        self.constellation_chan.send(RendererReadyMsg(self.id));
                    }
                    self.render_layer = Some(render_layer);
                }
                ReRenderMsg(tiles, scale, epoch) => {
                    if self.epoch == epoch {
                        self.render(tiles, scale);
                    } else {
                        debug!("renderer epoch mismatch: {:?} != {:?}", self.epoch, epoch);
                    }
                }
                UnusedBufferMsg(unused_buffers) => {
                    // move_rev_iter is more efficient
                    for buffer in unused_buffers.move_rev_iter() {
                        self.buffer_map.insert(&self.native_graphics_context, buffer);
                    }
                }
                PaintPermissionGranted => {
                    self.paint_permission = true;
                    match self.render_layer {
                        Some(ref render_layer) => {
                            self.epoch.next();
                            self.compositor.set_layer_page_size(self.id, render_layer.size, self.epoch);
                        }
                        None => {}
                    }
                }
                PaintPermissionRevoked => {
                    self.paint_permission = false;
                }
                ExitMsg(response_ch) => {
                    response_ch.send(());
                    break;
                }
            }
        }
    }

    fn render(&mut self, tiles: ~[BufferRequest], scale: f32) {
        let render_layer;
        match self.render_layer {
            Some(ref r_layer) => {
                render_layer = r_layer;
            }
            _ => return, // nothing to do
        }

        self.compositor.set_render_state(RenderingRenderState);
        do time::profile(time::RenderingCategory, self.profiler_chan.clone()) {
            // FIXME: Try not to create a new array here.
            let mut new_buffers = ~[];

            // Divide up the layer into tiles.
            do time::profile(time::RenderingPrepBuffCategory, self.profiler_chan.clone()) {
                for tile in tiles.iter() {
                    let width = tile.screen_rect.size.width;
                    let height = tile.screen_rect.size.height;

                    let size = Size2D(width as i32, height as i32);
                    let draw_target = match self.graphics_context {
                        CpuGraphicsContext => {
                            DrawTarget::new(self.opts.render_backend, size, B8G8R8A8)
                        }
                        GpuGraphicsContext => {
                            // FIXME(pcwalton): Cache the components of draw targets
                            // (texture color buffer, renderbuffers) instead of recreating them.
                            let draw_target =
                                DrawTarget::new_with_fbo(self.opts.render_backend,
                                                         &self.native_graphics_context,
                                                         size,
                                                         B8G8R8A8);
                            draw_target.make_current();
                            draw_target
                        }
                    };

                    {
                        // Build the render context.
                        let ctx = RenderContext {
                            draw_target: &draw_target,
                            font_ctx: self.font_ctx,
                            opts: &self.opts,
                            page_rect: tile.page_rect,
                            screen_rect: tile.screen_rect,
                        };

                        // Apply the translation to render the tile we want.
                        let matrix: Matrix2D<AzFloat> = Matrix2D::identity();
                        let matrix = matrix.scale(scale as AzFloat, scale as AzFloat);
                        let matrix = matrix.translate(-(tile.page_rect.origin.x) as AzFloat,
                                                      -(tile.page_rect.origin.y) as AzFloat);

                        ctx.draw_target.set_transform(&matrix);

                        // Clear the buffer.
                        ctx.clear();

                        // Draw the display list.
                        do profile(time::RenderingDrawingCategory, self.profiler_chan.clone()) {
                            render_layer.display_list.get().draw_into_context(&ctx);
                            ctx.draw_target.flush();
                        }
                    }

                    // Extract the texture from the draw target and place it into its slot in the
                    // buffer. If using CPU rendering, upload it first.
                    //
                    // FIXME(pcwalton): We should supply the texture and native surface *to* the
                    // draw target in GPU rendering mode, so that it doesn't have to recreate it.
                    let buffer = match self.graphics_context {
                        CpuGraphicsContext => {
                            let buffer = match self.buffer_map.find(tile.screen_rect.size) {
                                Some(buffer) => {
                                    let mut buffer = buffer;
                                    buffer.rect = tile.page_rect;
                                    buffer.screen_pos = tile.screen_rect;
                                    buffer.resolution = scale;
                                    buffer.native_surface.mark_wont_leak();
                                    buffer
                                }
                                None => {
                                    // Create an empty native surface. We mark it as not leaking
                                    // in case it dies in transit to the compositor task.
                                    let mut native_surface: NativeSurface =
                                        layers::platform::surface::NativeSurfaceMethods::new(
                                            &self.native_graphics_context,
                                            Size2D(width as i32, height as i32),
                                            width as i32 * 4);
                                    native_surface.mark_wont_leak();

                                    ~LayerBuffer {
                                        native_surface: native_surface,
                                        rect: tile.page_rect,
                                        screen_pos: tile.screen_rect,
                                        resolution: scale,
                                        stride: (width * 4) as uint
                                    }
                                }
                            };

                            do draw_target.snapshot().get_data_surface().with_data |data| {
                                buffer.native_surface.upload(&self.native_graphics_context, data);
                                debug!("RENDERER uploading to native surface {:d}",
                                       buffer.native_surface.get_id() as int);
                            }

                            buffer
                        }
                        GpuGraphicsContext => {
                            draw_target.make_current();
                            let StolenGLResources {
                                surface: native_surface
                            } = draw_target.steal_gl_resources().unwrap();

                            // We mark the native surface as not leaking in case the surfaces
                            // die on their way to the compositor task.
                            let mut native_surface: NativeSurface =
                                NativeSurfaceAzureMethods::from_azure_surface(native_surface);
                            native_surface.mark_wont_leak();

                            ~LayerBuffer {
                                native_surface: native_surface,
                                rect: tile.page_rect,
                                screen_pos: tile.screen_rect,
                                resolution: scale,
                                stride: (width * 4) as uint
                            }
                        }
                    };

                    new_buffers.push(buffer);
                }
            }

            let layer_buffer_set = ~LayerBufferSet {
                buffers: new_buffers,
            };

            debug!("render_task: returning surface");
            if self.paint_permission {
                self.compositor.paint(self.id, layer_buffer_set, self.epoch);
            } else {
                self.constellation_chan.send(RendererReadyMsg(self.id));
            }
            self.compositor.set_render_state(IdleRenderState);
        }
    }
}

<|endoftext|>


<commit_before>use editor::Editor;
use mode::{Mode, PrimitiveMode, CommandMode};
use redraw::RedrawTask;
use key::Key;

use std::collections::VecDeque;
use std::iter::FromIterator;

#[derive(Clone, PartialEq, Copy)]
/// The type of the insert mode
pub enum InsertMode {
    /// Append text (after the cursor)
    Append,
    /// Insert text (before the cursor)
    Insert,
    /// Replace text (on the cursor)
    Replace,
}

#[derive(Clone, PartialEq, Copy)]
/// The insert options
pub struct InsertOptions {
    /// The mode type
    pub mode: InsertMode,
}

impl Editor {
    /// Delta x, i.e. the cursors visual position's x coordinate relative to the cursors actual
    /// position. For example append will append character after the cursor, but visually it have
    /// delta x = 1, so it will look like normal insert mode, except when going back to normal
    /// mode, the cursor will move back (visually), because the delta x will drop to 0.
    pub fn delta(&self) -> usize {
        let (x, y) = self.pos();
        match self.cursor().mode {
            _ if x > self.buffer[y].len() => {
                0
            }
            Mode::Primitive(PrimitiveMode::Insert(InsertOptions { mode: InsertMode::Append }))
                if x == self.buffer[y].len() => 0,

            Mode::Primitive(PrimitiveMode::Insert(InsertOptions { mode: InsertMode::Append })) => 1,
            _ => 0,
        }
    }

    /// Insert text under the current cursor.
    pub fn insert(&mut self, k: Key, InsertOptions { mode }: InsertOptions) {
        let (mut x, mut y) = self.pos();
        match mode {
            InsertMode::Insert | InsertMode::Append => {
                let d = self.delta();

                match k {
                    Key::Char('\n') => {
                        let first_part  = self.buffer[y][..x + d].to_owned();
                        let second_part = self.buffer[y][x + d..].to_owned();

                        self.buffer[y] = first_part;

                        let nl = if self.options.autoindent {
                            self.buffer.get_indent(y).to_owned() + &second_part
                        } else {
                            String::new()
                        };
                        let begin = nl.len();

                        self.buffer.insert_line(y, nl);

                        self.redraw_task = RedrawTask::LinesAfter(y);
                        self.goto((begin, y + 1));
                    }
                    Key::Backspace => {
                        // Backspace
                        let del = if self.buffer[y].len() == 0 {
                            1
                        } else if d == 0 && x == 0 {
                            self.cursor_mut().mode =
                                Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
                                    mode: InsertMode::Append,
                                }));
                            1

                        } else {
                            1 - d
                        };
                        let prev = self.previous(del);
                        if let Some((x, y)) = prev {
                            // if self.x() != 0 || self.y() != 0 {
                            self.goto((x + d, y));
                            self.delete();
                            // }
                        }
                    }
                    Key::Char(c) => {
                        self.buffer[y].insert(x + d, c);

                        // TODO: Are there a better way than switching?
                        match mode {
                            InsertMode::Insert if x + 1 == self.buffer[y].len() => {
                                self.cursor_mut().mode =
                                    Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
                                        mode: InsertMode::Append,
                                    }));
                            }
                            _ => {}
                        }

                        self.redraw_task = RedrawTask::Lines(y..y + 1);
                        let right = self.right(1);
                        self.goto(right);
                    }
                    _ => {}
                }
            }
            InsertMode::Replace => match k {
                Key::Char(c) => {
                    if x == self.buffer[y].len() {
                        let next = self.next(1);
                        if let Some(p) = next {
                            self.goto(p);
                            x = self.x();
                            y = self.y();
                        }
                    }

                    if self.buffer.len() != y {
                        if self.buffer[y].len() == x {
                            let next = self.next(1);
                            if let Some(p) = next {
                                self.goto(p);
                            }
                        } else {
                            self.buffer[y].remove(x);
                            self.buffer[y].insert(x, c);
                        }
                    }
                    let next = self.next(1);
                    if let Some(p) = next {
                        self.goto(p);
                    }
                    self.redraw_task = RedrawTask::Lines(y..y + 1);
                }
                _ => {}
            },
        }
    }

    /// Insert a string
    pub fn insert_str(&mut self, txt: String, opt: InsertOptions) {
        for c in txt.chars() {
            self.insert(Key::Char(c), opt);
        }
    }

}
<commit_msg>Fix bug on newline<commit_after>use editor::Editor;
use mode::{Mode, PrimitiveMode, CommandMode};
use redraw::RedrawTask;
use key::Key;

use std::collections::VecDeque;
use std::iter::FromIterator;

#[derive(Clone, PartialEq, Copy)]
/// The type of the insert mode
pub enum InsertMode {
    /// Append text (after the cursor)
    Append,
    /// Insert text (before the cursor)
    Insert,
    /// Replace text (on the cursor)
    Replace,
}

#[derive(Clone, PartialEq, Copy)]
/// The insert options
pub struct InsertOptions {
    /// The mode type
    pub mode: InsertMode,
}

impl Editor {
    /// Delta x, i.e. the cursors visual position's x coordinate relative to the cursors actual
    /// position. For example append will append character after the cursor, but visually it have
    /// delta x = 1, so it will look like normal insert mode, except when going back to normal
    /// mode, the cursor will move back (visually), because the delta x will drop to 0.
    pub fn delta(&self) -> usize {
        let (x, y) = self.pos();
        match self.cursor().mode {
            _ if x > self.buffer[y].len() => {
                0
            }
            Mode::Primitive(PrimitiveMode::Insert(InsertOptions { mode: InsertMode::Append }))
                if x == self.buffer[y].len() => 0,

            Mode::Primitive(PrimitiveMode::Insert(InsertOptions { mode: InsertMode::Append })) => 1,
            _ => 0,
        }
    }

    /// Insert text under the current cursor.
    pub fn insert(&mut self, k: Key, InsertOptions { mode }: InsertOptions) {
        let (mut x, mut y) = self.pos();
        match mode {
            InsertMode::Insert | InsertMode::Append => {
                let d = self.delta();

                match k {
                    Key::Char('\n') => {
                        let first_part  = self.buffer[y][..x + d].to_owned();
                        let second_part = self.buffer[y][x + d..].to_owned();

                        self.buffer[y] = first_part;

                        let nl = if self.options.autoindent {
                            self.buffer.get_indent(y).to_owned()
                        } else {
                            String::new()
                        };
                        let begin = nl.len();

                        self.buffer.insert_line(y, nl + &second_part);

                        self.redraw_task = RedrawTask::LinesAfter(y);
                        self.goto((begin, y + 1));
                    }
                    Key::Backspace => {
                        // Backspace
                        let del = if self.buffer[y].len() == 0 {
                            1
                        } else if d == 0 && x == 0 {
                            self.cursor_mut().mode =
                                Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
                                    mode: InsertMode::Append,
                                }));
                            1

                        } else {
                            1 - d
                        };
                        let prev = self.previous(del);
                        if let Some((x, y)) = prev {
                            // if self.x() != 0 || self.y() != 0 {
                            self.goto((x + d, y));
                            self.delete();
                            // }
                        }
                    }
                    Key::Char(c) => {
                        self.buffer[y].insert(x + d, c);

                        // TODO: Are there a better way than switching?
                        match mode {
                            InsertMode::Insert if x + 1 == self.buffer[y].len() => {
                                self.cursor_mut().mode =
                                    Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
                                        mode: InsertMode::Append,
                                    }));
                            }
                            _ => {}
                        }

                        self.redraw_task = RedrawTask::Lines(y..y + 1);
                        let right = self.right(1);
                        self.goto(right);
                    }
                    _ => {}
                }
            }
            InsertMode::Replace => match k {
                Key::Char(c) => {
                    if x == self.buffer[y].len() {
                        let next = self.next(1);
                        if let Some(p) = next {
                            self.goto(p);
                            x = self.x();
                            y = self.y();
                        }
                    }

                    if self.buffer.len() != y {
                        if self.buffer[y].len() == x {
                            let next = self.next(1);
                            if let Some(p) = next {
                                self.goto(p);
                            }
                        } else {
                            self.buffer[y].remove(x);
                            self.buffer[y].insert(x, c);
                        }
                    }
                    let next = self.next(1);
                    if let Some(p) = next {
                        self.goto(p);
                    }
                    self.redraw_task = RedrawTask::Lines(y..y + 1);
                }
                _ => {}
            },
        }
    }

    /// Insert a string
    pub fn insert_str(&mut self, txt: String, opt: InsertOptions) {
        for c in txt.chars() {
            self.insert(Key::Char(c), opt);
        }
    }

}
<|endoftext|>