<commit_before>//! Module containing the types which make up `gluon`'s AST (Abstract Syntax Tree)

use std::ops::Deref;

use pos::{BytePos, Spanned};
use symbol::Symbol;
use types::{self, Alias, AliasData, ArcType, Type, TypeEnv};

pub trait DisplayEnv {
    type Ident;

    fn string<'a>(&'a self, ident: &'a Self::Ident) -> &'a str;
}

pub trait IdentEnv: DisplayEnv {
    fn from_str(&mut self, s: &str) -> Self::Ident;
}

pub struct EmptyEnv<T>(::std::marker::PhantomData<T>);

impl<T> EmptyEnv<T> {
    pub fn new() -> EmptyEnv<T> {
        EmptyEnv(::std::marker::PhantomData)
    }
}

impl<T: AsRef<str>> DisplayEnv for EmptyEnv<T> {
    type Ident = T;

    fn string<'a>(&'a self, ident: &'a Self::Ident) -> &'a str {
        ident.as_ref()
    }
}

impl<'t, T: ?Sized + DisplayEnv> DisplayEnv for &'t T {
    type Ident = T::Ident;

    fn string<'a>(&'a self, ident: &'a Self::Ident) -> &'a str {
        (**self).string(ident)
    }
}

impl<'t, T: ?Sized + DisplayEnv> DisplayEnv for &'t mut T {
    type Ident = T::Ident;

    fn string<'a>(&'a self, ident: &'a Self::Ident) -> &'a str {
        (**self).string(ident)
    }
}

impl<T> IdentEnv for EmptyEnv<T>
    where T: AsRef<str> + for<'a> From<&'a str>,
{
    fn from_str(&mut self, s: &str) -> Self::Ident {
        T::from(s)
    }
}

impl<'a, T: ?Sized + IdentEnv> IdentEnv for &'a mut T {
    fn from_str(&mut self, s: &str) -> Self::Ident {
        (**self).from_str(s)
    }
}

#[derive(Clone, Eq, PartialEq, Debug)]
pub struct TypedIdent<Id = Symbol> {
    pub typ: ArcType<Id>,
    pub name: Id,
}

impl<Id> TypedIdent<Id> {
    pub fn new(name: Id) -> TypedIdent<Id> {
        TypedIdent {
            typ: Type::hole(),
            name: name,
        }
    }
}

impl<Id> AsRef<str> for TypedIdent<Id>
    where Id: AsRef<str>,
{
    fn as_ref(&self) -> &str {
        self.name.as_ref()
    }
}

#[derive(Clone, PartialEq, Debug)]
pub enum Literal {
    Byte(u8),
    Integer(i64),
    Float(f64),
    String(String),
    Char(char),
}

/// Pattern which contains a location
pub type SpannedPattern<Id> = Spanned<Pattern<Id>, BytePos>;

#[derive(Clone, PartialEq, Debug)]
pub enum Pattern<Id> {
    Constructor(TypedIdent<Id>, Vec<TypedIdent<Id>>),
    Record {
        typ: ArcType<Id>,
        types: Vec<(Id, Option<Id>)>,
        fields: Vec<(Id, Option<Id>)>,
    },
    Ident(TypedIdent<Id>),
}

#[derive(Clone, PartialEq, Debug)]
pub struct Alternative<Id> {
    pub pattern: SpannedPattern<Id>,
    pub expression: SpannedExpr<Id>,
}

#[derive(Clone, PartialEq, Debug)]
pub struct Array<Id> {
    pub typ: ArcType<Id>,
    pub expressions: Vec<SpannedExpr<Id>>,
}

#[derive(Clone, PartialEq, Debug)]
pub struct Lambda<Id> {
    pub id: TypedIdent<Id>,
    pub arguments: Vec<TypedIdent<Id>>,
    pub body: Box<SpannedExpr<Id>>,
}

/// Expression which contains a location
pub type SpannedExpr<Id> = Spanned<Expr<Id>, BytePos>;

/// The representation of gluon's expression syntax
#[derive(Clone, PartialEq, Debug)]
pub enum Expr<Id> {
    /// Identifiers
    Ident(TypedIdent<Id>),
    /// Literal values
    Literal(Literal),
    /// Function application, eg. `f x`
    App(Box<SpannedExpr<Id>>, Vec<SpannedExpr<Id>>),
    /// Lambda abstraction, eg. `\x y -> x * y`
    Lambda(Lambda<Id>),
    /// If-then-else conditional
    IfElse(Box<SpannedExpr<Id>>, Box<SpannedExpr<Id>>, Box<SpannedExpr<Id>>),
    /// Pattern match expression
    Match(Box<SpannedExpr<Id>>, Vec<Alternative<Id>>),
    /// Infix operator expression eg. `f >> g`
    Infix(Box<SpannedExpr<Id>>, TypedIdent<Id>, Box<SpannedExpr<Id>>),
    /// Record field projection, eg. `value.field`
    Projection(Box<SpannedExpr<Id>>, Id, ArcType<Id>),
    /// Array construction
    Array(Array<Id>),
    /// Record construction
    Record {
        typ: ArcType<Id>,
        types: Vec<(Id, Option<ArcType<Id>>)>,
        exprs: Vec<(Id, Option<SpannedExpr<Id>>)>,
    },
    /// Tuple construction
    Tuple(Vec<SpannedExpr<Id>>),
    /// Declare a series of value bindings
    LetBindings(Vec<ValueBinding<Id>>, Box<SpannedExpr<Id>>),
    /// Declare a series of type aliases
    TypeBindings(Vec<TypeBinding<Id>>, Box<SpannedExpr<Id>>),
    /// A group of sequenced expressions
    Block(Vec<SpannedExpr<Id>>),
}

#[derive(Clone, PartialEq, Debug)]
pub struct TypeBinding<Id> {
    pub comment: Option<String>,
    pub name: Id,
    pub alias: Alias<Id, ArcType<Id>>,
}

#[derive(Clone, PartialEq, Debug)]
pub struct ValueBinding<Id> {
    pub comment: Option<String>,
    pub name: SpannedPattern<Id>,
    pub typ: ArcType<Id>,
    pub arguments: Vec<TypedIdent<Id>>,
    pub expression: SpannedExpr<Id>,
}

/// Visitor trait which walks over expressions calling `visit_*` on all encountered elements. By
/// default the `visit_*` functions just walk the tree. If they are overriden the user will need to
/// call `walk_mut_*` to continue traversing the tree.
pub trait MutVisitor {
    type Ident;

    fn visit_expr(&mut self, e: &mut SpannedExpr<Self::Ident>) {
        walk_mut_expr(self, e);
    }

    fn visit_pattern(&mut self, e: &mut SpannedPattern<Self::Ident>) {
        walk_mut_pattern(self, &mut e.value);
    }

    fn visit_typ(&mut self, _: &mut ArcType<Self::Ident>) {}
}

pub fn walk_mut_expr<V: ?Sized + MutVisitor>(v: &mut V, e: &mut SpannedExpr<V::Ident>) {
    match e.value {
        Expr::IfElse(ref mut pred, ref mut if_true, ref mut if_false) => {
            v.visit_expr(&mut **pred);
            v.visit_expr(&mut **if_true);
            v.visit_expr(&mut **if_false);
        }
        Expr::Infix(ref mut lhs, ref mut id, ref mut rhs) => {
            v.visit_expr(&mut **lhs);
            v.visit_typ(&mut id.typ);
            v.visit_expr(&mut **rhs);
        }
        Expr::LetBindings(ref mut bindings, ref mut body) => {
            for bind in bindings {
                v.visit_pattern(&mut bind.name);
                v.visit_expr(&mut bind.expression);
            }
            v.visit_expr(&mut **body);
        }
        Expr::App(ref mut func, ref mut args) => {
            v.visit_expr(&mut **func);
            for arg in args {
                v.visit_expr(arg);
            }
        }
        Expr::Projection(ref mut expr, _, ref mut typ) => {
            v.visit_expr(&mut **expr);
            v.visit_typ(typ);
        }
        Expr::Match(ref mut expr, ref mut alts) => {
            v.visit_expr(&mut **expr);
            for alt in alts.iter_mut() {
                v.visit_pattern(&mut alt.pattern);
                v.visit_expr(&mut alt.expression);
            }
        }
        Expr::Array(ref mut a) => {
            v.visit_typ(&mut a.typ);
            for expr in &mut a.expressions {
                v.visit_expr(expr);
            }
        }
        Expr::Record { ref mut typ, ref mut exprs, .. } => {
            v.visit_typ(typ);
            for field in exprs {
                if let Some(ref mut expr) = field.1 {
                    v.visit_expr(expr);
                }
            }
        }
        Expr::Tuple(ref mut exprs) => {
            for expr in exprs {
                v.visit_expr(expr);
            }
        }
        Expr::Lambda(ref mut lambda) => {
            v.visit_typ(&mut lambda.id.typ);
            v.visit_expr(&mut *lambda.body);
        }
        Expr::TypeBindings(_, ref mut expr) => v.visit_expr(&mut *expr),
        Expr::Ident(ref mut id) => v.visit_typ(&mut id.typ),
        Expr::Literal(..) => (),
        Expr::Block(ref mut exprs) => {
            for expr in exprs {
                v.visit_expr(expr);
            }
        }
    }
}

/// Walks a pattern, calling `visit_*` on all relevant elements
pub fn walk_mut_pattern<V: ?Sized + MutVisitor>(v: &mut V, p: &mut Pattern<V::Ident>) {
    match *p {
        Pattern::Constructor(ref mut id, ref mut args) => {
            v.visit_typ(&mut id.typ);
            for arg in args {
                v.visit_typ(&mut arg.typ);
            }
        }
        Pattern::Record { ref mut typ, .. } => {
            v.visit_typ(typ);
        }
        Pattern::Ident(ref mut id) => v.visit_typ(&mut id.typ),
    }
}

/// Trait which abstracts over things that have a type.
/// It is not guaranteed that the correct type is returned until after typechecking
pub trait Typed {
    type Ident;

    fn env_type_of(&self, env: &TypeEnv) -> ArcType<Self::Ident>;
}

impl<Id: Clone> Typed for TypedIdent<Id> {
    type Ident = Id;

    fn env_type_of(&self, _: &TypeEnv) -> ArcType<Id> {
        self.typ.clone()
    }
}

impl Typed for Expr<Symbol> {
    type Ident = Symbol;

    fn env_type_of(&self, env: &TypeEnv) -> ArcType {
        match *self {
            Expr::Ident(ref id) => id.typ.clone(),
            Expr::Projection(_, _, ref typ) => typ.clone(),
            Expr::Literal(ref lit) => {
                match *lit {
                    Literal::Integer(_) => Type::int(),
                    Literal::Float(_) => Type::float(),
                    Literal::Byte(_) => Type::byte(),
                    Literal::String(_) => Type::string(),
                    Literal::Char(_) => Type::char(),
                }
            }
            Expr::IfElse(_, ref arm, _) => arm.env_type_of(env),
            Expr::Tuple(ref exprs) => {
                assert!(exprs.is_empty());
                Type::unit()
            }
            Expr::Infix(_, ref op, _) => {
                if let Type::App(_, ref args) = *op.typ.clone() {
                    if let Type::App(_, ref args) = *args[1] {
                        return args[1].clone();
                    }
                }
                panic!("Expected function type in binop");
            }
            Expr::LetBindings(_, ref expr) |
            Expr::TypeBindings(_, ref expr) => expr.env_type_of(env),
            Expr::App(ref func, ref args) => {
                get_return_type(env, &func.env_type_of(env), args.len())
            }
            Expr::Match(_, ref alts) => alts[0].expression.env_type_of(env),
            Expr::Array(ref array) => array.typ.clone(),
            Expr::Lambda(ref lambda) => lambda.id.typ.clone(),
            Expr::Record { ref typ, .. } => typ.clone(),
            Expr::Block(ref exprs) => exprs.last().expect("Expr in block").env_type_of(env),
        }
    }
}

impl<T: Typed> Typed for Spanned<T, BytePos> {
    type Ident = T::Ident;

    fn env_type_of(&self, env: &TypeEnv) -> ArcType<T::Ident> {
        self.value.env_type_of(env)
    }
}

impl Typed for Pattern<Symbol> {
    type Ident = Symbol;

    fn env_type_of(&self, env: &TypeEnv) -> ArcType {
        // Identifier patterns might be a function so use the identifier's type instead
        match *self {
            Pattern::Ident(ref id) => id.typ.clone(),
            Pattern::Record { ref typ, .. } => typ.clone(),
            Pattern::Constructor(ref id, ref args) => get_return_type(env, &id.typ, args.len()),
        }
    }
}

fn get_return_type(env: &TypeEnv, alias_type: &ArcType, arg_count: usize) -> ArcType {
    if arg_count == 0 {
        alias_type.clone()
    } else {
        match alias_type.as_function() {
            Some((_, ret)) => get_return_type(env, ret, arg_count - 1),
            None => {
                match alias_type.as_alias() {
                    Some((id, alias_args)) => {
                        let (args, typ) = match env.find_type_info(&id).map(Alias::deref) {
                            Some(&AliasData { ref args, typ: Some(ref typ), .. }) => (args, typ),
                            Some(&AliasData { .. }) => panic!("ICE: '{:?}' does not exist", id),
                            None => panic!("Unexpected type {:?} is not a function", alias_type),
                        };

                        let typ = types::instantiate(typ.clone(), |gen| {
                            // Replace the generic variable with the type from the list
                            // or if it is not found the make a fresh variable
                            args.iter()
                                .zip(alias_args)
                                .find(|&(arg, _)| arg.id == gen.id)
                                .map(|(_, typ)| typ.clone())
                        });

                        get_return_type(env, &typ, arg_count)
                    }
                    None => {
                        panic!("ICE: Expected function with {} more arguments, found {:?}",
                               arg_count,
                               alias_type)
                    }
                }
            }
        }
    }
}
<commit_msg>Remove unused impl<commit_after>//! Module containing the types which make up `gluon`'s AST (Abstract Syntax Tree)

use std::ops::Deref;

use pos::{BytePos, Spanned};
use symbol::Symbol;
use types::{self, Alias, AliasData, ArcType, Type, TypeEnv};

pub trait DisplayEnv {
    type Ident;

    fn string<'a>(&'a self, ident: &'a Self::Ident) -> &'a str;
}

pub trait IdentEnv: DisplayEnv {
    fn from_str(&mut self, s: &str) -> Self::Ident;
}

pub struct EmptyEnv<T>(::std::marker::PhantomData<T>);

impl<T> EmptyEnv<T> {
    pub fn new() -> EmptyEnv<T> {
        EmptyEnv(::std::marker::PhantomData)
    }
}

impl<T: AsRef<str>> DisplayEnv for EmptyEnv<T> {
    type Ident = T;

    fn string<'a>(&'a self, ident: &'a Self::Ident) -> &'a str {
        ident.as_ref()
    }
}

impl<'t, T: ?Sized + DisplayEnv> DisplayEnv for &'t mut T {
    type Ident = T::Ident;

    fn string<'a>(&'a self, ident: &'a Self::Ident) -> &'a str {
        (**self).string(ident)
    }
}

impl<T> IdentEnv for EmptyEnv<T>
    where T: AsRef<str> + for<'a> From<&'a str>,
{
    fn from_str(&mut self, s: &str) -> Self::Ident {
        T::from(s)
    }
}

impl<'a, T: ?Sized + IdentEnv> IdentEnv for &'a mut T {
    fn from_str(&mut self, s: &str) -> Self::Ident {
        (**self).from_str(s)
    }
}

#[derive(Clone, Eq, PartialEq, Debug)]
pub struct TypedIdent<Id = Symbol> {
    pub typ: ArcType<Id>,
    pub name: Id,
}

impl<Id> TypedIdent<Id> {
    pub fn new(name: Id) -> TypedIdent<Id> {
        TypedIdent {
            typ: Type::hole(),
            name: name,
        }
    }
}

impl<Id> AsRef<str> for TypedIdent<Id>
    where Id: AsRef<str>,
{
    fn as_ref(&self) -> &str {
        self.name.as_ref()
    }
}

#[derive(Clone, PartialEq, Debug)]
pub enum Literal {
    Byte(u8),
    Integer(i64),
    Float(f64),
    String(String),
    Char(char),
}

/// Pattern which contains a location
pub type SpannedPattern<Id> = Spanned<Pattern<Id>, BytePos>;

#[derive(Clone, PartialEq, Debug)]
pub enum Pattern<Id> {
    Constructor(TypedIdent<Id>, Vec<TypedIdent<Id>>),
    Record {
        typ: ArcType<Id>,
        types: Vec<(Id, Option<Id>)>,
        fields: Vec<(Id, Option<Id>)>,
    },
    Ident(TypedIdent<Id>),
}

#[derive(Clone, PartialEq, Debug)]
pub struct Alternative<Id> {
    pub pattern: SpannedPattern<Id>,
    pub expression: SpannedExpr<Id>,
}

#[derive(Clone, PartialEq, Debug)]
pub struct Array<Id> {
    pub typ: ArcType<Id>,
    pub expressions: Vec<SpannedExpr<Id>>,
}

#[derive(Clone, PartialEq, Debug)]
pub struct Lambda<Id> {
    pub id: TypedIdent<Id>,
    pub arguments: Vec<TypedIdent<Id>>,
    pub body: Box<SpannedExpr<Id>>,
}

/// Expression which contains a location
pub type SpannedExpr<Id> = Spanned<Expr<Id>, BytePos>;

/// The representation of gluon's expression syntax
#[derive(Clone, PartialEq, Debug)]
pub enum Expr<Id> {
    /// Identifiers
    Ident(TypedIdent<Id>),
    /// Literal values
    Literal(Literal),
    /// Function application, eg. `f x`
    App(Box<SpannedExpr<Id>>, Vec<SpannedExpr<Id>>),
    /// Lambda abstraction, eg. `\x y -> x * y`
    Lambda(Lambda<Id>),
    /// If-then-else conditional
    IfElse(Box<SpannedExpr<Id>>, Box<SpannedExpr<Id>>, Box<SpannedExpr<Id>>),
    /// Pattern match expression
    Match(Box<SpannedExpr<Id>>, Vec<Alternative<Id>>),
    /// Infix operator expression eg. `f >> g`
    Infix(Box<SpannedExpr<Id>>, TypedIdent<Id>, Box<SpannedExpr<Id>>),
    /// Record field projection, eg. `value.field`
    Projection(Box<SpannedExpr<Id>>, Id, ArcType<Id>),
    /// Array construction
    Array(Array<Id>),
    /// Record construction
    Record {
        typ: ArcType<Id>,
        types: Vec<(Id, Option<ArcType<Id>>)>,
        exprs: Vec<(Id, Option<SpannedExpr<Id>>)>,
    },
    /// Tuple construction
    Tuple(Vec<SpannedExpr<Id>>),
    /// Declare a series of value bindings
    LetBindings(Vec<ValueBinding<Id>>, Box<SpannedExpr<Id>>),
    /// Declare a series of type aliases
    TypeBindings(Vec<TypeBinding<Id>>, Box<SpannedExpr<Id>>),
    /// A group of sequenced expressions
    Block(Vec<SpannedExpr<Id>>),
}

#[derive(Clone, PartialEq, Debug)]
pub struct TypeBinding<Id> {
    pub comment: Option<String>,
    pub name: Id,
    pub alias: Alias<Id, ArcType<Id>>,
}

#[derive(Clone, PartialEq, Debug)]
pub struct ValueBinding<Id> {
    pub comment: Option<String>,
    pub name: SpannedPattern<Id>,
    pub typ: ArcType<Id>,
    pub arguments: Vec<TypedIdent<Id>>,
    pub expression: SpannedExpr<Id>,
}

/// Visitor trait which walks over expressions calling `visit_*` on all encountered elements. By
/// default the `visit_*` functions just walk the tree. If they are overriden the user will need to
/// call `walk_mut_*` to continue traversing the tree.
pub trait MutVisitor {
    type Ident;

    fn visit_expr(&mut self, e: &mut SpannedExpr<Self::Ident>) {
        walk_mut_expr(self, e);
    }

    fn visit_pattern(&mut self, e: &mut SpannedPattern<Self::Ident>) {
        walk_mut_pattern(self, &mut e.value);
    }

    fn visit_typ(&mut self, _: &mut ArcType<Self::Ident>) {}
}

pub fn walk_mut_expr<V: ?Sized + MutVisitor>(v: &mut V, e: &mut SpannedExpr<V::Ident>) {
    match e.value {
        Expr::IfElse(ref mut pred, ref mut if_true, ref mut if_false) => {
            v.visit_expr(&mut **pred);
            v.visit_expr(&mut **if_true);
            v.visit_expr(&mut **if_false);
        }
        Expr::Infix(ref mut lhs, ref mut id, ref mut rhs) => {
            v.visit_expr(&mut **lhs);
            v.visit_typ(&mut id.typ);
            v.visit_expr(&mut **rhs);
        }
        Expr::LetBindings(ref mut bindings, ref mut body) => {
            for bind in bindings {
                v.visit_pattern(&mut bind.name);
                v.visit_expr(&mut bind.expression);
            }
            v.visit_expr(&mut **body);
        }
        Expr::App(ref mut func, ref mut args) => {
            v.visit_expr(&mut **func);
            for arg in args {
                v.visit_expr(arg);
            }
        }
        Expr::Projection(ref mut expr, _, ref mut typ) => {
            v.visit_expr(&mut **expr);
            v.visit_typ(typ);
        }
        Expr::Match(ref mut expr, ref mut alts) => {
            v.visit_expr(&mut **expr);
            for alt in alts.iter_mut() {
                v.visit_pattern(&mut alt.pattern);
                v.visit_expr(&mut alt.expression);
            }
        }
        Expr::Array(ref mut a) => {
            v.visit_typ(&mut a.typ);
            for expr in &mut a.expressions {
                v.visit_expr(expr);
            }
        }
        Expr::Record { ref mut typ, ref mut exprs, .. } => {
            v.visit_typ(typ);
            for field in exprs {
                if let Some(ref mut expr) = field.1 {
                    v.visit_expr(expr);
                }
            }
        }
        Expr::Tuple(ref mut exprs) => {
            for expr in exprs {
                v.visit_expr(expr);
            }
        }
        Expr::Lambda(ref mut lambda) => {
            v.visit_typ(&mut lambda.id.typ);
            v.visit_expr(&mut *lambda.body);
        }
        Expr::TypeBindings(_, ref mut expr) => v.visit_expr(&mut *expr),
        Expr::Ident(ref mut id) => v.visit_typ(&mut id.typ),
        Expr::Literal(..) => (),
        Expr::Block(ref mut exprs) => {
            for expr in exprs {
                v.visit_expr(expr);
            }
        }
    }
}

/// Walks a pattern, calling `visit_*` on all relevant elements
pub fn walk_mut_pattern<V: ?Sized + MutVisitor>(v: &mut V, p: &mut Pattern<V::Ident>) {
    match *p {
        Pattern::Constructor(ref mut id, ref mut args) => {
            v.visit_typ(&mut id.typ);
            for arg in args {
                v.visit_typ(&mut arg.typ);
            }
        }
        Pattern::Record { ref mut typ, .. } => {
            v.visit_typ(typ);
        }
        Pattern::Ident(ref mut id) => v.visit_typ(&mut id.typ),
    }
}

/// Trait which abstracts over things that have a type.
/// It is not guaranteed that the correct type is returned until after typechecking
pub trait Typed {
    type Ident;

    fn env_type_of(&self, env: &TypeEnv) -> ArcType<Self::Ident>;
}

impl<Id: Clone> Typed for TypedIdent<Id> {
    type Ident = Id;

    fn env_type_of(&self, _: &TypeEnv) -> ArcType<Id> {
        self.typ.clone()
    }
}

impl Typed for Expr<Symbol> {
    type Ident = Symbol;

    fn env_type_of(&self, env: &TypeEnv) -> ArcType {
        match *self {
            Expr::Ident(ref id) => id.typ.clone(),
            Expr::Projection(_, _, ref typ) => typ.clone(),
            Expr::Literal(ref lit) => {
                match *lit {
                    Literal::Integer(_) => Type::int(),
                    Literal::Float(_) => Type::float(),
                    Literal::Byte(_) => Type::byte(),
                    Literal::String(_) => Type::string(),
                    Literal::Char(_) => Type::char(),
                }
            }
            Expr::IfElse(_, ref arm, _) => arm.env_type_of(env),
            Expr::Tuple(ref exprs) => {
                assert!(exprs.is_empty());
                Type::unit()
            }
            Expr::Infix(_, ref op, _) => {
                if let Type::App(_, ref args) = *op.typ.clone() {
                    if let Type::App(_, ref args) = *args[1] {
                        return args[1].clone();
                    }
                }
                panic!("Expected function type in binop");
            }
            Expr::LetBindings(_, ref expr) |
            Expr::TypeBindings(_, ref expr) => expr.env_type_of(env),
            Expr::App(ref func, ref args) => {
                get_return_type(env, &func.env_type_of(env), args.len())
            }
            Expr::Match(_, ref alts) => alts[0].expression.env_type_of(env),
            Expr::Array(ref array) => array.typ.clone(),
            Expr::Lambda(ref lambda) => lambda.id.typ.clone(),
            Expr::Record { ref typ, .. } => typ.clone(),
            Expr::Block(ref exprs) => exprs.last().expect("Expr in block").env_type_of(env),
        }
    }
}

impl<T: Typed> Typed for Spanned<T, BytePos> {
    type Ident = T::Ident;

    fn env_type_of(&self, env: &TypeEnv) -> ArcType<T::Ident> {
        self.value.env_type_of(env)
    }
}

impl Typed for Pattern<Symbol> {
    type Ident = Symbol;

    fn env_type_of(&self, env: &TypeEnv) -> ArcType {
        // Identifier patterns might be a function so use the identifier's type instead
        match *self {
            Pattern::Ident(ref id) => id.typ.clone(),
            Pattern::Record { ref typ, .. } => typ.clone(),
            Pattern::Constructor(ref id, ref args) => get_return_type(env, &id.typ, args.len()),
        }
    }
}

fn get_return_type(env: &TypeEnv, alias_type: &ArcType, arg_count: usize) -> ArcType {
    if arg_count == 0 {
        alias_type.clone()
    } else {
        match alias_type.as_function() {
            Some((_, ret)) => get_return_type(env, ret, arg_count - 1),
            None => {
                match alias_type.as_alias() {
                    Some((id, alias_args)) => {
                        let (args, typ) = match env.find_type_info(&id).map(Alias::deref) {
                            Some(&AliasData { ref args, typ: Some(ref typ), .. }) => (args, typ),
                            Some(&AliasData { .. }) => panic!("ICE: '{:?}' does not exist", id),
                            None => panic!("Unexpected type {:?} is not a function", alias_type),
                        };

                        let typ = types::instantiate(typ.clone(), |gen| {
                            // Replace the generic variable with the type from the list
                            // or if it is not found the make a fresh variable
                            args.iter()
                                .zip(alias_args)
                                .find(|&(arg, _)| arg.id == gen.id)
                                .map(|(_, typ)| typ.clone())
                        });

                        get_return_type(env, &typ, arg_count)
                    }
                    None => {
                        panic!("ICE: Expected function with {} more arguments, found {:?}",
                               arg_count,
                               alias_type)
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io
extern crate hyper;
extern crate retry;
#[macro_use]
extern crate slog;
#[macro_use]
extern crate slog_scope;

use std::process::Command;
use std::error::Error;

extern crate mimir;
use mimir::rubber::Rubber;

/// This struct wraps a docker (for the moment explicitly ElasticSearch)
/// Allowing to setup a docker, tear it down and to provide its address and port
pub struct DockerWrapper {
    ip: String,
}

impl DockerWrapper {
    pub fn host(&self) -> String {
        format!("http://{}:9200", self.ip)
    }

    fn setup(&mut self) -> Result<(), Box<Error>> {
        info!("Launching ES docker");
        let status = try!(
            Command::new("docker")
                .args(&["run", "-d", "--name=mimirsbrunn_tests", "elasticsearch:2"])
                .status()
        );
        if !status.success() {
            return Err(format!("`docker run` failed {}", &status).into());
        }

        // we need to get the ip of the container if the container has been run on another machine
        let container_ip_cmd = try!(
            Command::new("docker")
                .args(&[
                    "inspect",
                    "--format={{.NetworkSettings.IPAddress}}",
                    "mimirsbrunn_tests",
                ])
                .output()
        );

        let container_ip = std::str::from_utf8(container_ip_cmd.stdout.as_slice())?.trim();

        warn!("container ip = {:?}", container_ip);
        self.ip = container_ip.to_string();

        info!("Waiting for ES in docker to be up and running...");
        match retry::retry(
            200,
            100,
            || hyper::client::Client::new().get(&self.host()).send(),
            |response| {
                response
                    .as_ref()
                    .map(|res| res.status == hyper::Ok)
                    .unwrap_or(false)
            },
        ) {
            Ok(_) => Ok(()),
            Err(_) => Err("ES is down".into()),
        }
    }

    pub fn new() -> Result<DockerWrapper, Box<Error>> {
        let mut wrapper = DockerWrapper { ip: "".to_string() };
        try!(wrapper.setup());
        let rubber = Rubber::new(&wrapper.host());
        rubber.initialize_templates().unwrap();
        Ok(wrapper)
    }
}

fn docker_command(args: &[&'static str]) {
    info!("Running docker {:?}", args);
    let status = Command::new("docker").args(args).status();
    match status {
        Ok(s) => {
            if !s.success() {
                warn!("`docker {a:?}` failed {s}", a = args, s = s)
            }
        }
        Err(e) => warn!("command `docker {a:?}` failed {e}", a = args, e = e),
    }
}

impl Drop for DockerWrapper {
    fn drop(&mut self) {
        if std::env::var("DONT_KILL_THE_WHALE") == Ok("1".to_string()) {
            warn!(
                "the docker won't be stoped at the end, you can debug it.
            Note: ES has been mapped to the port 9242 in you localhost
            manually stop and rm the container mimirsbrunn_tests after debug"
            );
            return;
        }
        docker_command(&["stop", "mimirsbrunn_tests"]);
        docker_command(&["rm", "mimirsbrunn_tests"]);
    }
}
<commit_msg>Compat stable/nightly<commit_after>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io
extern crate hyper;
extern crate retry;
#[macro_use]
extern crate slog;
#[macro_use]
extern crate slog_scope;

use std::process::Command;
use std::error::Error;

extern crate mimir;
use mimir::rubber::Rubber;

/// This struct wraps a docker (for the moment explicitly ElasticSearch)
/// Allowing to setup a docker, tear it down and to provide its address and port
pub struct DockerWrapper {
    ip: String,
}

impl DockerWrapper {
    pub fn host(&self) -> String {
        format!("http://{}:9200", self.ip)
    }

    fn setup(&mut self) -> Result<(), Box<Error>> {
        info!("Launching ES docker");
        let status = try!(
            Command::new("docker")
                .args(&["run", "-d", "--name=mimirsbrunn_tests", "elasticsearch:2"])
                .status()
        );
        if !status.success() {
            return Err(format!("`docker run` failed {}", &status).into());
        }

        // we need to get the ip of the container if the container has been run on another machine
        let container_ip_cmd = try!(
            Command::new("docker")
                .args(&[
                    "inspect",
                    "--format={{.NetworkSettings.IPAddress}}",
                    "mimirsbrunn_tests",
                ])
                .output()
        );

        let container_ip = std::str::from_utf8(container_ip_cmd.stdout.as_slice())?.trim();

        warn!("container ip = {:?}", container_ip);
        self.ip = container_ip.to_string();

        info!("Waiting for ES in docker to be up and running...");
        let retry = retry::retry(
            200,
            100,
            || hyper::client::Client::new().get(&self.host()).send(),
            |response| {
                response
                    .as_ref()
                    .map(|res| res.status == hyper::Ok)
                    .unwrap_or(false)
            },
        );
        match retry {
            Ok(_) => Ok(()),
            Err(_) => Err("ES is down".into()),
        }
    }

    pub fn new() -> Result<DockerWrapper, Box<Error>> {
        let mut wrapper = DockerWrapper { ip: "".to_string() };
        try!(wrapper.setup());
        let rubber = Rubber::new(&wrapper.host());
        rubber.initialize_templates().unwrap();
        Ok(wrapper)
    }
}

fn docker_command(args: &[&'static str]) {
    info!("Running docker {:?}", args);
    let status = Command::new("docker").args(args).status();
    match status {
        Ok(s) => {
            if !s.success() {
                warn!("`docker {a:?}` failed {s}", a = args, s = s)
            }
        }
        Err(e) => warn!("command `docker {a:?}` failed {e}", a = args, e = e),
    }
}

impl Drop for DockerWrapper {
    fn drop(&mut self) {
        if std::env::var("DONT_KILL_THE_WHALE") == Ok("1".to_string()) {
            warn!(
                "the docker won't be stoped at the end, you can debug it.
            Note: ES has been mapped to the port 9242 in you localhost
            manually stop and rm the container mimirsbrunn_tests after debug"
            );
            return;
        }
        docker_command(&["stop", "mimirsbrunn_tests"]);
        docker_command(&["rm", "mimirsbrunn_tests"]);
    }
}
<|endoftext|>


<commit_before>#![crate_name = "toy_aa"]
#![crate_type = "dylib"]

use std::fmt::{mod, Show, Formatter};
use std::mem::{replace, swap};

type Link<T> = Option<Box<T>>;

struct Node<K, V> {
    key: K,
    value: V,
    left: Link<Node<K, V>>,
    right: Link<Node<K, V>>,
    level: uint
}

pub struct Tree<K, V> {
    root: Link<Node<K, V>>,
}

impl<K: Ord, V> Tree<K, V> {
    pub fn new() -> Tree<K, V> {
        Tree { root: None }
    }

    fn is_bst(&self) -> bool {
        match self.root {
            None => true,
            Some(ref r) => r.is_bst()
        }
    }

    fn is_aa(&self) -> bool {
        match self.root {
            None => true,
            Some(ref r) => r.is_aa()
        }
    }

    pub fn find<'a>(&'a self, key: &K) -> Option<&'a V> {
        match self.root {
            None => None,
            Some(ref r) => r.find(key)
        }
    }

    pub fn insert(&mut self, key: K, value: V) -> Option<V> {
        match self.root {
            None => {
                self.root = Some(box Node::new(key, value));
                None
            },
            Some(ref mut r) => r.insert(key, value)
        }
    }
}

impl<K: Ord, V> Node<K, V> {
    pub fn new(key: K, value: V) -> Node<K, V> {
        Node { key: key, value: value, left: None, right: None, level: 1 }
    }

    fn max(&self) -> &K {
        match self.right {
            None => &self.key,
            Some(ref n) => n.max(),
        }
    }

    fn min(&self) -> &K {
        match self.left {
            None => &self.key,
            Some(ref n) => n.min(),
        }
    }

    pub fn is_bst(&self) -> bool {
        self.left.as_ref().map_or(true, |n| n.is_bst() && *n.max() < self.key)
        && self.right.as_ref().map_or(true, |n| n.is_bst() && *n.min() > self.key)
    }

    pub fn find<'a>(&'a self, key: &K) -> Option<&'a V> {
        let ch = match key.cmp(&self.key) {
            Equal => return Some(&self.value),
            Less => & self.left,
            Greater => & self.right,
        };

        match *ch {
            None => None,
            Some(ref b) => b.find(key),
        }
    }

    pub fn insert(&mut self, key: K, value: V) -> Option<V> {
        let inserted =
        {
            let ch = match key.cmp(&self.key) {
                Equal => {
                    self.key = key;
                    return Some(replace(&mut self.value, value))
                },
                Less => &mut self.left,
                Greater => &mut self.right,
            };

            match *ch {
                None => {
                    *ch = Some(box Node::new(key, value));
                    None
                },
                Some(ref mut b) => {
                    b.insert(key, value)
                },
            }
        };

        self.skew();
        self.split();
        inserted

    }

    // To be an AA tree, it must be a binary search tree and, for all nodes n:
    //   - if n is missing a child, its level must be 1
    //   - the left child must have a level one less than n's level
    //   - the right child must have a level equal to or one less than n's level
    //   - the right child's right child must not have the same level as n's level
    fn is_aa(&self) -> bool {
        let lvl = self.level;

        self.is_bst()
            && !((self.left.is_none() || self.right.is_none()) && self.level != 1)
            && self.left.as_ref().map_or(true, |n| n.is_aa())
            && self.no_red_left_child()
            && self.right.as_ref().map_or(true,
                |n| n.is_aa() && (n.level == lvl || n.level + 1 == lvl)
                    && !(n.level == lvl && !n.no_red_right_child()))
    }

    fn no_red_left_child(&self) -> bool {
        match self.left {
            None => true,
            Some(ref n) => n.level + 1 == self.level,
        }
    }

    fn no_red_right_child(&self) -> bool {
        match self.right {
            None => true,
            Some(ref n) => n.level + 1 == self.level,
        }
    }

    // Remove red left child by rotating right
    /*
         a      b
        /        \
       b    =>    a
        \        /
         c      c

      provided that a.level == b.level
    */
    fn skew(&mut self) {
        if self.left.is_some() && self.left.get_ref().level == self.level {
            let mut save = self.left.take_unwrap();
            swap(&mut self.left, &mut save.right); // save.right now None
            swap(self, &mut *save);
            self.right = Some(save);
        }
    }

    // Remove red right child of red right child by rotating left and increasing
    // level of the parent
    /*
        a            b
         \          / \
          b    =>  a   c
         / \        \
        d   c        d

      provided that a.level == c.level
    */
    fn split(&mut self) {
        if self.right.as_ref().map_or(false,
          |x| x.right.is_some() && x.right.get_ref().level == self.level) {
            let mut save = self.right.take_unwrap();
            swap(&mut self.right, &mut save.left); // save.left now None
            save.level += 1;
            swap(self, &mut *save);
            self.left = Some(save);
        }
    }

    /*

       In the below, 'o' represents black, '*' represents red.

       First, note that deleting a red leaf requires no rebalancing at all.

       ---

       There's only 1 possible AA tree of size 2:

       o
        \
         *

       Deleting the root or the leaf requires no rebalancing.

       ---

       For size 3 trees, we only have:

         o
        / \
       o   o

        - deleting left leaf means we have to decrease the level of root. this suffices to rebalance
        - deleting right leaf means we have to decrease level of root but then make left leaf the
          new root (and former root the child of new root)
        - deleting the root means right child is new root, left child becomes new root's right child

       ---

       For size 4 trees, we have either

         o       o
        / \     / \
       o   o   o   o
        \           \
         *           *

       There are 4 classes of deletion:

        - delete red leaf (see above)
        - delete red node's parent: make red a child of its former grandparent
        - delete root: in the first case, red needs to become root, so increase its level and make it
          the new root. in the second case, right child of root needs to become new root.
        - delete other child: in the first case, red needs to become root and the old root needs to
          be right child of new root. in the second case, decrease level of old root, increase level
          of right child and make old root the child of the right child (which is the new root)

       ---

       For size 5 trees, we have one of

         o        o
        / \      / \
       o   o    o   *
        \   \      / \
         *   *    o   o

       ===

       One fundamental operation we need is "promote the max from the left subtree (or min from right subtree!)
       this is used when we delete a root, for example. this seems essentially whenever we delete a node that
       has two children.

     */
}

impl<K: Show, V: Show> Show for Node<K, V> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}:{}", self.key, self.value)
    }
}

fn print_node_depth<K: Show, V: Show>(node: &Link<Node<K,V>>, depth: uint) {
    let mut pre = "".to_string();
    if depth > 0 {
        for i in range(0, depth) {
            pre = pre + "   ";
        }
    }

    match *node {
        Some(ref n) => {
            println!("{}{}^{}", pre, n, n.level);
            print_node_depth(&n.left, depth + 1);
            print_node_depth(&n.right, depth + 1);
        },
        None => println!("{}-", pre),
    }
}

pub fn print_tree<K: Show + Ord, V: Show>(tree: &Tree<K, V>) {
    print_node_depth(&tree.root, 0);
    println!("Is AA: {}", tree.is_aa());
    println!("------------");
}

mod test {
    use super::Tree;
    use std::rand;
    use std::rand::distributions::{IndependentSample, Range};

    #[test]
    fn test_find() {
        let mut t = Tree::new();
        assert_eq!(t.find(&1u), None);
        t.insert(1u, 'j');
        assert_eq!(t.find(&1u), Some(&'j'));

    }

    // testing whether we can find all the things we inserted
    #[test]
    fn test_insert() {
        let mut t: Tree<uint, u8> = Tree::new();
        for (i, c) in range(0u, 10).zip(range(b'a', b'z')) {
            t.insert(i, c);
        }

        for (ref i, ref c) in range(0u, 10).zip(range(b'a', b'z')) {
            assert_eq!(t.find(i), Some(c));
        }

        assert_eq!(t.find(&10u), None);
    }

    fn insert_n_check_aa(n: uint, between: Range<uint>, rng: &mut rand::TaskRng) {
        let mut t = Tree::new();

        for _ in range(0u, n) {
            let a = between.ind_sample(rng);
            println!("{}", a);
            t.insert(a, ());
        }

        assert!(t.is_aa());
    }

    // testing whether, after inserting 20 random keys, is_aa() returns true
    #[test]
    fn test_insert_is_aa() {
        let mut rng = rand::task_rng();
        let between = Range::new(0u, 100_000);

        for _ in range(0u, 300) {
            insert_n_check_aa(20, between, &mut rng);
        }
    }

    // testing whether, after inserting 20 random keys, is_aa() returns true,
    // but this time some of the keys are repeated
    #[test]
    fn test_insert_dups_is_aa() {
        let mut rng = rand::task_rng();
        let between = Range::new(0u, 15);

        for _ in range(0u, 300) {
            insert_n_check_aa(20, between, &mut rng);
        }
    }
}
<commit_msg>Make variable names in insert more gooder<commit_after>#![crate_name = "toy_aa"]
#![crate_type = "dylib"]

use std::fmt::{mod, Show};
use std::mem::{replace, swap};

type Link<T> = Option<Box<T>>;

struct Node<K, V> {
    key: K,
    value: V,
    left: Link<Node<K, V>>,
    right: Link<Node<K, V>>,
    level: uint
}

pub struct Tree<K, V> {
    root: Link<Node<K, V>>,
}

impl<K: Ord, V> Tree<K, V> {
    pub fn new() -> Tree<K, V> {
        Tree { root: None }
    }

    fn is_bst(&self) -> bool {
        match self.root {
            None => true,
            Some(ref r) => r.is_bst()
        }
    }

    fn is_aa(&self) -> bool {
        match self.root {
            None => true,
            Some(ref r) => r.is_aa()
        }
    }

    pub fn find<'a>(&'a self, key: &K) -> Option<&'a V> {
        match self.root {
            None => None,
            Some(ref r) => r.find(key)
        }
    }

    pub fn insert(&mut self, key: K, value: V) -> Option<V> {
        match self.root {
            None => {
                self.root = Some(box Node::new(key, value));
                None
            },
            Some(ref mut r) => r.insert(key, value)
        }
    }
}

impl<K: Ord, V> Node<K, V> {
    pub fn new(key: K, value: V) -> Node<K, V> {
        Node { key: key, value: value, left: None, right: None, level: 1 }
    }

    fn max(&self) -> &K {
        match self.right {
            None => &self.key,
            Some(ref n) => n.max(),
        }
    }

    fn min(&self) -> &K {
        match self.left {
            None => &self.key,
            Some(ref n) => n.min(),
        }
    }

    pub fn is_bst(&self) -> bool {
        self.left.as_ref().map_or(true, |n| n.is_bst() && *n.max() < self.key)
        && self.right.as_ref().map_or(true, |n| n.is_bst() && *n.min() > self.key)
    }

    pub fn find<'a>(&'a self, key: &K) -> Option<&'a V> {
        let ch = match key.cmp(&self.key) {
            Equal => return Some(&self.value),
            Less => & self.left,
            Greater => & self.right,
        };

        match *ch {
            None => None,
            Some(ref b) => b.find(key),
        }
    }

    pub fn insert(&mut self, key: K, value: V) -> Option<V> {
        let replaced =
        {
            let link = match key.cmp(&self.key) {
                Equal => {
                    self.key = key;
                    return Some(replace(&mut self.value, value))
                },
                Less => &mut self.left,
                Greater => &mut self.right,
            };

            match *link {
                None => {
                    *link = Some(box Node::new(key, value));
                    None
                },
                Some(ref mut b) => {
                    b.insert(key, value)
                },
            }
        };

        self.skew();
        self.split();
        replaced

    }

    // To be an AA tree, it must be a binary search tree and, for all nodes n:
    //   - if n is missing a child, its level must be 1
    //   - the left child must have a level one less than n's level
    //   - the right child must have a level equal to or one less than n's level
    //   - the right child's right child must not have the same level as n's level
    fn is_aa(&self) -> bool {
        let lvl = self.level;

        self.is_bst()
            && !((self.left.is_none() || self.right.is_none()) && self.level != 1)
            && self.left.as_ref().map_or(true, |n| n.is_aa())
            && self.no_red_left_child()
            && self.right.as_ref().map_or(true,
                |n| n.is_aa() && (n.level == lvl || n.level + 1 == lvl)
                    && !(n.level == lvl && !n.no_red_right_child()))
    }

    fn no_red_left_child(&self) -> bool {
        match self.left {
            None => true,
            Some(ref n) => n.level + 1 == self.level,
        }
    }

    fn no_red_right_child(&self) -> bool {
        match self.right {
            None => true,
            Some(ref n) => n.level + 1 == self.level,
        }
    }

    // Remove red left child by rotating right
    /*
         a      b
        /        \
       b    =>    a
        \        /
         c      c

      provided that a.level == b.level
    */
    fn skew(&mut self) {
        if self.left.is_some() && self.left.get_ref().level == self.level {
            let mut save = self.left.take_unwrap();
            swap(&mut self.left, &mut save.right); // save.right now None
            swap(self, &mut *save);
            self.right = Some(save);
        }
    }

    // Remove red right child of red right child by rotating left and increasing
    // level of the parent
    /*
        a            b
         \          / \
          b    =>  a   c
         / \        \
        d   c        d

      provided that a.level == c.level
    */
    fn split(&mut self) {
        if self.right.as_ref().map_or(false,
          |x| x.right.is_some() && x.right.get_ref().level == self.level) {
            let mut save = self.right.take_unwrap();
            swap(&mut self.right, &mut save.left); // save.left now None
            save.level += 1;
            swap(self, &mut *save);
            self.left = Some(save);
        }
    }

    /*

       In the below, 'o' represents black, '*' represents red.

       First, note that deleting a red leaf requires no rebalancing at all.

       ---

       There's only 1 possible AA tree of size 2:

       o
        \
         *

       Deleting the root or the leaf requires no rebalancing.

       ---

       For size 3 trees, we only have:

         o
        / \
       o   o

        - deleting left leaf means we have to decrease the level of root. this suffices to rebalance
        - deleting right leaf means we have to decrease level of root but then make left leaf the
          new root (and former root the child of new root)
        - deleting the root means right child is new root, left child becomes new root's right child

       ---

       For size 4 trees, we have either

         o       o
        / \     / \
       o   o   o   o
        \           \
         *           *

       There are 4 classes of deletion:

        - delete red leaf (see above)
        - delete red node's parent: make red a child of its former grandparent
        - delete root: in the first case, red needs to become root, so increase its level and make it
          the new root. in the second case, right child of root needs to become new root.
        - delete other child: in the first case, red needs to become root and the old root needs to
          be right child of new root. in the second case, decrease level of old root, increase level
          of right child and make old root the child of the right child (which is the new root)

       ---

       For size 5 trees, we have one of

         o        o
        / \      / \
       o   o    o   *
        \   \      / \
         *   *    o   o

       ===

       One fundamental operation we need is "promote the max from the left subtree (or min from right subtree!)
       this is used when we delete a root, for example. this seems essentially whenever we delete a node that
       has two children.

     */
}

impl<K: Show, V: Show> Show for Node<K, V> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}:{}", self.key, self.value)
    }
}

fn print_node_depth<K: Show, V: Show>(node: &Link<Node<K,V>>, depth: uint) {
    let mut pre = "".to_string();
    if depth > 0 {
        for i in range(0, depth) {
            pre = pre + "   ";
        }
    }

    match *node {
        Some(ref n) => {
            println!("{}{}^{}", pre, n, n.level);
            print_node_depth(&n.left, depth + 1);
            print_node_depth(&n.right, depth + 1);
        },
        None => println!("{}-", pre),
    }
}

pub fn print_tree<K: Show + Ord, V: Show>(tree: &Tree<K, V>) {
    print_node_depth(&tree.root, 0);
    println!("Is AA: {}", tree.is_aa());
    println!("------------");
}

mod test {
    use super::Tree;
    use std::rand;
    use std::rand::distributions::{IndependentSample, Range};

    #[test]
    fn test_find() {
        let mut t = Tree::new();
        assert_eq!(t.find(&1u), None);
        t.insert(1u, 'j');
        assert_eq!(t.find(&1u), Some(&'j'));

    }

    // testing whether we can find all the things we inserted
    #[test]
    fn test_insert() {
        let mut t: Tree<uint, u8> = Tree::new();
        for (i, c) in range(0u, 10).zip(range(b'a', b'z')) {
            t.insert(i, c);
        }

        for (ref i, ref c) in range(0u, 10).zip(range(b'a', b'z')) {
            assert_eq!(t.find(i), Some(c));
        }

        assert_eq!(t.find(&10u), None);
    }

    fn insert_n_check_aa(n: uint, between: Range<uint>, rng: &mut rand::TaskRng) {
        let mut t = Tree::new();

        for _ in range(0u, n) {
            let a = between.ind_sample(rng);
            println!("{}", a);
            t.insert(a, ());
        }

        assert!(t.is_aa());
    }

    // testing whether, after inserting 20 random keys, is_aa() returns true
    #[test]
    fn test_insert_is_aa() {
        let mut rng = rand::task_rng();
        let between = Range::new(0u, 100_000);

        for _ in range(0u, 300) {
            insert_n_check_aa(20, between, &mut rng);
        }
    }

    // testing whether, after inserting 20 random keys, is_aa() returns true,
    // but this time some of the keys are repeated
    #[test]
    fn test_insert_dups_is_aa() {
        let mut rng = rand::task_rng();
        let between = Range::new(0u, 15);

        for _ in range(0u, 300) {
            insert_n_check_aa(20, between, &mut rng);
        }
    }
}
<|endoftext|>


<commit_before>//! Trait solving using Chalk.

use std::env::var;

use chalk_ir::GoalData;
use chalk_recursive::Cache;
use chalk_solve::{logging_db::LoggingRustIrDatabase, Solver};

use base_db::CrateId;
use hir_def::{lang_item::LangItemTarget, TraitId};
use stdx::panic_context;
use syntax::SmolStr;

use crate::{
    db::HirDatabase, AliasEq, AliasTy, Canonical, DomainGoal, Goal, Guidance, InEnvironment,
    Interner, Solution, TraitRefExt, Ty, TyKind, WhereClause,
};

/// This controls how much 'time' we give the Chalk solver before giving up.
const CHALK_SOLVER_FUEL: i32 = 100;

#[derive(Debug, Copy, Clone)]
pub(crate) struct ChalkContext<'a> {
    pub(crate) db: &'a dyn HirDatabase,
    pub(crate) krate: CrateId,
}

fn create_chalk_solver() -> chalk_recursive::RecursiveSolver<Interner> {
    let overflow_depth =
        var("CHALK_OVERFLOW_DEPTH").ok().and_then(|s| s.parse().ok()).unwrap_or(300);
    let max_size = var("CHALK_SOLVER_MAX_SIZE").ok().and_then(|s| s.parse().ok()).unwrap_or(150);
    chalk_recursive::RecursiveSolver::new(overflow_depth, max_size, Some(Cache::new()))
}

/// A set of clauses that we assume to be true. E.g. if we are inside this function:
/// ```rust
/// fn foo<T: Default>(t: T) {}
/// ```
/// we assume that `T: Default`.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct TraitEnvironment {
    pub krate: CrateId,
    // FIXME make this a BTreeMap
    pub(crate) traits_from_clauses: Vec<(Ty, TraitId)>,
    pub env: chalk_ir::Environment<Interner>,
}

impl TraitEnvironment {
    pub fn empty(krate: CrateId) -> Self {
        TraitEnvironment {
            krate,
            traits_from_clauses: Vec::new(),
            env: chalk_ir::Environment::new(Interner),
        }
    }

    pub fn traits_in_scope_from_clauses<'a>(
        &'a self,
        ty: Ty,
    ) -> impl Iterator<Item = TraitId> + 'a {
        self.traits_from_clauses
            .iter()
            .filter_map(move |(self_ty, trait_id)| (*self_ty == ty).then(|| *trait_id))
    }
}

/// Solve a trait goal using Chalk.
pub(crate) fn trait_solve_query(
    db: &dyn HirDatabase,
    krate: CrateId,
    goal: Canonical<InEnvironment<Goal>>,
) -> Option<Solution> {
    let _p = profile::span("trait_solve_query").detail(|| match &goal.value.goal.data(Interner) {
        GoalData::DomainGoal(DomainGoal::Holds(WhereClause::Implemented(it))) => {
            db.trait_data(it.hir_trait_id()).name.to_string()
        }
        GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(_))) => "alias_eq".to_string(),
        _ => "??".to_string(),
    });
    tracing::info!("trait_solve_query({:?})", goal.value.goal);

    if let GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(AliasEq {
        alias: AliasTy::Projection(projection_ty),
        ..
    }))) = &goal.value.goal.data(Interner)
    {
        if let TyKind::BoundVar(_) = projection_ty.self_type_parameter(Interner).kind(Interner) {
            // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible
            return Some(Solution::Ambig(Guidance::Unknown));
        }
    }

    // We currently don't deal with universes (I think / hope they're not yet
    // relevant for our use cases?)
    let u_canonical = chalk_ir::UCanonical { canonical: goal, universes: 1 };
    solve(db, krate, &u_canonical)
}

fn solve(
    db: &dyn HirDatabase,
    krate: CrateId,
    goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal<Interner>>>,
) -> Option<chalk_solve::Solution<Interner>> {
    let context = ChalkContext { db, krate };
    tracing::debug!("solve goal: {:?}", goal);
    let mut solver = create_chalk_solver();

    let fuel = std::cell::Cell::new(CHALK_SOLVER_FUEL);

    let should_continue = || {
        db.unwind_if_cancelled();
        let remaining = fuel.get();
        fuel.set(remaining - 1);
        if remaining == 0 {
            tracing::debug!("fuel exhausted");
        }
        remaining > 0
    };

    let mut solve = || {
        let _ctx = if is_chalk_debug() || is_chalk_print() {
            Some(panic_context::enter(format!("solving {:?}", goal)))
        } else {
            None
        };
        let solution = if is_chalk_print() {
            let logging_db =
                LoggingRustIrDatabaseLoggingOnDrop(LoggingRustIrDatabase::new(context));
            solver.solve_limited(&logging_db.0, goal, &should_continue)
        } else {
            solver.solve_limited(&context, goal, &should_continue)
        };

        tracing::debug!("solve({:?}) => {:?}", goal, solution);

        solution
    };

    // don't set the TLS for Chalk unless Chalk debugging is active, to make
    // extra sure we only use it for debugging
    if is_chalk_debug() {
        crate::tls::set_current_program(db, solve)
    } else {
        solve()
    }
}

struct LoggingRustIrDatabaseLoggingOnDrop<'a>(LoggingRustIrDatabase<Interner, ChalkContext<'a>>);

impl<'a> Drop for LoggingRustIrDatabaseLoggingOnDrop<'a> {
    fn drop(&mut self) {
        eprintln!("chalk program:\n{}", self.0);
    }
}

fn is_chalk_debug() -> bool {
    std::env::var("CHALK_DEBUG").is_ok()
}

fn is_chalk_print() -> bool {
    std::env::var("CHALK_PRINT").is_ok()
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum FnTrait {
    FnOnce,
    FnMut,
    Fn,
}

impl FnTrait {
    const fn lang_item_name(self) -> &'static str {
        match self {
            FnTrait::FnOnce => "fn_once",
            FnTrait::FnMut => "fn_mut",
            FnTrait::Fn => "fn",
        }
    }

    pub fn get_id(&self, db: &dyn HirDatabase, krate: CrateId) -> Option<TraitId> {
        let target = db.lang_item(krate, SmolStr::new_inline(self.lang_item_name()))?;
        match target {
            LangItemTarget::TraitId(t) => Some(t),
            _ => None,
        }
    }
}
<commit_msg>Auto merge of #12281 - lnicola:increase-overflow-depth, r=lnicola<commit_after>//! Trait solving using Chalk.

use std::env::var;

use chalk_ir::GoalData;
use chalk_recursive::Cache;
use chalk_solve::{logging_db::LoggingRustIrDatabase, Solver};

use base_db::CrateId;
use hir_def::{lang_item::LangItemTarget, TraitId};
use stdx::panic_context;
use syntax::SmolStr;

use crate::{
    db::HirDatabase, AliasEq, AliasTy, Canonical, DomainGoal, Goal, Guidance, InEnvironment,
    Interner, Solution, TraitRefExt, Ty, TyKind, WhereClause,
};

/// This controls how much 'time' we give the Chalk solver before giving up.
const CHALK_SOLVER_FUEL: i32 = 100;

#[derive(Debug, Copy, Clone)]
pub(crate) struct ChalkContext<'a> {
    pub(crate) db: &'a dyn HirDatabase,
    pub(crate) krate: CrateId,
}

fn create_chalk_solver() -> chalk_recursive::RecursiveSolver<Interner> {
    let overflow_depth =
        var("CHALK_OVERFLOW_DEPTH").ok().and_then(|s| s.parse().ok()).unwrap_or(500);
    let max_size = var("CHALK_SOLVER_MAX_SIZE").ok().and_then(|s| s.parse().ok()).unwrap_or(150);
    chalk_recursive::RecursiveSolver::new(overflow_depth, max_size, Some(Cache::new()))
}

/// A set of clauses that we assume to be true. E.g. if we are inside this function:
/// ```rust
/// fn foo<T: Default>(t: T) {}
/// ```
/// we assume that `T: Default`.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct TraitEnvironment {
    pub krate: CrateId,
    // FIXME make this a BTreeMap
    pub(crate) traits_from_clauses: Vec<(Ty, TraitId)>,
    pub env: chalk_ir::Environment<Interner>,
}

impl TraitEnvironment {
    pub fn empty(krate: CrateId) -> Self {
        TraitEnvironment {
            krate,
            traits_from_clauses: Vec::new(),
            env: chalk_ir::Environment::new(Interner),
        }
    }

    pub fn traits_in_scope_from_clauses<'a>(
        &'a self,
        ty: Ty,
    ) -> impl Iterator<Item = TraitId> + 'a {
        self.traits_from_clauses
            .iter()
            .filter_map(move |(self_ty, trait_id)| (*self_ty == ty).then(|| *trait_id))
    }
}

/// Solve a trait goal using Chalk.
pub(crate) fn trait_solve_query(
    db: &dyn HirDatabase,
    krate: CrateId,
    goal: Canonical<InEnvironment<Goal>>,
) -> Option<Solution> {
    let _p = profile::span("trait_solve_query").detail(|| match &goal.value.goal.data(Interner) {
        GoalData::DomainGoal(DomainGoal::Holds(WhereClause::Implemented(it))) => {
            db.trait_data(it.hir_trait_id()).name.to_string()
        }
        GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(_))) => "alias_eq".to_string(),
        _ => "??".to_string(),
    });
    tracing::info!("trait_solve_query({:?})", goal.value.goal);

    if let GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(AliasEq {
        alias: AliasTy::Projection(projection_ty),
        ..
    }))) = &goal.value.goal.data(Interner)
    {
        if let TyKind::BoundVar(_) = projection_ty.self_type_parameter(Interner).kind(Interner) {
            // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible
            return Some(Solution::Ambig(Guidance::Unknown));
        }
    }

    // We currently don't deal with universes (I think / hope they're not yet
    // relevant for our use cases?)
    let u_canonical = chalk_ir::UCanonical { canonical: goal, universes: 1 };
    solve(db, krate, &u_canonical)
}

fn solve(
    db: &dyn HirDatabase,
    krate: CrateId,
    goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal<Interner>>>,
) -> Option<chalk_solve::Solution<Interner>> {
    let context = ChalkContext { db, krate };
    tracing::debug!("solve goal: {:?}", goal);
    let mut solver = create_chalk_solver();

    let fuel = std::cell::Cell::new(CHALK_SOLVER_FUEL);

    let should_continue = || {
        db.unwind_if_cancelled();
        let remaining = fuel.get();
        fuel.set(remaining - 1);
        if remaining == 0 {
            tracing::debug!("fuel exhausted");
        }
        remaining > 0
    };

    let mut solve = || {
        let _ctx = if is_chalk_debug() || is_chalk_print() {
            Some(panic_context::enter(format!("solving {:?}", goal)))
        } else {
            None
        };
        let solution = if is_chalk_print() {
            let logging_db =
                LoggingRustIrDatabaseLoggingOnDrop(LoggingRustIrDatabase::new(context));
            solver.solve_limited(&logging_db.0, goal, &should_continue)
        } else {
            solver.solve_limited(&context, goal, &should_continue)
        };

        tracing::debug!("solve({:?}) => {:?}", goal, solution);

        solution
    };

    // don't set the TLS for Chalk unless Chalk debugging is active, to make
    // extra sure we only use it for debugging
    if is_chalk_debug() {
        crate::tls::set_current_program(db, solve)
    } else {
        solve()
    }
}

struct LoggingRustIrDatabaseLoggingOnDrop<'a>(LoggingRustIrDatabase<Interner, ChalkContext<'a>>);

impl<'a> Drop for LoggingRustIrDatabaseLoggingOnDrop<'a> {
    fn drop(&mut self) {
        eprintln!("chalk program:\n{}", self.0);
    }
}

fn is_chalk_debug() -> bool {
    std::env::var("CHALK_DEBUG").is_ok()
}

fn is_chalk_print() -> bool {
    std::env::var("CHALK_PRINT").is_ok()
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum FnTrait {
    FnOnce,
    FnMut,
    Fn,
}

impl FnTrait {
    const fn lang_item_name(self) -> &'static str {
        match self {
            FnTrait::FnOnce => "fn_once",
            FnTrait::FnMut => "fn_mut",
            FnTrait::Fn => "fn",
        }
    }

    pub fn get_id(&self, db: &dyn HirDatabase, krate: CrateId) -> Option<TraitId> {
        let target = db.lang_item(krate, SmolStr::new_inline(self.lang_item_name()))?;
        match target {
            LangItemTarget::TraitId(t) => Some(t),
            _ => None,
        }
    }
}
<|endoftext|>


<commit_before>//! Add a delta to a weave file.

use regex::Regex;
use std::{
    collections::BTreeMap,
    fs::{remove_file, rename},
    io::{self, BufRead, BufReader, BufWriter, Write},
    mem::replace,
    path::PathBuf,
    process::{Command, Stdio},
};

use crate::{header::Header, Error, NamingConvention, Parser, Result, Sink, WriterInfo};

/// A DeltaWriter is used to write a new delta.  Data should be written to the writer, and then the
/// `close` method called to update the weave file with the new delta.
pub struct DeltaWriter<'n> {
    naming: &'n dyn NamingConvention,

    // Where the temporary file will be written.
    temp: Option<WriterInfo>,

    // The base delta.
    base: usize,

    // The new delta.
    new_delta: usize,

    // The name of the file with the base written to it.
    base_name: PathBuf,

    // The regex for parsing diff output.
    diff_re: Regex,

    // The header to be written for the new delta.
    header: Header,
}

impl<'n> DeltaWriter<'n> {
    /// Construct a writer for a new delta.  The naming convention and the tags set where the names
    /// will be written, and what tags will be associated with the convention.  The `base` is the
    /// existing delta that the change should be based on.
    pub fn new<'a, 'b, I>(nc: &dyn NamingConvention, tags: I, base: usize) -> Result<DeltaWriter>
    where
        I: Iterator<Item = (&'a str, &'b str)>,
    {
        // Copy the tags, making sure there is a "name", which is used to index.
        // TODO: Ensure that "name" is unique among the existing deltas.
        let mut ntags = BTreeMap::new();
        for (k, v) in tags {
            ntags.insert(k.to_owned(), v.to_owned());
        }
        if !ntags.contains_key("name") {
            return Err(Error::NameMissing);
        }

        // Extract the base delta to a file.

        let (base_name, base_file) = nc.temp_file()?;
        let mut header = {
            let dsync = RevWriter {
                dest: BufWriter::new(base_file),
            };
            let mut parser = Parser::new(nc, dsync, base)?;
            match parser.parse_to(0) {
                Ok(0) => (),
                Ok(_) => panic!("Unexpected stop of parser"),
                Err(e) => return Err(e),
            }
            parser.into_header()
        };
        let new_delta = header.add(ntags)?;

        let (new_name, new_file) = nc.temp_file()?;
        let new_info = WriterInfo {
            name: new_name,
            writer: Box::new(BufWriter::new(new_file)),
        };

        Ok(DeltaWriter {
            naming: nc,
            temp: Some(new_info),
            base,
            new_delta,
            base_name,
            diff_re: Regex::new(r"^(\d+)(,(\d+))?([acd]).*$").unwrap(),
            header,
        })
    }

    pub fn close(mut self) -> Result<()> {
        // Close the temporary file, getting its name.
        let temp = replace(&mut self.temp, None);
        let temp_name = match temp {
            Some(mut wi) => {
                wi.writer.flush()?;
                drop(wi.writer);
                wi.name
            }
            None => return Err(Error::AlreadyClosed),
        };

        let tweave_info = self.naming.new_temp()?;

        // Invoke diff on the files.
        let mut child = Command::new("diff")
            .arg(self.base_name.as_os_str())
            .arg(temp_name.as_os_str())
            .stdout(Stdio::piped())
            .spawn()?;

        {
            let lines = BufReader::new(child.stdout.as_mut().unwrap()).lines();
            let weave_write = WeaveWriter {
                dest: tweave_info.writer,
            };
            let mut parser = Parser::new(self.naming, weave_write, self.base)?;

            let weave_write = parser.get_sink();

            self.header.write(&mut weave_write.borrow_mut().dest)?;

            let mut is_done = false;
            let mut is_adding = false;

            for line in lines {
                let line = line?;
                if let Some(cap) = self.diff_re.captures(&line) {
                    // If adding, this completes the add.
                    if is_adding {
                        weave_write.borrow_mut().end(self.new_delta)?;
                        is_adding = false;
                    }

                    let left = cap.get(1).unwrap().as_str().parse::<usize>().unwrap();
                    let right = match cap.get(3) {
                        None => left,
                        Some(r) => r.as_str().parse().unwrap(),
                    };
                    let cmd = cap.get(4).unwrap().as_str().chars().next().unwrap();

                    if cmd == 'd' || cmd == 'c' {
                        // These include deletions.
                        match parser.parse_to(left)? {
                            0 => return Err(Error::UnexpectedEof),
                            n if n == left => (),
                            _ => panic!("Unexpected parse result"),
                        }
                        weave_write.borrow_mut().delete(self.new_delta)?;
                        match parser.parse_to(right + 1) {
                            Ok(0) => is_done = true,
                            Ok(n) if n == right + 1 => (),
                            Ok(_) => panic!("Unexpected parse result"),
                            Err(e) => return Err(e),
                        }
                        weave_write.borrow_mut().end(self.new_delta)?;
                    } else {
                        match parser.parse_to(right + 1) {
                            Ok(0) => is_done = true,
                            Ok(n) if n == right + 1 => (),
                            Ok(_) => panic!("Unexpected parse result"),
                            Err(e) => return Err(e),
                        }
                    }

                    if cmd == 'c' || cmd == 'a' {
                        weave_write.borrow_mut().insert(self.new_delta)?;
                        is_adding = true;
                    }

                    continue;
                }

                match line.chars().next() {
                    None => panic!("Unexpected blank line in diff"),
                    Some('<') => continue,
                    Some('-') => continue,
                    Some('>') => {
                        // Add lines should just be written as-is.
                        weave_write.borrow_mut().plain(&line[2..], true)?;
                    }
                    Some(_) => panic!("Unexpected diff line: {:?}", line),
                }
            }

            if is_adding {
                weave_write.borrow_mut().end(self.new_delta)?;
            }

            if !is_done {
                match parser.parse_to(0) {
                    Ok(0) => (),
                    Ok(_) => panic!("Unexpected non-eof"),
                    Err(e) => return Err(e),
                }
            }
        }

        match child.wait()?.code() {
            None => return Err(Error::DiffKilled),
            Some(0) => (), // No diffs
            Some(1) => (), // Normal with diffs
            Some(n) => return Err(Error::DiffError(n)),
        }

        // Now that is all done, clean up the temp files, and cycle the backup.
        let _ = rename(self.naming.main_file(), self.naming.backup_file());
        rename(tweave_info.name, self.naming.main_file())?;
        remove_file(&self.base_name)?;
        remove_file(&temp_name)?;

        Ok(())
    }
}

impl<'n> Write for DeltaWriter<'n> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.temp
            .as_mut()
            .expect("Attempt to write to DeltaWriter that is closed")
            .writer
            .write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.temp
            .as_mut()
            .expect("Attempt to flush DeltaWriter that is closed")
            .writer
            .flush()
    }
}

struct RevWriter<W: Write> {
    dest: BufWriter<W>,
}

impl<W: Write> Sink for RevWriter<W> {
    fn plain(&mut self, text: &str, keep: bool) -> Result<()> {
        if !keep {
            return Ok(());
        }

        writeln!(&mut self.dest, "{}", text)?;
        Ok(())
    }
}

/// The weave writer writes out the contents of a weave to a file.
struct WeaveWriter<W: Write> {
    dest: W,
}

impl<W: Write> Sink for WeaveWriter<W> {
    fn insert(&mut self, delta: usize) -> Result<()> {
        writeln!(&mut self.dest, "\x01I {}", delta)?;
        Ok(())
    }
    fn delete(&mut self, delta: usize) -> Result<()> {
        writeln!(&mut self.dest, "\x01D {}", delta)?;
        Ok(())
    }
    fn end(&mut self, delta: usize) -> Result<()> {
        writeln!(&mut self.dest, "\x01E {}", delta)?;
        Ok(())
    }
    fn plain(&mut self, text: &str, _keep: bool) -> Result<()> {
        writeln!(&mut self.dest, "{}", text)?;
        Ok(())
    }
}
<commit_msg>weave: Convert one push to pull parser<commit_after>//! Add a delta to a weave file.

use regex::Regex;
use std::{
    collections::BTreeMap,
    fs::{remove_file, rename},
    io::{self, BufRead, BufReader, BufWriter, Write},
    mem::replace,
    path::PathBuf,
    process::{Command, Stdio},
};

use crate::{header::Header, Entry, Error, NamingConvention, Parser, PullParser, Result, Sink, WriterInfo};

/// A DeltaWriter is used to write a new delta.  Data should be written to the writer, and then the
/// `close` method called to update the weave file with the new delta.
pub struct DeltaWriter<'n> {
    naming: &'n dyn NamingConvention,

    // Where the temporary file will be written.
    temp: Option<WriterInfo>,

    // The base delta.
    base: usize,

    // The new delta.
    new_delta: usize,

    // The name of the file with the base written to it.
    base_name: PathBuf,

    // The regex for parsing diff output.
    diff_re: Regex,

    // The header to be written for the new delta.
    header: Header,
}

impl<'n> DeltaWriter<'n> {
    /// Construct a writer for a new delta.  The naming convention and the tags set where the names
    /// will be written, and what tags will be associated with the convention.  The `base` is the
    /// existing delta that the change should be based on.
    pub fn new<'a, 'b, I>(nc: &dyn NamingConvention, tags: I, base: usize) -> Result<DeltaWriter>
    where
        I: Iterator<Item = (&'a str, &'b str)>,
    {
        // Copy the tags, making sure there is a "name", which is used to index.
        // TODO: Ensure that "name" is unique among the existing deltas.
        let mut ntags = BTreeMap::new();
        for (k, v) in tags {
            ntags.insert(k.to_owned(), v.to_owned());
        }
        if !ntags.contains_key("name") {
            return Err(Error::NameMissing);
        }

        // Extract the base delta to a file.

        let (base_name, mut base_file) = nc.temp_file()?;
        let mut header = {
            let mut parser = PullParser::new(nc, base)?;
            for node in &mut parser {
                match node? {
                    Entry::Plain { text, keep } => {
                        if keep {
                            writeln!(base_file, "{}", text)?;
                        }
                    }
                    _ => (),
                }
            }
            parser.into_header()
        };
        let new_delta = header.add(ntags)?;

        let (new_name, new_file) = nc.temp_file()?;
        let new_info = WriterInfo {
            name: new_name,
            writer: Box::new(BufWriter::new(new_file)),
        };

        Ok(DeltaWriter {
            naming: nc,
            temp: Some(new_info),
            base,
            new_delta,
            base_name,
            diff_re: Regex::new(r"^(\d+)(,(\d+))?([acd]).*$").unwrap(),
            header,
        })
    }

    pub fn close(mut self) -> Result<()> {
        // Close the temporary file, getting its name.
        let temp = replace(&mut self.temp, None);
        let temp_name = match temp {
            Some(mut wi) => {
                wi.writer.flush()?;
                drop(wi.writer);
                wi.name
            }
            None => return Err(Error::AlreadyClosed),
        };

        let tweave_info = self.naming.new_temp()?;

        // Invoke diff on the files.
        let mut child = Command::new("diff")
            .arg(self.base_name.as_os_str())
            .arg(temp_name.as_os_str())
            .stdout(Stdio::piped())
            .spawn()?;

        {
            let lines = BufReader::new(child.stdout.as_mut().unwrap()).lines();
            let weave_write = WeaveWriter {
                dest: tweave_info.writer,
            };
            let mut parser = Parser::new(self.naming, weave_write, self.base)?;

            let weave_write = parser.get_sink();

            self.header.write(&mut weave_write.borrow_mut().dest)?;

            let mut is_done = false;
            let mut is_adding = false;

            for line in lines {
                let line = line?;
                if let Some(cap) = self.diff_re.captures(&line) {
                    // If adding, this completes the add.
                    if is_adding {
                        weave_write.borrow_mut().end(self.new_delta)?;
                        is_adding = false;
                    }

                    let left = cap.get(1).unwrap().as_str().parse::<usize>().unwrap();
                    let right = match cap.get(3) {
                        None => left,
                        Some(r) => r.as_str().parse().unwrap(),
                    };
                    let cmd = cap.get(4).unwrap().as_str().chars().next().unwrap();

                    if cmd == 'd' || cmd == 'c' {
                        // These include deletions.
                        match parser.parse_to(left)? {
                            0 => return Err(Error::UnexpectedEof),
                            n if n == left => (),
                            _ => panic!("Unexpected parse result"),
                        }
                        weave_write.borrow_mut().delete(self.new_delta)?;
                        match parser.parse_to(right + 1) {
                            Ok(0) => is_done = true,
                            Ok(n) if n == right + 1 => (),
                            Ok(_) => panic!("Unexpected parse result"),
                            Err(e) => return Err(e),
                        }
                        weave_write.borrow_mut().end(self.new_delta)?;
                    } else {
                        match parser.parse_to(right + 1) {
                            Ok(0) => is_done = true,
                            Ok(n) if n == right + 1 => (),
                            Ok(_) => panic!("Unexpected parse result"),
                            Err(e) => return Err(e),
                        }
                    }

                    if cmd == 'c' || cmd == 'a' {
                        weave_write.borrow_mut().insert(self.new_delta)?;
                        is_adding = true;
                    }

                    continue;
                }

                match line.chars().next() {
                    None => panic!("Unexpected blank line in diff"),
                    Some('<') => continue,
                    Some('-') => continue,
                    Some('>') => {
                        // Add lines should just be written as-is.
                        weave_write.borrow_mut().plain(&line[2..], true)?;
                    }
                    Some(_) => panic!("Unexpected diff line: {:?}", line),
                }
            }

            if is_adding {
                weave_write.borrow_mut().end(self.new_delta)?;
            }

            if !is_done {
                match parser.parse_to(0) {
                    Ok(0) => (),
                    Ok(_) => panic!("Unexpected non-eof"),
                    Err(e) => return Err(e),
                }
            }
        }

        match child.wait()?.code() {
            None => return Err(Error::DiffKilled),
            Some(0) => (), // No diffs
            Some(1) => (), // Normal with diffs
            Some(n) => return Err(Error::DiffError(n)),
        }

        // Now that is all done, clean up the temp files, and cycle the backup.
        let _ = rename(self.naming.main_file(), self.naming.backup_file());
        rename(tweave_info.name, self.naming.main_file())?;
        remove_file(&self.base_name)?;
        remove_file(&temp_name)?;

        Ok(())
    }
}

impl<'n> Write for DeltaWriter<'n> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.temp
            .as_mut()
            .expect("Attempt to write to DeltaWriter that is closed")
            .writer
            .write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.temp
            .as_mut()
            .expect("Attempt to flush DeltaWriter that is closed")
            .writer
            .flush()
    }
}

struct RevWriter<W: Write> {
    dest: BufWriter<W>,
}

impl<W: Write> Sink for RevWriter<W> {
    fn plain(&mut self, text: &str, keep: bool) -> Result<()> {
        if !keep {
            return Ok(());
        }

        writeln!(&mut self.dest, "{}", text)?;
        Ok(())
    }
}

/// The weave writer writes out the contents of a weave to a file.
struct WeaveWriter<W: Write> {
    dest: W,
}

impl<W: Write> Sink for WeaveWriter<W> {
    fn insert(&mut self, delta: usize) -> Result<()> {
        writeln!(&mut self.dest, "\x01I {}", delta)?;
        Ok(())
    }
    fn delete(&mut self, delta: usize) -> Result<()> {
        writeln!(&mut self.dest, "\x01D {}", delta)?;
        Ok(())
    }
    fn end(&mut self, delta: usize) -> Result<()> {
        writeln!(&mut self.dest, "\x01E {}", delta)?;
        Ok(())
    }
    fn plain(&mut self, text: &str, _keep: bool) -> Result<()> {
        writeln!(&mut self.dest, "{}", text)?;
        Ok(())
    }
}
<|endoftext|>


<commit_before>#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.25.0")]
#![allow(unknown_lints, bare_trait_objects)]
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
#![cfg_attr(
    feature = "cargo-clippy",
    allow(
        cognitive_complexity,
        redundant_field_names,
        result_unit_err,
        should_implement_trait,
        trivially_copy_pass_by_ref,
        wildcard_in_or_patterns,
        // clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704
        unnested_or_patterns,
    )
)]

#[macro_use]
extern crate syn;

extern crate proc_macro2;
extern crate quote;

#[path = "src/mod.rs"]
mod internals;

pub use internals::*;
<commit_msg>Update serde_derive_internals to tool attrs<commit_after>#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.25.0")]
#![allow(unknown_lints, bare_trait_objects)]
#![deny(clippy::all)]
#![allow(
    clippy::cognitive_complexity,
    clippy::redundant_field_names,
    clippy::result_unit_err,
    clippy::should_implement_trait,
    clippy::trivially_copy_pass_by_ref,
    clippy::wildcard_in_or_patterns,
    // clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704
    clippy::unnested_or_patterns,
)]

#[macro_use]
extern crate syn;

extern crate proc_macro2;
extern crate quote;

#[path = "src/mod.rs"]
mod internals;

pub use internals::*;
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fs::{File, remove_file};
use std::ops::Drop;
use std::path::PathBuf;
use std::result::Result as RResult;
use std::sync::Arc;
use std::sync::RwLock;

use fs2::FileExt;

use entry::Entry;
use error::{StoreError, StoreErrorKind};
use storeid::StoreId;

/// The Result Type returned by any interaction with the store that could fail
pub type Result<T> = RResult<T, StoreError>;

#[derive(PartialEq)]
enum StoreEntryPresence {
    Present,
    Borrowed
}

/// A store entry, depending on the option type it is either borrowed currently
/// or not.
struct StoreEntry {
    file: File,
    entry: StoreEntryPresence
}

impl StoreEntry {
    /// The entry is currently borrowed, meaning that some thread is currently
    /// mutating it
    fn is_borrowed(&self) -> bool {
        self.entry == StoreEntryPresence::Borrowed
    }
}

/// The Store itself, through this object one can interact with IMAG's entries
pub struct Store {
    location: PathBuf,

    /**
     * Internal Path->File cache map
     *
     * Caches the files, so they remain flock()ed
     *
     * Could be optimized for a threadsafe HashMap
     */
    entries: Arc<RwLock<HashMap<StoreId, StoreEntry>>>,
}

impl Store {

    /// Create a new Store object
    pub fn new(location: PathBuf) -> Store {
        Store {
            location: location,
            entries: Arc::new(RwLock::new(HashMap::new())),
        }
    }

    /// Creates the Entry at the given location (inside the entry)
    pub fn create(&self, entry: Entry) -> Result<()> {
        unimplemented!();
    }

    /// Borrow a given Entry. When the `FileLockEntry` is either `update`d or
    /// dropped, the new Entry is written to disk
    pub fn retrieve<'a>(&'a self, id: StoreId) -> Result<FileLockEntry<'a>> {
        unimplemented!();
    }

    /// Return the `FileLockEntry` and write to disk
    pub fn update<'a>(&'a self, entry: FileLockEntry<'a>) -> Result<()> {
        self._update(&entry)
    }

    /// Internal method to write to the filesystem store.
    ///
    /// # Assumptions
    /// This method assumes that entry is dropped _right after_ the call, hence
    /// it is not public.
    fn _update<'a>(&'a self, entry: &FileLockEntry<'a>) -> Result<()> {
        unimplemented!();
    }

    /// Retrieve a copy of a given entry, this cannot be used to mutate
    /// the one on disk
    pub fn retrieve_copy(&self, id: StoreId) -> Result<Entry> {
        unimplemented!();
    }

    /// Delete an entry
    pub fn delete(&self, id: StoreId) -> Result<()> {
        let mut entries_lock = self.entries.write();
        let mut entries = entries_lock.unwrap();

        // if the entry is currently modified by the user, we cannot drop it
        if entries.get(&id).map(|e| e.is_borrowed()).unwrap_or(false) {
            return Err(StoreError::new(StoreErrorKind::IdLocked, None));
        }

        // remove the entry first, then the file
        entries.remove(&id);
        remove_file(&id).map_err(|e| StoreError::new(StoreErrorKind::FileError, Some(Box::new(e))))
    }
}

impl Drop for Store {

    /**
     * Unlock all files on drop
     *
     * TODO: Error message when file cannot be unlocked?
     */
    fn drop(&mut self) {
        self.entries.write().unwrap()
            .iter().map(|f| f.1.file.unlock());
    }

}

/// A struct that allows you to borrow an Entry
pub struct FileLockEntry<'a> {
    store: &'a Store,
    entry: Entry,
    key: StoreId,
}

impl<'a> FileLockEntry<'a, > {
    fn new(store: &'a Store, entry: Entry, key: StoreId) -> FileLockEntry<'a> {
        FileLockEntry {
            store: store,
            entry: entry,
            key: key,
        }
    }
}

impl<'a> ::std::ops::Deref for FileLockEntry<'a> {
    type Target = Entry;

    fn deref(&self) -> &Self::Target {
        &self.entry
    }
}

impl<'a> ::std::ops::DerefMut for FileLockEntry<'a> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.entry
    }
}

impl<'a> Drop for FileLockEntry<'a> {
    fn drop(&mut self) {
        self.store._update(self).unwrap()
    }
}
<commit_msg>Store::new(): Create path if nonexistent<commit_after>use std::collections::HashMap;
use std::fs::{File, remove_file};
use std::ops::Drop;
use std::path::PathBuf;
use std::result::Result as RResult;
use std::sync::Arc;
use std::sync::RwLock;

use fs2::FileExt;

use entry::Entry;
use error::{StoreError, StoreErrorKind};
use storeid::StoreId;

/// The Result Type returned by any interaction with the store that could fail
pub type Result<T> = RResult<T, StoreError>;

#[derive(PartialEq)]
enum StoreEntryPresence {
    Present,
    Borrowed
}

/// A store entry, depending on the option type it is either borrowed currently
/// or not.
struct StoreEntry {
    file: File,
    entry: StoreEntryPresence
}

impl StoreEntry {
    /// The entry is currently borrowed, meaning that some thread is currently
    /// mutating it
    fn is_borrowed(&self) -> bool {
        self.entry == StoreEntryPresence::Borrowed
    }
}

/// The Store itself, through this object one can interact with IMAG's entries
pub struct Store {
    location: PathBuf,

    /**
     * Internal Path->File cache map
     *
     * Caches the files, so they remain flock()ed
     *
     * Could be optimized for a threadsafe HashMap
     */
    entries: Arc<RwLock<HashMap<StoreId, StoreEntry>>>,
}

impl Store {

    /// Create a new Store object
    pub fn new(location: PathBuf) -> Store {
        use std::fs::create_dir_all;

        if !location.exists() {
            create_dir_all(location.clone()).ok(); // TODO: Error handling?
        }

        // TODO: Path exists, but is a file? What now?

        Store {
            location: location,
            entries: Arc::new(RwLock::new(HashMap::new())),
        }
    }

    /// Creates the Entry at the given location (inside the entry)
    pub fn create(&self, entry: Entry) -> Result<()> {
        unimplemented!();
    }

    /// Borrow a given Entry. When the `FileLockEntry` is either `update`d or
    /// dropped, the new Entry is written to disk
    pub fn retrieve<'a>(&'a self, id: StoreId) -> Result<FileLockEntry<'a>> {
        unimplemented!();
    }

    /// Return the `FileLockEntry` and write to disk
    pub fn update<'a>(&'a self, entry: FileLockEntry<'a>) -> Result<()> {
        self._update(&entry)
    }

    /// Internal method to write to the filesystem store.
    ///
    /// # Assumptions
    /// This method assumes that entry is dropped _right after_ the call, hence
    /// it is not public.
    fn _update<'a>(&'a self, entry: &FileLockEntry<'a>) -> Result<()> {
        unimplemented!();
    }

    /// Retrieve a copy of a given entry, this cannot be used to mutate
    /// the one on disk
    pub fn retrieve_copy(&self, id: StoreId) -> Result<Entry> {
        unimplemented!();
    }

    /// Delete an entry
    pub fn delete(&self, id: StoreId) -> Result<()> {
        let mut entries_lock = self.entries.write();
        let mut entries = entries_lock.unwrap();

        // if the entry is currently modified by the user, we cannot drop it
        if entries.get(&id).map(|e| e.is_borrowed()).unwrap_or(false) {
            return Err(StoreError::new(StoreErrorKind::IdLocked, None));
        }

        // remove the entry first, then the file
        entries.remove(&id);
        remove_file(&id).map_err(|e| StoreError::new(StoreErrorKind::FileError, Some(Box::new(e))))
    }
}

impl Drop for Store {

    /**
     * Unlock all files on drop
     *
     * TODO: Error message when file cannot be unlocked?
     */
    fn drop(&mut self) {
        self.entries.write().unwrap()
            .iter().map(|f| f.1.file.unlock());
    }

}

/// A struct that allows you to borrow an Entry
pub struct FileLockEntry<'a> {
    store: &'a Store,
    entry: Entry,
    key: StoreId,
}

impl<'a> FileLockEntry<'a, > {
    fn new(store: &'a Store, entry: Entry, key: StoreId) -> FileLockEntry<'a> {
        FileLockEntry {
            store: store,
            entry: entry,
            key: key,
        }
    }
}

impl<'a> ::std::ops::Deref for FileLockEntry<'a> {
    type Target = Entry;

    fn deref(&self) -> &Self::Target {
        &self.entry
    }
}

impl<'a> ::std::ops::DerefMut for FileLockEntry<'a> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.entry
    }
}

impl<'a> Drop for FileLockEntry<'a> {
    fn drop(&mut self) {
        self.store._update(self).unwrap()
    }
}
<|endoftext|>