<commit_before>use super::*;
use serde_json;
use std;

#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, PartialOrd, Serialize)]
pub struct Number {
    pub value: f64,
}

impl std::fmt::Display for Number {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{}", self.value)
    }
}

impl Eq for Number {}
impl BindingsValue for Number {}

impl ConstraintValue for Number {
    fn float(f: f64) -> Self {
        Number { value: f }
    }

    fn to_float(&self) -> Option<f64> {
        Some(self.value)
    }
}

impl Number {
    pub fn new(f: f64) -> Self {
        Number { value: f }
    }
}

#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub enum NumericalConstraint {
    /// ?x = CONSTANT
    #[serde(rename = "set")]
    Set { variable: String, constant: f64 },
    /// ?x + ?y = ?z
    #[serde(rename = "sum")]
    Sum {
        first: String,
        second: String,
        third: String,
    },
    /// ?x * ?y = ?z
    #[serde(rename = "mul")]
    Mul {
        first: String,
        second: String,
        third: String,
    },
    /// ?x > ?y
    #[serde(rename = ">")]
    GreaterThan { left: String, right: String },
    /// ?x != ?y
    #[serde(rename = "neq")]
    NotEqual { left: String, right: String },
}

impl Eq for NumericalConstraint {}
impl Ord for NumericalConstraint {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.partial_cmp(other).unwrap_or(std::cmp::Ordering::Less)
    }
}
impl PartialOrd for NumericalConstraint {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        match (self, other) {
            (
                &NumericalConstraint::Set {
                    ref variable,
                    ref constant,
                    ..
                },
                &NumericalConstraint::Set {
                    variable: ref variable2,
                    constant: ref constant2,
                    ..
                },
            ) => match variable.partial_cmp(variable2) {
                Some(std::cmp::Ordering::Equal) => constant.partial_cmp(constant2),
                ordering => ordering,
            },
            (
                &NumericalConstraint::Sum {
                    ref first,
                    ref second,
                    ref third,
                    ..
                },
                &NumericalConstraint::Sum {
                    first: ref first2,
                    second: ref second2,
                    third: ref third2,
                    ..
                },
            ) => match first.partial_cmp(first2) {
                Some(std::cmp::Ordering::Equal) => match second.partial_cmp(second2) {
                    Some(std::cmp::Ordering::Equal) => third.partial_cmp(third2),
                    ordering => ordering,
                },
                ordering => ordering,
            },
            (
                &NumericalConstraint::Mul {
                    ref first,
                    ref second,
                    ref third,
                    ..
                },
                &NumericalConstraint::Mul {
                    first: ref first2,
                    second: ref second2,
                    third: ref third2,
                    ..
                },
            ) => match first.partial_cmp(first2) {
                Some(std::cmp::Ordering::Equal) => match second.partial_cmp(second2) {
                    Some(std::cmp::Ordering::Equal) => third.partial_cmp(third2),
                    ordering => ordering,
                },
                ordering => ordering,
            },
            (
                &NumericalConstraint::GreaterThan {
                    ref left,
                    ref right,
                    ..
                },
                &NumericalConstraint::GreaterThan {
                    left: ref left2,
                    right: ref right2,
                    ..
                },
            ) => match left.partial_cmp(left2) {
                Some(std::cmp::Ordering::Equal) => right.partial_cmp(right2),
                ordering => ordering,
            },
            (
                &NumericalConstraint::NotEqual {
                    ref left,
                    ref right,
                    ..
                },
                &NumericalConstraint::NotEqual {
                    left: ref left2,
                    right: ref right2,
                    ..
                },
            ) => match left.partial_cmp(left2) {
                Some(std::cmp::Ordering::Equal) => right.partial_cmp(right2),
                ordering => ordering,
            },
            (_, _) => None,
        }
    }
}

impl std::fmt::Display for NumericalConstraint {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{}", serde_json::to_string(&self).unwrap())
    }
}

impl NumericalConstraint {
    /// Try to solve this constraint using the information in the bindings
    pub fn solve<T: ConstraintValue>(&self, bindings: &Bindings<T>) -> SolveResult<T> {
        let apply_op = |x: &T, y: &T, op: &Fn(f64, f64) -> f64| -> Option<T> {
            x.to_float()
                .and_then(|x| y.to_float().and_then(|y| Some(T::float(op(x, y)))))
        };
        macro_rules! apply_op_or_return {
            ($x: ident, $y: ident, $z: ident, $op: expr) => ({
                if let Some(value) = apply_op($x, $y, &$op) {
                    ($z, value)
                } else {
                    return SolveResult::Conflict
                }
            })
        }
        let (key, value) = match *self {
            NumericalConstraint::Set {
                ref variable,
                ref constant,
                ..
            } => match bindings.get_binding(variable) {
                None => (variable, T::float(constant.clone())),
                Some(ref value) if value.to_float() == Some(*constant) => (variable, value.clone()),
                Some(_) => return SolveResult::Conflict,
            },
            NumericalConstraint::Sum {
                ref first,
                ref second,
                ref third,
                ..
            } => match (
                bindings.get_binding(first),
                bindings.get_binding(second),
                bindings.get_binding(third),
            ) {
                (Some(ref value), Some(ref value2), None) => apply_op_or_return!(value, value2, third, &Add::add),
                (Some(ref value), None, Some(ref value3)) => apply_op_or_return!(value3, value, second, &Sub::sub),
                (None, Some(ref value2), Some(ref value3)) => apply_op_or_return!(value3, value2, first, &Sub::sub),
                (Some(ref value), Some(ref value2), Some(ref value3)) => {
                    if Some(value) == apply_op(value3, value2, &Sub::sub).as_ref() {
                        return SolveResult::Partial(bindings.clone());
                    } else {
                        return SolveResult::Conflict;
                    }
                }
                _ => return SolveResult::Partial(bindings.clone()),
            },
            NumericalConstraint::Mul {
                ref first,
                ref second,
                ref third,
                ..
            } => match (
                bindings.get_binding(first),
                bindings.get_binding(second),
                bindings.get_binding(third),
            ) {
                (Some(ref value), Some(ref value2), None) => apply_op_or_return!(value, value2, third, &Mul::mul),
                (Some(ref value), None, Some(ref value3)) => apply_op_or_return!(value3, value, second, &Div::div),
                (None, Some(ref value2), Some(ref value3)) => apply_op_or_return!(value3, value2, first, &Div::div),
                (Some(ref value), Some(ref value2), Some(ref value3)) => {
                    if Some(value) == apply_op(value3, value2, &Div::div).as_ref() {
                        return SolveResult::Partial(bindings.clone());
                    } else {
                        return SolveResult::Conflict;
                    }
                }
                _ => return SolveResult::Partial(bindings.clone()),
            },
            NumericalConstraint::GreaterThan {
                ref left,
                ref right,
                ..
            } => match (bindings.get_binding(left), bindings.get_binding(right)) {
                (Some(ref left_value), Some(ref right_value)) if left_value > right_value => return SolveResult::Success(bindings.clone()),
                (Some(_), Some(_)) => return SolveResult::Conflict,
                _ => return SolveResult::Partial(bindings.clone()),
            },
            NumericalConstraint::NotEqual {
                ref left,
                ref right,
                ..
            } => match (bindings.get_binding(left), bindings.get_binding(right)) {
                (Some(ref left_value), Some(ref right_value)) if left_value != right_value => return SolveResult::Success(bindings.clone()),
                (Some(_), Some(_)) => return SolveResult::Conflict,
                _ => return SolveResult::Partial(bindings.clone()),
            },
        };
        SolveResult::Success(bindings.set_binding(key, value))
    }

    pub fn rename_variables(&self, renamed_variables: &HashMap<String, String>) -> Self {
        let lookup = |v: &String| -> String {
            renamed_variables
                .get(v)
                .cloned()
                .or_else(|| Some(v.clone()))
                .unwrap()
        };
        match *self {
            NumericalConstraint::Set {
                ref variable,
                ref constant,
                ..
            } => NumericalConstraint::Set {
                variable: lookup(variable),
                constant: constant.clone(),
            },
            NumericalConstraint::Sum {
                ref first,
                ref second,
                ref third,
                ..
            } => NumericalConstraint::Sum {
                first: lookup(first),
                second: lookup(second),
                third: lookup(third),
            },
            NumericalConstraint::Mul {
                ref first,
                ref second,
                ref third,
                ..
            } => NumericalConstraint::Mul {
                first: lookup(first),
                second: lookup(second),
                third: lookup(third),
            },
            NumericalConstraint::GreaterThan {
                ref left,
                ref right,
                ..
            } => NumericalConstraint::GreaterThan {
                left: lookup(left),
                right: lookup(right),
            },
            NumericalConstraint::NotEqual {
                ref left,
                ref right,
                ..
            } => NumericalConstraint::GreaterThan {
                left: lookup(left),
                right: lookup(right),
            },
        }
    }

    pub fn variables(&self) -> Vec<String> {
        match *self {
            NumericalConstraint::Set { ref variable, .. } => vec![variable.clone()],
            NumericalConstraint::Sum {
                ref first,
                ref second,
                ref third,
                ..
            } => vec![first.clone(), second.clone(), third.clone()],
            NumericalConstraint::Mul {
                ref first,
                ref second,
                ref third,
                ..
            } => vec![first.clone(), second.clone(), third.clone()],
            NumericalConstraint::GreaterThan {
                ref left,
                ref right,
                ..
            } => vec![left.clone(), right.clone()],
            NumericalConstraint::NotEqual {
                ref left,
                ref right,
                ..
            } => vec![left.clone(), right.clone()],
        }
    }
}
<commit_msg>Better ordering<commit_after>use super::*;
use serde_json;
use std;

#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, PartialOrd, Serialize)]
pub struct Number {
    pub value: f64,
}

impl std::fmt::Display for Number {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{}", self.value)
    }
}

impl Eq for Number {}
impl BindingsValue for Number {}

impl ConstraintValue for Number {
    fn float(f: f64) -> Self {
        Number { value: f }
    }

    fn to_float(&self) -> Option<f64> {
        Some(self.value)
    }
}

impl Number {
    pub fn new(f: f64) -> Self {
        Number { value: f }
    }
}

#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub enum NumericalConstraint {
    /// ?x = CONSTANT
    #[serde(rename = "set")]
    Set { variable: String, constant: f64 },
    /// ?x + ?y = ?z
    #[serde(rename = "sum")]
    Sum {
        first: String,
        second: String,
        third: String,
    },
    /// ?x * ?y = ?z
    #[serde(rename = "mul")]
    Mul {
        first: String,
        second: String,
        third: String,
    },
    /// ?x > ?y
    #[serde(rename = ">")]
    GreaterThan { left: String, right: String },
    /// ?x != ?y
    #[serde(rename = "neq")]
    NotEqual { left: String, right: String },
}

impl Eq for NumericalConstraint {}
impl Ord for NumericalConstraint {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.partial_cmp(other).unwrap_or(std::cmp::Ordering::Less)
    }
}
impl PartialOrd for NumericalConstraint {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        match (self, other) {
            (
                &NumericalConstraint::Set {
                    ref variable,
                    ref constant,
                    ..
                },
                &NumericalConstraint::Set {
                    variable: ref variable2,
                    constant: ref constant2,
                    ..
                },
            ) => match variable.partial_cmp(variable2) {
                Some(std::cmp::Ordering::Equal) => constant.partial_cmp(constant2),
                ordering => ordering,
            },
            (
                &NumericalConstraint::Sum {
                    ref first,
                    ref second,
                    ref third,
                    ..
                },
                &NumericalConstraint::Sum {
                    first: ref first2,
                    second: ref second2,
                    third: ref third2,
                    ..
                },
            ) => match first.partial_cmp(first2) {
                Some(std::cmp::Ordering::Equal) => match second.partial_cmp(second2) {
                    Some(std::cmp::Ordering::Equal) => third.partial_cmp(third2),
                    ordering => ordering,
                },
                ordering => ordering,
            },
            (
                &NumericalConstraint::Mul {
                    ref first,
                    ref second,
                    ref third,
                    ..
                },
                &NumericalConstraint::Mul {
                    first: ref first2,
                    second: ref second2,
                    third: ref third2,
                    ..
                },
            ) => match first.partial_cmp(first2) {
                Some(std::cmp::Ordering::Equal) => match second.partial_cmp(second2) {
                    Some(std::cmp::Ordering::Equal) => third.partial_cmp(third2),
                    ordering => ordering,
                },
                ordering => ordering,
            },
            (
                &NumericalConstraint::GreaterThan {
                    ref left,
                    ref right,
                    ..
                },
                &NumericalConstraint::GreaterThan {
                    left: ref left2,
                    right: ref right2,
                    ..
                },
            ) => match left.partial_cmp(left2) {
                Some(std::cmp::Ordering::Equal) => right.partial_cmp(right2),
                ordering => ordering,
            },
            (
                &NumericalConstraint::NotEqual {
                    ref left,
                    ref right,
                    ..
                },
                &NumericalConstraint::NotEqual {
                    left: ref left2,
                    right: ref right2,
                    ..
                },
            ) => match left.partial_cmp(left2) {
                Some(std::cmp::Ordering::Equal) => right.partial_cmp(right2),
                ordering => ordering,
            },
            (&NumericalConstraint::Set { .. }, &NumericalConstraint::Sum { .. }) => Some(std::cmp::Ordering::Less),
            (&NumericalConstraint::Set { .. }, &NumericalConstraint::Mul { .. }) => Some(std::cmp::Ordering::Less),
            (&NumericalConstraint::Set { .. }, &NumericalConstraint::GreaterThan { .. }) => Some(std::cmp::Ordering::Less),
            (&NumericalConstraint::Set { .. }, &NumericalConstraint::NotEqual { .. }) => Some(std::cmp::Ordering::Less),

            (&NumericalConstraint::Sum { .. }, &NumericalConstraint::Set { .. }) => Some(std::cmp::Ordering::Greater),
            (&NumericalConstraint::Sum { .. }, &NumericalConstraint::Mul { .. }) => Some(std::cmp::Ordering::Less),
            (&NumericalConstraint::Sum { .. }, &NumericalConstraint::GreaterThan { .. }) => Some(std::cmp::Ordering::Less),
            (&NumericalConstraint::Sum { .. }, &NumericalConstraint::NotEqual { .. }) => Some(std::cmp::Ordering::Less),

            (&NumericalConstraint::Mul { .. }, &NumericalConstraint::Set { .. }) => Some(std::cmp::Ordering::Greater),
            (&NumericalConstraint::Mul { .. }, &NumericalConstraint::Sum { .. }) => Some(std::cmp::Ordering::Greater),
            (&NumericalConstraint::Mul { .. }, &NumericalConstraint::GreaterThan { .. }) => Some(std::cmp::Ordering::Less),
            (&NumericalConstraint::Mul { .. }, &NumericalConstraint::NotEqual { .. }) => Some(std::cmp::Ordering::Less),

            (&NumericalConstraint::GreaterThan { .. }, &NumericalConstraint::Set { .. }) => Some(std::cmp::Ordering::Greater),
            (&NumericalConstraint::GreaterThan { .. }, &NumericalConstraint::Sum { .. }) => Some(std::cmp::Ordering::Greater),
            (&NumericalConstraint::GreaterThan { .. }, &NumericalConstraint::Mul { .. }) => Some(std::cmp::Ordering::Greater),
            (&NumericalConstraint::GreaterThan { .. }, &NumericalConstraint::NotEqual { .. }) => Some(std::cmp::Ordering::Less),

            (&NumericalConstraint::NotEqual { .. }, &NumericalConstraint::Set { .. }) => Some(std::cmp::Ordering::Greater),
            (&NumericalConstraint::NotEqual { .. }, &NumericalConstraint::Sum { .. }) => Some(std::cmp::Ordering::Greater),
            (&NumericalConstraint::NotEqual { .. }, &NumericalConstraint::Mul { .. }) => Some(std::cmp::Ordering::Greater),
            (&NumericalConstraint::NotEqual { .. }, &NumericalConstraint::GreaterThan { .. }) => Some(std::cmp::Ordering::Greater),
        }
    }
}

impl std::fmt::Display for NumericalConstraint {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{}", serde_json::to_string(&self).unwrap())
    }
}

impl NumericalConstraint {
    /// Try to solve this constraint using the information in the bindings
    pub fn solve<T: ConstraintValue>(&self, bindings: &Bindings<T>) -> SolveResult<T> {
        let apply_op = |x: &T, y: &T, op: &Fn(f64, f64) -> f64| -> Option<T> {
            x.to_float()
                .and_then(|x| y.to_float().and_then(|y| Some(T::float(op(x, y)))))
        };
        macro_rules! apply_op_or_return {
            ($x: ident, $y: ident, $z: ident, $op: expr) => ({
                if let Some(value) = apply_op($x, $y, &$op) {
                    ($z, value)
                } else {
                    return SolveResult::Conflict
                }
            })
        }
        let (key, value) = match *self {
            NumericalConstraint::Set {
                ref variable,
                ref constant,
                ..
            } => match bindings.get_binding(variable) {
                None => (variable, T::float(constant.clone())),
                Some(ref value) if value.to_float() == Some(*constant) => (variable, value.clone()),
                Some(_) => return SolveResult::Conflict,
            },
            NumericalConstraint::Sum {
                ref first,
                ref second,
                ref third,
                ..
            } => match (
                bindings.get_binding(first),
                bindings.get_binding(second),
                bindings.get_binding(third),
            ) {
                (Some(ref value), Some(ref value2), None) => apply_op_or_return!(value, value2, third, &Add::add),
                (Some(ref value), None, Some(ref value3)) => apply_op_or_return!(value3, value, second, &Sub::sub),
                (None, Some(ref value2), Some(ref value3)) => apply_op_or_return!(value3, value2, first, &Sub::sub),
                (Some(ref value), Some(ref value2), Some(ref value3)) => {
                    if Some(value) == apply_op(value3, value2, &Sub::sub).as_ref() {
                        return SolveResult::Partial(bindings.clone());
                    } else {
                        return SolveResult::Conflict;
                    }
                }
                _ => return SolveResult::Partial(bindings.clone()),
            },
            NumericalConstraint::Mul {
                ref first,
                ref second,
                ref third,
                ..
            } => match (
                bindings.get_binding(first),
                bindings.get_binding(second),
                bindings.get_binding(third),
            ) {
                (Some(ref value), Some(ref value2), None) => apply_op_or_return!(value, value2, third, &Mul::mul),
                (Some(ref value), None, Some(ref value3)) => apply_op_or_return!(value3, value, second, &Div::div),
                (None, Some(ref value2), Some(ref value3)) => apply_op_or_return!(value3, value2, first, &Div::div),
                (Some(ref value), Some(ref value2), Some(ref value3)) => {
                    if Some(value) == apply_op(value3, value2, &Div::div).as_ref() {
                        return SolveResult::Partial(bindings.clone());
                    } else {
                        return SolveResult::Conflict;
                    }
                }
                _ => return SolveResult::Partial(bindings.clone()),
            },
            NumericalConstraint::GreaterThan {
                ref left,
                ref right,
                ..
            } => match (bindings.get_binding(left), bindings.get_binding(right)) {
                (Some(ref left_value), Some(ref right_value)) if left_value > right_value => return SolveResult::Success(bindings.clone()),
                (Some(_), Some(_)) => return SolveResult::Conflict,
                _ => return SolveResult::Partial(bindings.clone()),
            },
            NumericalConstraint::NotEqual {
                ref left,
                ref right,
                ..
            } => match (bindings.get_binding(left), bindings.get_binding(right)) {
                (Some(ref left_value), Some(ref right_value)) if left_value != right_value => return SolveResult::Success(bindings.clone()),
                (Some(_), Some(_)) => return SolveResult::Conflict,
                _ => return SolveResult::Partial(bindings.clone()),
            },
        };
        SolveResult::Success(bindings.set_binding(key, value))
    }

    pub fn rename_variables(&self, renamed_variables: &HashMap<String, String>) -> Self {
        let lookup = |v: &String| -> String {
            renamed_variables
                .get(v)
                .cloned()
                .or_else(|| Some(v.clone()))
                .unwrap()
        };
        match *self {
            NumericalConstraint::Set {
                ref variable,
                ref constant,
                ..
            } => NumericalConstraint::Set {
                variable: lookup(variable),
                constant: constant.clone(),
            },
            NumericalConstraint::Sum {
                ref first,
                ref second,
                ref third,
                ..
            } => NumericalConstraint::Sum {
                first: lookup(first),
                second: lookup(second),
                third: lookup(third),
            },
            NumericalConstraint::Mul {
                ref first,
                ref second,
                ref third,
                ..
            } => NumericalConstraint::Mul {
                first: lookup(first),
                second: lookup(second),
                third: lookup(third),
            },
            NumericalConstraint::GreaterThan {
                ref left,
                ref right,
                ..
            } => NumericalConstraint::GreaterThan {
                left: lookup(left),
                right: lookup(right),
            },
            NumericalConstraint::NotEqual {
                ref left,
                ref right,
                ..
            } => NumericalConstraint::GreaterThan {
                left: lookup(left),
                right: lookup(right),
            },
        }
    }

    pub fn variables(&self) -> Vec<String> {
        match *self {
            NumericalConstraint::Set { ref variable, .. } => vec![variable.clone()],
            NumericalConstraint::Sum {
                ref first,
                ref second,
                ref third,
                ..
            } => vec![first.clone(), second.clone(), third.clone()],
            NumericalConstraint::Mul {
                ref first,
                ref second,
                ref third,
                ..
            } => vec![first.clone(), second.clone(), third.clone()],
            NumericalConstraint::GreaterThan {
                ref left,
                ref right,
                ..
            } => vec![left.clone(), right.clone()],
            NumericalConstraint::NotEqual {
                ref left,
                ref right,
                ..
            } => vec![left.clone(), right.clone()],
        }
    }
}
<|endoftext|>


<commit_before>/*! A codemap is a thing that maps uints to file/line/column positions
 * in a crate. This to make it possible to represent the positions
 * with single-word things, rather than passing records all over the
 * compiler.
 */

use dvec::DVec;
use std::serialization::{Serializable,
                         Deserializable,
                         Serializer,
                         Deserializer};

export filename;
export filemap;
export filemap_;
export span;
export file_substr;
export fss_none;
export fss_internal;
export fss_external;
export CodeMap;
export expn_info;
export expn_info_;
export expanded_from;
export new_filemap;
export new_filemap_w_substr;
export mk_substr_filename;
export lookup_char_pos;
export lookup_char_pos_adj;
export adjust_span;
export span_to_str;
export span_to_filename;
export span_to_lines;
export file_lines;
export get_line;
export next_line;
export span_to_snippet;
export loc;
export get_filemap;
export new_codemap;

type filename = ~str;

struct file_pos {
    ch: uint, byte: uint
}

impl file_pos : cmp::Eq {
    pure fn eq(other: &file_pos) -> bool {
        self.ch == (*other).ch && self.byte == (*other).byte
    }
    pure fn ne(other: &file_pos) -> bool { !self.eq(other) }
}

enum file_substr {
    fss_none,
    fss_internal(span),
    fss_external({filename: ~str, line: uint, col: uint})
}

struct filemap {
    name: filename,
    substr: file_substr,
    src: @~str,
    start_pos: file_pos,
    mut lines: ~[file_pos]
}

impl filemap {
    static fn new_w_substr(+filename: filename, +substr: file_substr,
                           src: @~str,
                           start_pos_ch: uint, start_pos_byte: uint)
        -> filemap {
        return filemap {
            name: filename, substr: substr, src: src,
            start_pos: file_pos {ch: start_pos_ch, byte: start_pos_byte},
            mut lines: ~[file_pos {ch: start_pos_ch, byte: start_pos_byte}]
        };
    }

    static fn new(+filename: filename, src: @~str,
                  start_pos_ch: uint, start_pos_byte: uint)
        -> filemap {
        return filemap::new_w_substr(filename, fss_none, src,
                                     start_pos_ch, start_pos_byte);
    }
}

struct CodeMap {
    files: DVec<@filemap>
}

struct loc {
    file: @filemap, line: uint, col: uint
}

fn new_codemap() -> CodeMap {
    CodeMap {
        files: DVec()
    }
}

fn mk_substr_filename(cm: @CodeMap, sp: span) -> ~str
{
    let pos = lookup_char_pos(cm, sp.lo);
    return fmt!("<%s:%u:%u>", pos.file.name, pos.line, pos.col);
}

fn next_line(file: @filemap, chpos: uint, byte_pos: uint) {
    file.lines.push(file_pos {ch: chpos, byte: byte_pos + file.start_pos.byte});
}

type lookup_fn = pure fn(file_pos) -> uint;

fn lookup_line(map: @CodeMap, pos: uint, lookup: lookup_fn)
    -> {fm: @filemap, line: uint}
{
    let len = map.files.len();
    let mut a = 0u;
    let mut b = len;
    while b - a > 1u {
        let m = (a + b) / 2u;
        if lookup(map.files[m].start_pos) > pos { b = m; } else { a = m; }
    }
    if (a >= len) {
        fail fmt!("position %u does not resolve to a source location", pos)
    }
    let f = map.files[a];
    a = 0u;
    b = vec::len(f.lines);
    while b - a > 1u {
        let m = (a + b) / 2u;
        if lookup(f.lines[m]) > pos { b = m; } else { a = m; }
    }
    return {fm: f, line: a};
}

fn lookup_pos(map: @CodeMap, pos: uint, lookup: lookup_fn) -> loc {
    let {fm: f, line: a} = lookup_line(map, pos, lookup);
    return loc {file: f, line: a + 1u, col: pos - lookup(f.lines[a])};
}

fn lookup_char_pos(map: @CodeMap, pos: uint) -> loc {
    pure fn lookup(pos: file_pos) -> uint { return pos.ch; }
    return lookup_pos(map, pos, lookup);
}

fn lookup_byte_pos(map: @CodeMap, pos: uint) -> loc {
    pure fn lookup(pos: file_pos) -> uint { return pos.byte; }
    return lookup_pos(map, pos, lookup);
}

fn lookup_char_pos_adj(map: @CodeMap, pos: uint)
    -> {filename: ~str, line: uint, col: uint, file: Option<@filemap>}
{
    let loc = lookup_char_pos(map, pos);
    match (loc.file.substr) {
      fss_none => {
        {filename: /* FIXME (#2543) */ copy loc.file.name,
         line: loc.line,
         col: loc.col,
         file: Some(loc.file)}
      }
      fss_internal(sp) => {
        lookup_char_pos_adj(map, sp.lo + (pos - loc.file.start_pos.ch))
      }
      fss_external(eloc) => {
        {filename: /* FIXME (#2543) */ copy eloc.filename,
         line: eloc.line + loc.line - 1u,
         col: if loc.line == 1u {eloc.col + loc.col} else {loc.col},
         file: None}
      }
    }
}

fn adjust_span(map: @CodeMap, sp: span) -> span {
    pure fn lookup(pos: file_pos) -> uint { return pos.ch; }
    let line = lookup_line(map, sp.lo, lookup);
    match (line.fm.substr) {
      fss_none => sp,
      fss_internal(s) => {
        adjust_span(map, span {lo: s.lo + (sp.lo - line.fm.start_pos.ch),
                               hi: s.lo + (sp.hi - line.fm.start_pos.ch),
                               expn_info: sp.expn_info})}
      fss_external(_) => sp
    }
}

enum expn_info_ {
    expanded_from({call_site: span,
                   callie: {name: ~str, span: Option<span>}})
}
type expn_info = Option<@expn_info_>;

struct span {lo: uint, hi: uint, expn_info: expn_info}

impl span : cmp::Eq {
    pure fn eq(other: &span) -> bool {
        return self.lo == (*other).lo && self.hi == (*other).hi;
    }
    pure fn ne(other: &span) -> bool { !self.eq(other) }
}

impl<S: Serializer> span: Serializable<S> {
    /* Note #1972 -- spans are serialized but not deserialized */
    fn serialize(&self, _s: &S) { }
}

impl<D: Deserializer> span: Deserializable<D> {
    static fn deserialize(_d: &D) -> span {
        ast_util::dummy_sp()
    }
}

fn span_to_str_no_adj(sp: span, cm: @CodeMap) -> ~str {
    let lo = lookup_char_pos(cm, sp.lo);
    let hi = lookup_char_pos(cm, sp.hi);
    return fmt!("%s:%u:%u: %u:%u", lo.file.name,
             lo.line, lo.col, hi.line, hi.col)
}

fn span_to_str(sp: span, cm: @CodeMap) -> ~str {
    let lo = lookup_char_pos_adj(cm, sp.lo);
    let hi = lookup_char_pos_adj(cm, sp.hi);
    return fmt!("%s:%u:%u: %u:%u", lo.filename,
             lo.line, lo.col, hi.line, hi.col)
}

struct file_lines {
    file: @filemap,
    lines: ~[uint]
}

fn span_to_filename(sp: span, cm: @codemap::CodeMap) -> filename {
    let lo = lookup_char_pos(cm, sp.lo);
    return /* FIXME (#2543) */ copy lo.file.name;
}

fn span_to_lines(sp: span, cm: @codemap::CodeMap) -> @file_lines {
    let lo = lookup_char_pos(cm, sp.lo);
    let hi = lookup_char_pos(cm, sp.hi);
    let mut lines = ~[];
    for uint::range(lo.line - 1u, hi.line as uint) |i| {
        lines.push(i);
    };
    return @file_lines {file: lo.file, lines: lines};
}

fn get_line(fm: @filemap, line: int) -> ~str unsafe {
    let begin: uint = fm.lines[line].byte - fm.start_pos.byte;
    let end = match str::find_char_from(*fm.src, '\n', begin) {
      Some(e) => e,
      None => str::len(*fm.src)
    };
    str::slice(*fm.src, begin, end)
}

fn lookup_byte_offset(cm: @codemap::CodeMap, chpos: uint)
    -> {fm: @filemap, pos: uint} {
    pure fn lookup(pos: file_pos) -> uint { return pos.ch; }
    let {fm, line} = lookup_line(cm, chpos, lookup);
    let line_offset = fm.lines[line].byte - fm.start_pos.byte;
    let col = chpos - fm.lines[line].ch;
    let col_offset = str::count_bytes(*fm.src, line_offset, col);
    {fm: fm, pos: line_offset + col_offset}
}

fn span_to_snippet(sp: span, cm: @codemap::CodeMap) -> ~str {
    let begin = lookup_byte_offset(cm, sp.lo);
    let end = lookup_byte_offset(cm, sp.hi);
    assert begin.fm.start_pos == end.fm.start_pos;
    return str::slice(*begin.fm.src, begin.pos, end.pos);
}

fn get_snippet(cm: @codemap::CodeMap, fidx: uint, lo: uint, hi: uint) -> ~str
{
    let fm = cm.files[fidx];
    return str::slice(*fm.src, lo, hi)
}

fn get_filemap(cm: @CodeMap, filename: ~str) -> @filemap {
    for cm.files.each |fm| { if fm.name == filename { return *fm; } }
    //XXjdm the following triggers a mismatched type bug
    //      (or expected function, found _|_)
    fail; // ("asking for " + filename + " which we don't know about");
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
//
<commit_msg>Reorder codemap decls<commit_after>/*! A codemap is a thing that maps uints to file/line/column positions
 * in a crate. This to make it possible to represent the positions
 * with single-word things, rather than passing records all over the
 * compiler.
 */

use dvec::DVec;
use std::serialization::{Serializable,
                         Deserializable,
                         Serializer,
                         Deserializer};

export filename;
export filemap;
export filemap_;
export span;
export file_substr;
export fss_none;
export fss_internal;
export fss_external;
export CodeMap;
export expn_info;
export expn_info_;
export expanded_from;
export new_filemap;
export new_filemap_w_substr;
export mk_substr_filename;
export lookup_char_pos;
export lookup_char_pos_adj;
export adjust_span;
export span_to_str;
export span_to_filename;
export span_to_lines;
export file_lines;
export get_line;
export next_line;
export span_to_snippet;
export loc;
export get_filemap;
export new_codemap;

struct span {lo: uint, hi: uint, expn_info: expn_info}

impl span : cmp::Eq {
    pure fn eq(other: &span) -> bool {
        return self.lo == (*other).lo && self.hi == (*other).hi;
    }
    pure fn ne(other: &span) -> bool { !self.eq(other) }
}

impl<S: Serializer> span: Serializable<S> {
    /* Note #1972 -- spans are serialized but not deserialized */
    fn serialize(&self, _s: &S) { }
}

impl<D: Deserializer> span: Deserializable<D> {
    static fn deserialize(_d: &D) -> span {
        ast_util::dummy_sp()
    }
}

enum expn_info_ {
    expanded_from({call_site: span,
                   callie: {name: ~str, span: Option<span>}})
}
type expn_info = Option<@expn_info_>;

type filename = ~str;

type lookup_fn = pure fn(file_pos) -> uint;

struct loc {
    file: @filemap, line: uint, col: uint
}

struct file_pos {
    ch: uint, byte: uint
}

impl file_pos : cmp::Eq {
    pure fn eq(other: &file_pos) -> bool {
        self.ch == (*other).ch && self.byte == (*other).byte
    }
    pure fn ne(other: &file_pos) -> bool { !self.eq(other) }
}

enum file_substr {
    fss_none,
    fss_internal(span),
    fss_external({filename: ~str, line: uint, col: uint})
}

struct filemap {
    name: filename,
    substr: file_substr,
    src: @~str,
    start_pos: file_pos,
    mut lines: ~[file_pos]
}

impl filemap {
    static fn new_w_substr(+filename: filename, +substr: file_substr,
                           src: @~str,
                           start_pos_ch: uint, start_pos_byte: uint)
        -> filemap {
        return filemap {
            name: filename, substr: substr, src: src,
            start_pos: file_pos {ch: start_pos_ch, byte: start_pos_byte},
            mut lines: ~[file_pos {ch: start_pos_ch, byte: start_pos_byte}]
        };
    }

    static fn new(+filename: filename, src: @~str,
                  start_pos_ch: uint, start_pos_byte: uint)
        -> filemap {
        return filemap::new_w_substr(filename, fss_none, src,
                                     start_pos_ch, start_pos_byte);
    }
}

struct CodeMap {
    files: DVec<@filemap>
}

fn new_codemap() -> CodeMap {
    CodeMap {
        files: DVec()
    }
}

fn mk_substr_filename(cm: @CodeMap, sp: span) -> ~str
{
    let pos = lookup_char_pos(cm, sp.lo);
    return fmt!("<%s:%u:%u>", pos.file.name, pos.line, pos.col);
}

fn next_line(file: @filemap, chpos: uint, byte_pos: uint) {
    file.lines.push(file_pos {ch: chpos, byte: byte_pos + file.start_pos.byte});
}

fn lookup_line(map: @CodeMap, pos: uint, lookup: lookup_fn)
    -> {fm: @filemap, line: uint}
{
    let len = map.files.len();
    let mut a = 0u;
    let mut b = len;
    while b - a > 1u {
        let m = (a + b) / 2u;
        if lookup(map.files[m].start_pos) > pos { b = m; } else { a = m; }
    }
    if (a >= len) {
        fail fmt!("position %u does not resolve to a source location", pos)
    }
    let f = map.files[a];
    a = 0u;
    b = vec::len(f.lines);
    while b - a > 1u {
        let m = (a + b) / 2u;
        if lookup(f.lines[m]) > pos { b = m; } else { a = m; }
    }
    return {fm: f, line: a};
}

fn lookup_pos(map: @CodeMap, pos: uint, lookup: lookup_fn) -> loc {
    let {fm: f, line: a} = lookup_line(map, pos, lookup);
    return loc {file: f, line: a + 1u, col: pos - lookup(f.lines[a])};
}

fn lookup_char_pos(map: @CodeMap, pos: uint) -> loc {
    pure fn lookup(pos: file_pos) -> uint { return pos.ch; }
    return lookup_pos(map, pos, lookup);
}

fn lookup_byte_pos(map: @CodeMap, pos: uint) -> loc {
    pure fn lookup(pos: file_pos) -> uint { return pos.byte; }
    return lookup_pos(map, pos, lookup);
}

fn lookup_char_pos_adj(map: @CodeMap, pos: uint)
    -> {filename: ~str, line: uint, col: uint, file: Option<@filemap>}
{
    let loc = lookup_char_pos(map, pos);
    match (loc.file.substr) {
      fss_none => {
        {filename: /* FIXME (#2543) */ copy loc.file.name,
         line: loc.line,
         col: loc.col,
         file: Some(loc.file)}
      }
      fss_internal(sp) => {
        lookup_char_pos_adj(map, sp.lo + (pos - loc.file.start_pos.ch))
      }
      fss_external(eloc) => {
        {filename: /* FIXME (#2543) */ copy eloc.filename,
         line: eloc.line + loc.line - 1u,
         col: if loc.line == 1u {eloc.col + loc.col} else {loc.col},
         file: None}
      }
    }
}

fn adjust_span(map: @CodeMap, sp: span) -> span {
    pure fn lookup(pos: file_pos) -> uint { return pos.ch; }
    let line = lookup_line(map, sp.lo, lookup);
    match (line.fm.substr) {
      fss_none => sp,
      fss_internal(s) => {
        adjust_span(map, span {lo: s.lo + (sp.lo - line.fm.start_pos.ch),
                               hi: s.lo + (sp.hi - line.fm.start_pos.ch),
                               expn_info: sp.expn_info})}
      fss_external(_) => sp
    }
}

fn span_to_str_no_adj(sp: span, cm: @CodeMap) -> ~str {
    let lo = lookup_char_pos(cm, sp.lo);
    let hi = lookup_char_pos(cm, sp.hi);
    return fmt!("%s:%u:%u: %u:%u", lo.file.name,
             lo.line, lo.col, hi.line, hi.col)
}

fn span_to_str(sp: span, cm: @CodeMap) -> ~str {
    let lo = lookup_char_pos_adj(cm, sp.lo);
    let hi = lookup_char_pos_adj(cm, sp.hi);
    return fmt!("%s:%u:%u: %u:%u", lo.filename,
             lo.line, lo.col, hi.line, hi.col)
}

struct file_lines {
    file: @filemap,
    lines: ~[uint]
}

fn span_to_filename(sp: span, cm: @codemap::CodeMap) -> filename {
    let lo = lookup_char_pos(cm, sp.lo);
    return /* FIXME (#2543) */ copy lo.file.name;
}

fn span_to_lines(sp: span, cm: @codemap::CodeMap) -> @file_lines {
    let lo = lookup_char_pos(cm, sp.lo);
    let hi = lookup_char_pos(cm, sp.hi);
    let mut lines = ~[];
    for uint::range(lo.line - 1u, hi.line as uint) |i| {
        lines.push(i);
    };
    return @file_lines {file: lo.file, lines: lines};
}

fn get_line(fm: @filemap, line: int) -> ~str unsafe {
    let begin: uint = fm.lines[line].byte - fm.start_pos.byte;
    let end = match str::find_char_from(*fm.src, '\n', begin) {
      Some(e) => e,
      None => str::len(*fm.src)
    };
    str::slice(*fm.src, begin, end)
}

fn lookup_byte_offset(cm: @codemap::CodeMap, chpos: uint)
    -> {fm: @filemap, pos: uint} {
    pure fn lookup(pos: file_pos) -> uint { return pos.ch; }
    let {fm, line} = lookup_line(cm, chpos, lookup);
    let line_offset = fm.lines[line].byte - fm.start_pos.byte;
    let col = chpos - fm.lines[line].ch;
    let col_offset = str::count_bytes(*fm.src, line_offset, col);
    {fm: fm, pos: line_offset + col_offset}
}

fn span_to_snippet(sp: span, cm: @codemap::CodeMap) -> ~str {
    let begin = lookup_byte_offset(cm, sp.lo);
    let end = lookup_byte_offset(cm, sp.hi);
    assert begin.fm.start_pos == end.fm.start_pos;
    return str::slice(*begin.fm.src, begin.pos, end.pos);
}

fn get_snippet(cm: @codemap::CodeMap, fidx: uint, lo: uint, hi: uint) -> ~str
{
    let fm = cm.files[fidx];
    return str::slice(*fm.src, lo, hi)
}

fn get_filemap(cm: @CodeMap, filename: ~str) -> @filemap {
    for cm.files.each |fm| { if fm.name == filename { return *fm; } }
    //XXjdm the following triggers a mismatched type bug
    //      (or expected function, found _|_)
    fail; // ("asking for " + filename + " which we don't know about");
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
//
<|endoftext|>


<commit_before>use libc::{ c_int, c_uint, sockaddr_nl };
// use std::marker::PhantomData;
use std::mem::size_of;

pub const NETLINK_ROUTE: c_int		= 0;	// Routing/device hook
pub const NETLINK_UNUSED: c_int		= 1;	// Unused number
pub const NETLINK_USERSOCK: c_int	= 2;	// Reserved for user mode socket protocols
pub const NETLINK_FIREWALL: c_int	= 3;	// Unused number, formerly ip_queue
pub const NETLINK_SOCK_DIAG: c_int	= 4;	// socket monitoring
pub const NETLINK_NFLOG: c_int		= 5;	// netfilter/iptables ULOG
pub const NETLINK_XFRM: c_int		= 6;	// ipsec
pub const NETLINK_SELINUX: c_int	= 7;	// SELinux event notifications
pub const NETLINK_ISCSI: c_int		= 8;	// Open-iSCSI
pub const NETLINK_AUDIT: c_int		= 9;	// auditing
pub const NETLINK_FIB_LOOKUP: c_int	= 10;
pub const NETLINK_CONNECTOR: c_int	= 11;
pub const NETLINK_NETFILTER: c_int	= 12;	// netfilter subsystem
pub const NETLINK_IP6_FW: c_int		= 13;
pub const NETLINK_DNRTMSG: c_int	= 14;	// DECnet routing messages
pub const NETLINK_KOBJECT_UEVENT: c_int	= 15;	// Kernel messages to userspace
pub const NETLINK_GENERIC: c_int	= 16;
// leave room for NETLINK_DM (DM Events)
pub const NETLINK_SCSITRANSPORT: c_int	= 18;	// SCSI Transports
pub const NETLINK_ECRYPTFS: c_int	= 19;
pub const NETLINK_RDMA: c_int		= 20;
pub const NETLINK_CRYPTO: c_int		= 21;	// Crypto layer

pub const NETLINK_INET_DIAG: c_int	= NETLINK_SOCK_DIAG;

pub const MAX_LINKS: c_int		= 32;

#[allow(non_camel_case_types)]
pub enum Family {
    ROUTE,             // Routing/device hook
    UNUSED,            // Unused number
    USERSOCK,          // Reserved for user mode socket protocols
    FIREWALL,          // Unused number, formerly ip_queue
    SOCK_DIAG,         // socket monitoring
    NFLOG,             // netfilter/iptables ULOG
    XFRM,              // ipsec
    SELINUX,           // SELinux event notifications
    ISCSI,             // Open-iSCSI
    AUDIT,             // auditing
    FIB_LOOKUP,
    CONNECTOR,
    NETFILTER,         // netfilter subsystem
    IP6_FW,
    DNRTMSG,           // DECnet routing messages
    KOBJECT_UEVENT,    // Kernel messages to userspace
    GENERIC,

    SCSITRANSPORT,     // SCSI Transports
    ECRYPTFS,
    RDMA,
    CRYPTO,            // Crypto layer

    INET_DIAG,         // NETLINK_SOCK_DIAG
}

impl Family {
    pub fn c_int(self) -> c_int {
	match self {
	    Family::ROUTE		=> NETLINK_ROUTE,
	    Family::UNUSED		=> NETLINK_UNUSED,
	    Family::USERSOCK		=> NETLINK_USERSOCK,
	    Family::FIREWALL		=> NETLINK_FIREWALL,
	    Family::SOCK_DIAG		=> NETLINK_SOCK_DIAG,
	    Family::NFLOG		=> NETLINK_NFLOG,
	    Family::XFRM		=> NETLINK_XFRM,
	    Family::SELINUX		=> NETLINK_SELINUX,
	    Family::ISCSI		=> NETLINK_ISCSI,
	    Family::AUDIT		=> NETLINK_AUDIT,
	    Family::FIB_LOOKUP		=> NETLINK_FIB_LOOKUP,
	    Family::CONNECTOR		=> NETLINK_CONNECTOR,
	    Family::NETFILTER		=> NETLINK_NETFILTER,
	    Family::IP6_FW		=> NETLINK_IP6_FW,
	    Family::DNRTMSG		=> NETLINK_DNRTMSG,
	    Family::KOBJECT_UEVENT	=> NETLINK_KOBJECT_UEVENT,
	    Family::GENERIC		=> NETLINK_GENERIC,
	    Family::SCSITRANSPORT	=> NETLINK_SCSITRANSPORT,
	    Family::ECRYPTFS		=> NETLINK_ECRYPTFS,
	    Family::RDMA		=> NETLINK_RDMA,
	    Family::CRYPTO		=> NETLINK_CRYPTO,
	    Family::INET_DIAG		=> NETLINK_INET_DIAG,
	}
    }
}

// XXX: not ported yet
// #[repr(C)]
pub struct SockaddrNl { inner: sockaddr_nl }

#[repr(C)]
pub struct Nlmsghdr { // pub struct Nlmsghdr <'a> {
    pub nlmsg_len: u32,
    pub nlmsg_type: u16,
    pub nlmsg_flags: u16,
    pub nlmsg_seq: u32,
    pub nlmsg_pid: u32,
    // pub phantom: PhantomData<&'a [u8]>
}

// Flags values
pub const NLM_F_REQUEST: u16		= 1;	// It is request message.
pub const NLM_F_MULTI: u16		= 2;	// Multipart message, terminated by NLMSG_DONE
pub const NLM_F_ACK: u16		= 4;	// Reply with ack, with zero or error code
pub const NLM_F_ECHO: u16		= 8;	// Echo this request
pub const NLM_F_DUMP_INTR: u16		= 16;	// Dump was inconsistent due to sequence change
pub const NLM_F_DUMP_FILTERED: u16	= 32;	// Dump was filtered as requested

// Modifiers to GET request
pub const NLM_F_ROOT: u16	= 0x100;	// specify tree	root
pub const NLM_F_MATCH: u16	= 0x200;	// return all matching
pub const NLM_F_ATOMIC: u16	= 0x400;	// atomic GET
pub const NLM_F_DUMP: u16	= (NLM_F_ROOT|NLM_F_MATCH);

// Modifiers to NEW request
pub const NLM_F_REPLACE: u16	= 0x100;	// Override existing
pub const NLM_F_EXCL: u16	= 0x200;	// Do not touch, if it exists
pub const NLM_F_CREATE: u16	= 0x400;	// Create, if it does not exist
pub const NLM_F_APPEND: u16	= 0x800;	// Add to end of list

// 4.4BSD ADD		NLM_F_CREATE|NLM_F_EXCL
// 4.4BSD CHANGE	NLM_F_REPLACE
//
// True CHANGE		NLM_F_CREATE|NLM_F_REPLACE
// Append		NLM_F_CREATE
// Check		NLM_F_EXCL

pub const NLMSG_ALIGNTO: u32	= 4;
#[allow(non_snake_case)]
pub fn NLMSG_ALIGN(len: u32) -> u32 {
    (len + NLMSG_ALIGNTO - 1) & !(NLMSG_ALIGNTO - 1)
}

#[allow(non_snake_case)]
pub fn NLMSG_HDRLEN() -> u32 {
    NLMSG_ALIGN(size_of::<Nlmsghdr>() as u32)
}
// macro_rules! NLMSG_HDRLEN {
//    () => { ALIGN(size_of::<Nlmsghdr>() as u32) }
// }

#[allow(non_snake_case)]
pub fn NLMSG_LENGTH(len: u32) -> u32 {
    len + NLMSG_HDRLEN()
}

#[allow(non_snake_case)]
pub fn NLMSG_SPACE(len: u32) -> u32 {
    NLMSG_ALIGN(NLMSG_LENGTH(len))
}

#[allow(non_snake_case)]
pub fn NLMSG_DATA<T>(nlh: &mut Nlmsghdr) -> &mut T {
    unsafe {
        ((nlh as *mut _ as *mut u8)
         .offset(NLMSG_LENGTH(0) as isize) as *mut T)
            .as_mut()
    }.unwrap()
}

#[allow(non_snake_case)]
pub fn NLMSG_NEXT<'a>(nlh: &'a mut Nlmsghdr, len: &mut u32) -> &'a mut Nlmsghdr {
    *len -= NLMSG_ALIGN(nlh.nlmsg_len);
    unsafe {
        ((nlh as *mut _ as *mut u8)
         .offset(NLMSG_ALIGN(nlh.nlmsg_len) as isize) as *mut Nlmsghdr)
            .as_mut()
    }.unwrap()
}

#[allow(non_snake_case)]
pub fn NLMSG_OK(nlh: &Nlmsghdr, len: u32) -> bool {
    len >= size_of::<Nlmsghdr>() as u32 &&
	nlh.nlmsg_len >= size_of::<Nlmsghdr>() as u32 &&
	nlh.nlmsg_len <= len
}

#[allow(non_snake_case)]
pub fn NLMSG_PAYLOAD(nlh: &Nlmsghdr, len: u32) -> u32 {
    nlh.nlmsg_len - NLMSG_SPACE((len))
}

pub const NLMSG_NOOP: u16	= 0x1;	// Nothing.
pub const NLMSG_ERROR: u16	= 0x2;	// Error
pub const NLMSG_DONE: u16	= 0x3;	// End of a dump
pub const NLMSG_OVERRUN: u16	= 0x4;	// Data lost

pub const NLMSG_MIN_TYPE: u16	= 0x10;	// < 0x10: reserved control messages

#[repr(C)]
pub struct Nlmsgerr {		// pub struct Nlmsgerr <'a> {
    pub error: c_int,
    pub msg: Nlmsghdr,		// pub msg: Nlmsghdr<'a>,
}

pub const NETLINK_ADD_MEMBERSHIP: c_int		= 1;
pub const NETLINK_DROP_MEMBERSHIP: c_int	= 2;
pub const NETLINK_PKTINFO: c_int		= 3;
pub const NETLINK_BROADCAST_ERROR: c_int	= 4;
pub const NETLINK_NO_ENOBUFS: c_int		= 5;
// pub const NETLINK_RX_RING: c_int		= 6;
// pub const NETLINK_TX_RING: c_int		= 7;
pub const NETLINK_LISTEN_ALL_NSID: c_int	= 8;
pub const NETLINK_LIST_MEMBERSHIPS: c_int	= 9;
pub const NETLINK_CAP_ACK: c_int		= 10;

pub struct NlPktinfo {
    group: u32,
}

pub const NET_MAJOR: c_uint	= 36;	// Major 36 is reserved for networking

// struct sock_common.skc_state;
pub const NETLINK_UNCONNECTED: u8	= 0;
pub const NETLINK_CONNECTED: u8		= 1;

//  <------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)-->
// +---------------------+- - -+- - - - - - - - - -+- - -+
// |        Header       | Pad |     Payload       | Pad |
// |   (struct nlattr)   | ing |                   | ing |
// +---------------------+- - -+- - - - - - - - - -+- - -+
//  <-------------- nlattr->nla_len -------------->
#[repr(C)]
pub struct Nlattr {
    nla_len: u16,
    nla_type: u16,
}

// nla_type (16 bits)
// +---+---+-------------------------------+
// | N | O | Attribute Type                |
// +---+---+-------------------------------+
// N := Carries nested attributes
// O := Payload stored in network byte order
//
// Note: The N and O flag are mutually exclusive.
pub const NLA_F_NESTED: u16		= (1 << 15);
pub const NLA_F_NET_BYTEORDER: u16	= (1 << 14);
pub const NLA_TYPE_MASK: u16		= !(NLA_F_NESTED | NLA_F_NET_BYTEORDER);

pub const NLA_ALIGNTO: u16		= 4;

#[allow(non_snake_case)]
pub fn NLA_ALIGN(len: u16) -> u16 {
    (len + NLA_ALIGNTO - 1) & !(NLA_ALIGNTO - 1)
}

#[allow(non_snake_case)]
pub fn NLA_HDRLEN() -> u16 {
    NLA_ALIGN(size_of::<Nlattr>() as u16)
}
// macro_rules! ATTR_HDRLEN {
//     () => { ALIGN(size_of::<Nlattr>() as u16) }
// }
<commit_msg>[linux] fix nlattr access<commit_after>use libc::{ c_int, c_uint, sockaddr_nl };
// use std::marker::PhantomData;
use std::mem::size_of;

pub const NETLINK_ROUTE: c_int		= 0;	// Routing/device hook
pub const NETLINK_UNUSED: c_int		= 1;	// Unused number
pub const NETLINK_USERSOCK: c_int	= 2;	// Reserved for user mode socket protocols
pub const NETLINK_FIREWALL: c_int	= 3;	// Unused number, formerly ip_queue
pub const NETLINK_SOCK_DIAG: c_int	= 4;	// socket monitoring
pub const NETLINK_NFLOG: c_int		= 5;	// netfilter/iptables ULOG
pub const NETLINK_XFRM: c_int		= 6;	// ipsec
pub const NETLINK_SELINUX: c_int	= 7;	// SELinux event notifications
pub const NETLINK_ISCSI: c_int		= 8;	// Open-iSCSI
pub const NETLINK_AUDIT: c_int		= 9;	// auditing
pub const NETLINK_FIB_LOOKUP: c_int	= 10;
pub const NETLINK_CONNECTOR: c_int	= 11;
pub const NETLINK_NETFILTER: c_int	= 12;	// netfilter subsystem
pub const NETLINK_IP6_FW: c_int		= 13;
pub const NETLINK_DNRTMSG: c_int	= 14;	// DECnet routing messages
pub const NETLINK_KOBJECT_UEVENT: c_int	= 15;	// Kernel messages to userspace
pub const NETLINK_GENERIC: c_int	= 16;
// leave room for NETLINK_DM (DM Events)
pub const NETLINK_SCSITRANSPORT: c_int	= 18;	// SCSI Transports
pub const NETLINK_ECRYPTFS: c_int	= 19;
pub const NETLINK_RDMA: c_int		= 20;
pub const NETLINK_CRYPTO: c_int		= 21;	// Crypto layer

pub const NETLINK_INET_DIAG: c_int	= NETLINK_SOCK_DIAG;

pub const MAX_LINKS: c_int		= 32;

#[allow(non_camel_case_types)]
pub enum Family {
    ROUTE,             // Routing/device hook
    UNUSED,            // Unused number
    USERSOCK,          // Reserved for user mode socket protocols
    FIREWALL,          // Unused number, formerly ip_queue
    SOCK_DIAG,         // socket monitoring
    NFLOG,             // netfilter/iptables ULOG
    XFRM,              // ipsec
    SELINUX,           // SELinux event notifications
    ISCSI,             // Open-iSCSI
    AUDIT,             // auditing
    FIB_LOOKUP,
    CONNECTOR,
    NETFILTER,         // netfilter subsystem
    IP6_FW,
    DNRTMSG,           // DECnet routing messages
    KOBJECT_UEVENT,    // Kernel messages to userspace
    GENERIC,

    SCSITRANSPORT,     // SCSI Transports
    ECRYPTFS,
    RDMA,
    CRYPTO,            // Crypto layer

    INET_DIAG,         // NETLINK_SOCK_DIAG
}

impl Family {
    pub fn c_int(self) -> c_int {
	match self {
	    Family::ROUTE		=> NETLINK_ROUTE,
	    Family::UNUSED		=> NETLINK_UNUSED,
	    Family::USERSOCK		=> NETLINK_USERSOCK,
	    Family::FIREWALL		=> NETLINK_FIREWALL,
	    Family::SOCK_DIAG		=> NETLINK_SOCK_DIAG,
	    Family::NFLOG		=> NETLINK_NFLOG,
	    Family::XFRM		=> NETLINK_XFRM,
	    Family::SELINUX		=> NETLINK_SELINUX,
	    Family::ISCSI		=> NETLINK_ISCSI,
	    Family::AUDIT		=> NETLINK_AUDIT,
	    Family::FIB_LOOKUP		=> NETLINK_FIB_LOOKUP,
	    Family::CONNECTOR		=> NETLINK_CONNECTOR,
	    Family::NETFILTER		=> NETLINK_NETFILTER,
	    Family::IP6_FW		=> NETLINK_IP6_FW,
	    Family::DNRTMSG		=> NETLINK_DNRTMSG,
	    Family::KOBJECT_UEVENT	=> NETLINK_KOBJECT_UEVENT,
	    Family::GENERIC		=> NETLINK_GENERIC,
	    Family::SCSITRANSPORT	=> NETLINK_SCSITRANSPORT,
	    Family::ECRYPTFS		=> NETLINK_ECRYPTFS,
	    Family::RDMA		=> NETLINK_RDMA,
	    Family::CRYPTO		=> NETLINK_CRYPTO,
	    Family::INET_DIAG		=> NETLINK_INET_DIAG,
	}
    }
}

// XXX: not ported yet
// #[repr(C)]
pub struct SockaddrNl { inner: sockaddr_nl }

#[repr(C)]
pub struct Nlmsghdr { // pub struct Nlmsghdr <'a> {
    pub nlmsg_len: u32,
    pub nlmsg_type: u16,
    pub nlmsg_flags: u16,
    pub nlmsg_seq: u32,
    pub nlmsg_pid: u32,
    // pub phantom: PhantomData<&'a [u8]>
}

// Flags values
pub const NLM_F_REQUEST: u16		= 1;	// It is request message.
pub const NLM_F_MULTI: u16		= 2;	// Multipart message, terminated by NLMSG_DONE
pub const NLM_F_ACK: u16		= 4;	// Reply with ack, with zero or error code
pub const NLM_F_ECHO: u16		= 8;	// Echo this request
pub const NLM_F_DUMP_INTR: u16		= 16;	// Dump was inconsistent due to sequence change
pub const NLM_F_DUMP_FILTERED: u16	= 32;	// Dump was filtered as requested

// Modifiers to GET request
pub const NLM_F_ROOT: u16	= 0x100;	// specify tree	root
pub const NLM_F_MATCH: u16	= 0x200;	// return all matching
pub const NLM_F_ATOMIC: u16	= 0x400;	// atomic GET
pub const NLM_F_DUMP: u16	= (NLM_F_ROOT|NLM_F_MATCH);

// Modifiers to NEW request
pub const NLM_F_REPLACE: u16	= 0x100;	// Override existing
pub const NLM_F_EXCL: u16	= 0x200;	// Do not touch, if it exists
pub const NLM_F_CREATE: u16	= 0x400;	// Create, if it does not exist
pub const NLM_F_APPEND: u16	= 0x800;	// Add to end of list

// 4.4BSD ADD		NLM_F_CREATE|NLM_F_EXCL
// 4.4BSD CHANGE	NLM_F_REPLACE
//
// True CHANGE		NLM_F_CREATE|NLM_F_REPLACE
// Append		NLM_F_CREATE
// Check		NLM_F_EXCL

pub const NLMSG_ALIGNTO: u32	= 4;
#[allow(non_snake_case)]
pub fn NLMSG_ALIGN(len: u32) -> u32 {
    (len + NLMSG_ALIGNTO - 1) & !(NLMSG_ALIGNTO - 1)
}

#[allow(non_snake_case)]
pub fn NLMSG_HDRLEN() -> u32 {
    NLMSG_ALIGN(size_of::<Nlmsghdr>() as u32)
}
// macro_rules! NLMSG_HDRLEN {
//    () => { ALIGN(size_of::<Nlmsghdr>() as u32) }
// }

#[allow(non_snake_case)]
pub fn NLMSG_LENGTH(len: u32) -> u32 {
    len + NLMSG_HDRLEN()
}

#[allow(non_snake_case)]
pub fn NLMSG_SPACE(len: u32) -> u32 {
    NLMSG_ALIGN(NLMSG_LENGTH(len))
}

#[allow(non_snake_case)]
pub fn NLMSG_DATA<T>(nlh: &mut Nlmsghdr) -> &mut T {
    unsafe {
        ((nlh as *mut _ as *mut u8)
         .offset(NLMSG_LENGTH(0) as isize) as *mut T)
            .as_mut()
    }.unwrap()
}

#[allow(non_snake_case)]
pub fn NLMSG_NEXT<'a>(nlh: &'a mut Nlmsghdr, len: &mut u32) -> &'a mut Nlmsghdr {
    *len -= NLMSG_ALIGN(nlh.nlmsg_len);
    unsafe {
        ((nlh as *mut _ as *mut u8)
         .offset(NLMSG_ALIGN(nlh.nlmsg_len) as isize) as *mut Nlmsghdr)
            .as_mut()
    }.unwrap()
}

#[allow(non_snake_case)]
pub fn NLMSG_OK(nlh: &Nlmsghdr, len: u32) -> bool {
    len >= size_of::<Nlmsghdr>() as u32 &&
	nlh.nlmsg_len >= size_of::<Nlmsghdr>() as u32 &&
	nlh.nlmsg_len <= len
}

#[allow(non_snake_case)]
pub fn NLMSG_PAYLOAD(nlh: &Nlmsghdr, len: u32) -> u32 {
    nlh.nlmsg_len - NLMSG_SPACE((len))
}

pub const NLMSG_NOOP: u16	= 0x1;	// Nothing.
pub const NLMSG_ERROR: u16	= 0x2;	// Error
pub const NLMSG_DONE: u16	= 0x3;	// End of a dump
pub const NLMSG_OVERRUN: u16	= 0x4;	// Data lost

pub const NLMSG_MIN_TYPE: u16	= 0x10;	// < 0x10: reserved control messages

#[repr(C)]
pub struct Nlmsgerr {		// pub struct Nlmsgerr <'a> {
    pub error: c_int,
    pub msg: Nlmsghdr,		// pub msg: Nlmsghdr<'a>,
}

pub const NETLINK_ADD_MEMBERSHIP: c_int		= 1;
pub const NETLINK_DROP_MEMBERSHIP: c_int	= 2;
pub const NETLINK_PKTINFO: c_int		= 3;
pub const NETLINK_BROADCAST_ERROR: c_int	= 4;
pub const NETLINK_NO_ENOBUFS: c_int		= 5;
// pub const NETLINK_RX_RING: c_int		= 6;
// pub const NETLINK_TX_RING: c_int		= 7;
pub const NETLINK_LISTEN_ALL_NSID: c_int	= 8;
pub const NETLINK_LIST_MEMBERSHIPS: c_int	= 9;
pub const NETLINK_CAP_ACK: c_int		= 10;

pub struct NlPktinfo {
    group: u32,
}

pub const NET_MAJOR: c_uint	= 36;	// Major 36 is reserved for networking

// struct sock_common.skc_state;
pub const NETLINK_UNCONNECTED: u8	= 0;
pub const NETLINK_CONNECTED: u8		= 1;

//  <------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)-->
// +---------------------+- - -+- - - - - - - - - -+- - -+
// |        Header       | Pad |     Payload       | Pad |
// |   (struct nlattr)   | ing |                   | ing |
// +---------------------+- - -+- - - - - - - - - -+- - -+
//  <-------------- nlattr->nla_len -------------->
#[repr(C)]
pub struct Nlattr {
    pub nla_len: u16,
    pub nla_type: u16,
}

// nla_type (16 bits)
// +---+---+-------------------------------+
// | N | O | Attribute Type                |
// +---+---+-------------------------------+
// N := Carries nested attributes
// O := Payload stored in network byte order
//
// Note: The N and O flag are mutually exclusive.
pub const NLA_F_NESTED: u16		= (1 << 15);
pub const NLA_F_NET_BYTEORDER: u16	= (1 << 14);
pub const NLA_TYPE_MASK: u16		= !(NLA_F_NESTED | NLA_F_NET_BYTEORDER);

pub const NLA_ALIGNTO: u16		= 4;

#[allow(non_snake_case)]
pub fn NLA_ALIGN(len: u16) -> u16 {
    (len + NLA_ALIGNTO - 1) & !(NLA_ALIGNTO - 1)
}

#[allow(non_snake_case)]
pub fn NLA_HDRLEN() -> u16 {
    NLA_ALIGN(size_of::<Nlattr>() as u16)
}
// macro_rules! ATTR_HDRLEN {
//     () => { ALIGN(size_of::<Nlattr>() as u16) }
// }
<|endoftext|>


<commit_before>use std::{
    io::{Read, Write},
    os::unix::{io::FromRawFd, net::UnixStream},
};

use nix::{errno::Errno, sys::socket, Error as NixError, Result as NixResult};

/// Find a free X11 display slot and setup
pub(crate) fn prepare_x11_sockets(log: ::slog::Logger) -> Result<(X11Lock, [UnixStream; 2]), ()> {
    for d in 0..33 {
        // if fails, try the next one
        if let Ok(lock) = X11Lock::grab(d, log.clone()) {
            // we got a lockfile, try and create the socket
            if let Ok(sockets) = open_x11_sockets_for_display(d) {
                return Ok((lock, sockets));
            }
        }
    }
    // If we reach here, all values from 0 to 32 failed
    // we need to stop trying at some point
    Err(())
}

pub(crate) struct X11Lock {
    display: u32,
    log: ::slog::Logger,
}

impl X11Lock {
    /// Try to grab a lockfile for given X display number
    fn grab(display: u32, log: ::slog::Logger) -> Result<X11Lock, ()> {
        debug!(log, "Attempting to aquire an X11 display lock"; "D" => display);
        let filename = format!("/tmp/.X{}-lock", display);
        let lockfile = ::std::fs::OpenOptions::new()
            .write(true)
            .create_new(true)
            .open(&filename);
        match lockfile {
            Ok(mut file) => {
                // we got it, write our PID in it and we're good
                let ret = file.write_fmt(format_args!("{:>10}", ::nix::unistd::Pid::this()));
                if ret.is_err() {
                    // write to the file failed ? we abandon
                    ::std::mem::drop(file);
                    let _ = ::std::fs::remove_file(&filename);
                    Err(())
                } else {
                    debug!(log, "X11 lock aquired"; "D" => display);
                    // we got the lockfile and wrote our pid to it, all is good
                    Ok(X11Lock { display, log })
                }
            }
            Err(_) => {
                debug!(log, "Failed to acquire lock"; "D" => display);
                // we could not open the file, now we try to read it
                // and if it contains the pid of a process that no longer
                // exist (so if a previous x server claimed it and did not
                // exit gracefully and remove it), we claim it
                // if we can't open it, give up
                let mut file = ::std::fs::File::open(&filename).map_err(|_| ())?;
                let mut spid = [0u8; 11];
                file.read_exact(&mut spid).map_err(|_| ())?;
                ::std::mem::drop(file);
                let pid = ::nix::unistd::Pid::from_raw(
                    ::std::str::from_utf8(&spid)
                        .map_err(|_| ())?
                        .trim()
                        .parse::<i32>()
                        .map_err(|_| ())?,
                );
                if let Err(NixError::Sys(Errno::ESRCH)) = ::nix::sys::signal::kill(pid, None) {
                    // no process whose pid equals the contents of the lockfile exists
                    // remove the lockfile and try grabbing it again
                    if let Ok(()) = ::std::fs::remove_file(filename) {
                        debug!(log, "Lock was blocked by a defunct X11 server, trying again"; "D" => display);
                        return X11Lock::grab(display, log);
                    } else {
                        // we could not remove the lockfile, abort
                        return Err(());
                    }
                }
                // if we reach here, this lockfile exists and is probably in use, give up
                Err(())
            }
        }
    }

    pub(crate) fn display(&self) -> u32 {
        self.display
    }
}

impl Drop for X11Lock {
    fn drop(&mut self) {
        info!(self.log, "Cleaning up X11 lock.");
        // Cleanup all the X11 files
        if let Err(e) = ::std::fs::remove_file(format!("/tmp/.X11-unix/X{}", self.display)) {
            warn!(self.log, "Failed to remove X11 socket"; "error" => format!("{:?}", e));
        }
        if let Err(e) = ::std::fs::remove_file(format!("/tmp/.X{}-lock", self.display)) {
            warn!(self.log, "Failed to remove X11 lockfile"; "error" => format!("{:?}", e));
        }
    }
}

/// Open the two unix sockets an X server listens on
///
/// Should only be done after the associated lockfile is aquired!
fn open_x11_sockets_for_display(display: u32) -> NixResult<[UnixStream; 2]> {
    let path = format!("/tmp/.X11-unix/X{}", display);
    // We know this path is not to long, these unwrap cannot fail
    let fs_addr = socket::UnixAddr::new(path.as_bytes()).unwrap();
    let abs_addr = socket::UnixAddr::new_abstract(path.as_bytes()).unwrap();
    let fs_socket = open_socket(fs_addr)?;
    let abstract_socket = open_socket(abs_addr)?;
    Ok([fs_socket, abstract_socket])
}

/// Open an unix socket for listening and bind it to given path
fn open_socket(addr: socket::UnixAddr) -> NixResult<UnixStream> {
    // create an unix stream socket
    let fd = socket::socket(
        socket::AddressFamily::Unix,
        socket::SockType::Stream,
        socket::SockFlag::SOCK_CLOEXEC,
        None,
    )?;
    // bind it to requested address
    if let Err(e) = socket::bind(fd, &socket::SockAddr::Unix(addr)) {
        let _ = ::nix::unistd::close(fd);
        return Err(e);
    }
    if let Err(e) = socket::listen(fd, 1) {
        let _ = ::nix::unistd::close(fd);
        return Err(e);
    }
    Ok(unsafe { FromRawFd::from_raw_fd(fd) })
}
<commit_msg>Fix writing /tmp/.X{}.lock<commit_after>use std::{
    io::{Read, Write},
    os::unix::{io::FromRawFd, net::UnixStream},
};

use nix::{errno::Errno, sys::socket, Error as NixError, Result as NixResult};

/// Find a free X11 display slot and setup
pub(crate) fn prepare_x11_sockets(log: ::slog::Logger) -> Result<(X11Lock, [UnixStream; 2]), ()> {
    for d in 0..33 {
        // if fails, try the next one
        if let Ok(lock) = X11Lock::grab(d, log.clone()) {
            // we got a lockfile, try and create the socket
            if let Ok(sockets) = open_x11_sockets_for_display(d) {
                return Ok((lock, sockets));
            }
        }
    }
    // If we reach here, all values from 0 to 32 failed
    // we need to stop trying at some point
    Err(())
}

pub(crate) struct X11Lock {
    display: u32,
    log: ::slog::Logger,
}

impl X11Lock {
    /// Try to grab a lockfile for given X display number
    fn grab(display: u32, log: ::slog::Logger) -> Result<X11Lock, ()> {
        debug!(log, "Attempting to aquire an X11 display lock"; "D" => display);
        let filename = format!("/tmp/.X{}-lock", display);
        let lockfile = ::std::fs::OpenOptions::new()
            .write(true)
            .create_new(true)
            .open(&filename);
        match lockfile {
            Ok(mut file) => {
                // we got it, write our PID in it and we're good
                let ret = file.write_fmt(format_args!("{:>10}\n", ::nix::unistd::Pid::this()));
                if ret.is_err() {
                    // write to the file failed ? we abandon
                    ::std::mem::drop(file);
                    let _ = ::std::fs::remove_file(&filename);
                    Err(())
                } else {
                    debug!(log, "X11 lock aquired"; "D" => display);
                    // we got the lockfile and wrote our pid to it, all is good
                    Ok(X11Lock { display, log })
                }
            }
            Err(_) => {
                debug!(log, "Failed to acquire lock"; "D" => display);
                // we could not open the file, now we try to read it
                // and if it contains the pid of a process that no longer
                // exist (so if a previous x server claimed it and did not
                // exit gracefully and remove it), we claim it
                // if we can't open it, give up
                let mut file = ::std::fs::File::open(&filename).map_err(|_| ())?;
                let mut spid = [0u8; 11];
                file.read_exact(&mut spid).map_err(|_| ())?;
                ::std::mem::drop(file);
                let pid = ::nix::unistd::Pid::from_raw(
                    ::std::str::from_utf8(&spid)
                        .map_err(|_| ())?
                        .trim()
                        .parse::<i32>()
                        .map_err(|_| ())?,
                );
                if let Err(NixError::Sys(Errno::ESRCH)) = ::nix::sys::signal::kill(pid, None) {
                    // no process whose pid equals the contents of the lockfile exists
                    // remove the lockfile and try grabbing it again
                    if let Ok(()) = ::std::fs::remove_file(filename) {
                        debug!(log, "Lock was blocked by a defunct X11 server, trying again"; "D" => display);
                        return X11Lock::grab(display, log);
                    } else {
                        // we could not remove the lockfile, abort
                        return Err(());
                    }
                }
                // if we reach here, this lockfile exists and is probably in use, give up
                Err(())
            }
        }
    }

    pub(crate) fn display(&self) -> u32 {
        self.display
    }
}

impl Drop for X11Lock {
    fn drop(&mut self) {
        info!(self.log, "Cleaning up X11 lock.");
        // Cleanup all the X11 files
        if let Err(e) = ::std::fs::remove_file(format!("/tmp/.X11-unix/X{}", self.display)) {
            warn!(self.log, "Failed to remove X11 socket"; "error" => format!("{:?}", e));
        }
        if let Err(e) = ::std::fs::remove_file(format!("/tmp/.X{}-lock", self.display)) {
            warn!(self.log, "Failed to remove X11 lockfile"; "error" => format!("{:?}", e));
        }
    }
}

/// Open the two unix sockets an X server listens on
///
/// Should only be done after the associated lockfile is aquired!
fn open_x11_sockets_for_display(display: u32) -> NixResult<[UnixStream; 2]> {
    let path = format!("/tmp/.X11-unix/X{}", display);
    // We know this path is not to long, these unwrap cannot fail
    let fs_addr = socket::UnixAddr::new(path.as_bytes()).unwrap();
    let abs_addr = socket::UnixAddr::new_abstract(path.as_bytes()).unwrap();
    let fs_socket = open_socket(fs_addr)?;
    let abstract_socket = open_socket(abs_addr)?;
    Ok([fs_socket, abstract_socket])
}

/// Open an unix socket for listening and bind it to given path
fn open_socket(addr: socket::UnixAddr) -> NixResult<UnixStream> {
    // create an unix stream socket
    let fd = socket::socket(
        socket::AddressFamily::Unix,
        socket::SockType::Stream,
        socket::SockFlag::SOCK_CLOEXEC,
        None,
    )?;
    // bind it to requested address
    if let Err(e) = socket::bind(fd, &socket::SockAddr::Unix(addr)) {
        let _ = ::nix::unistd::close(fd);
        return Err(e);
    }
    if let Err(e) = socket::listen(fd, 1) {
        let _ = ::nix::unistd::close(fd);
        return Err(e);
    }
    Ok(unsafe { FromRawFd::from_raw_fd(fd) })
}
<|endoftext|>


<commit_before>use na::{Mat2, DMat};
use std::collections::HashMap;
use std::num::*;
use itertools::Itertools;
use std::cell::RefCell;
use std::rc::Rc;

mod test;

impl Default for DStreamProps {
    fn default() -> DStreamProps {
        DStreamProps {
            c_m: 3.0,
            c_l: 0.8,
            lambda: 0.998,
            beta: 0.3,
            i_bins: 10 as usize,
            j_bins: 10 as usize,
            i_range: (-10.0, 10.0),
            j_range: (-10.0, 10.0),
        }
    }
}
pub struct DStreamProps {
    c_m: f64,
    c_l: f64,
    lambda: f64,
    beta: f64,
    i_bins: usize,
    j_bins: usize,
    i_range: (f64, f64),
    j_range: (f64, f64),
}

#[derive(Clone)]
pub struct RawData {
    x: f64,
    y: f64,
    v: f64,
}

#[derive(Clone)]
#[derive(Debug)]
#[derive(Copy)]
struct BucketPoint {
    t: u32,
    v: f64,
}
#[derive(Clone)]
struct GridData {
    i: usize,
    j: usize,
    v: f64,
}
struct TheWorld {
    g_vec: Vec<((usize, usize), DG)>,
}

#[test]
fn test_new_put_works() {
    let raw_data_1 = RawData{x: 1.0, y: -1.0, v: 123.45};
    let raw_data_2 = RawData{x: 5.0, y: -7.0, v: 23.45};
    let raw_data_3 = RawData{x: 5.0, y: -7.0, v: 83.45};
    let raw_data_4 = RawData{x: 15.0, y: -17.0, v: 83.45};

    let rd_vec = vec!(raw_data_1, raw_data_2, raw_data_3, raw_data_4);

    let t = 1;

    let default_vec : Vec<BucketPoint> = Vec::new();
    let mut world = TheWorld{g_vec: Vec::new()};
    world.init(default_vec);
    let res1 = world.put(t, rd_vec.clone());
    let res2 = world.put(t + 1, rd_vec.clone());
    let res3 = world.put(t + 2, rd_vec.clone());

}

impl TheWorld {

    #[test]
    fn test_which_grid() {
        let loc = (-6., 6.);
        let i_rn = (-10.0, 10.0);
        let j_rn = (-10.0, 10.0);
        let i_bins = 10 as usize;
        let j_bins = 10 as usize;

        let result = TheWorld::which_grid(loc, i_rn, j_rn, i_bins, j_bins).unwrap();
        assert_eq!((2, 8), result);

    }
    fn which_grid(val: (f64, f64), i_range: (f64, f64), j_range: (f64, f64), i_bins: usize, j_bins: usize) -> Result<(usize, usize), String> {
        let i_size = (i_range.1 - i_range.0) / i_bins as f64;
        let i_number_of_sizes = ((val.0 - i_range.0) / i_size) as usize;
        let j_size = (j_range.1 - j_range.0) / j_bins as f64;
        let j_number_of_sizes = ((val.1 - j_range.0) / j_size) as usize;

        assert!(i_number_of_sizes < i_bins);
        assert!(j_number_of_sizes < j_bins);

        Ok((i_number_of_sizes, j_number_of_sizes))
    }

    fn init(&mut self, def_bucket: Vec<BucketPoint>) {
        println!("init");
        let props: DStreamProps = DStreamProps { ..Default::default() };

        for i in 0..props.i_bins {
            for j in 0..props.j_bins {
                let z_clone = def_bucket.clone();
                let some_default_dg = DG {i: i, j: j, updates_and_vals: z_clone};
                (self.g_vec).push(((i as usize, j as usize), some_default_dg));
            }
        }
    }
    fn do_time_steps() {}
    fn do_one_time_step(t: u32, data: Vec<RawData>) {}

    fn get_by_idx(&mut self, idx: (usize, usize))-> DG {
        let  vec_f: Vec<((usize, usize), DG)> = self.g_vec.clone().into_iter().filter(|i| i.0 == idx).collect();
        vec_f[0].1.clone()
    }
    fn update_by_idx(&mut self, idx: (usize, usize), dg: DG) -> Result<(), String> {
        self.g_vec.retain(|i| i.0 != idx);
        self.g_vec.push((idx, dg));
        Ok(())
    }
    fn put(&mut self, t: u32, dat: Vec<RawData>) -> Result<(), String> {

        fn validate_range(loc2d: (f64, f64)) -> bool {

            let props: DStreamProps = DStreamProps { ..Default::default() };

            if ((loc2d.0 <= props.i_range.1) &&
            (loc2d.0 >= props.i_range.0) &&
            (loc2d.1 <= props.j_range.1) &&
            (loc2d.1 >= props.j_range.0)) {
                println!("valid!");
            } else {
                println!("invalid! -- bad input range");
                return false
            }
            return true
        }
        let with_idxs: Vec<GridData> = dat
            .iter()
            .filter(|rd| validate_range((rd.x, rd.y)))
            .map(|rd| self.which_idxs(rd).unwrap())
            .collect();

        let props: DStreamProps = DStreamProps { ..Default::default() };

        for (key, group) in with_idxs.iter().group_by(|gd| (gd.i, gd.j)) {
            println!("--put: key, g size: ({},{}) : {}", key.0, key.1, group.len());

            let the_vec_of_vals: Vec<f64> = group.iter().map(|t| t.v).collect();

            let mut some_default_dg = DG {i: key.0, j: key.1, updates_and_vals: Vec::<BucketPoint>::new()};

            let teh_dg: &mut DG = &mut self.get_by_idx(key);
            let update_dg_result = teh_dg.update(t, the_vec_of_vals);
            let udpate_world_result = self.update_by_idx(key, teh_dg.clone());
        }
        Ok(())
    }
    fn which_idxs(&self, dat: &RawData) -> Result<GridData, String> {

        let props: DStreamProps = DStreamProps { ..Default::default() };

        let idxs = TheWorld::which_grid((dat.x, dat.y), props.i_range, props.j_range,props.i_bins, props.j_bins).unwrap();

        Ok((GridData{i:idxs.0,j:idxs.1,v:dat.v}))

    }
}

#[test]
fn test_dg_update_and_get() {
    let mut dg = DG {i: 0, j:0, updates_and_vals: Vec::new()};
    dg.update(1, vec!(100.0));
    dg.update(10, vec!(200.0));
    dg.update(20, vec!(300.0));
    let v_at_t = dg.get_at_time(30);
    println!("v: {}", v_at_t);
}

#[derive(Debug)]
#[derive(Clone)]
//#[derive(Copy)] TODO: how to make this work?
struct DG {
    i: usize,
    j: usize,
    updates_and_vals: Vec<BucketPoint>,
}
impl DG {
    fn get_at_time(&self, t: u32) -> f64 {
        let last_update_time_and_value = self.get_last_update_and_value_to(t);
        let coeff = self.coeff(t, last_update_time_and_value.0);
        let d = coeff * last_update_time_and_value.1 + 1.0;

        d
    }
    fn update(&mut self, t: u32, vals: Vec<f64>) -> Result<(), String> {
        let sum = vals.clone().iter().fold(0.0, |sum, x| sum + x);
        self.updates_and_vals.push(BucketPoint {t: t, v: sum});
        println!("  times updated dg: {}", self.updates_and_vals.len());
        Ok(())
    }

    fn get_last_update_and_value_to(&self, t: u32) -> (u32, f64) {
        let a: BucketPoint = self.updates_and_vals.clone().into_iter().filter(|bp| bp.t < t).max_by_key(|bp| bp.t).unwrap();
        let t_l = a.t;
        let v_l = a.v;
        println!("last update relative to {} is (t: {}, v: {})", t, t_l, v_l);
        (t_l, v_l)
    }

    fn coeff(&self, t_n: u32, t_l: u32) -> f64 {
        let props: DStreamProps = DStreamProps { ..Default::default() };
        props.lambda.powf((t_n - t_l) as f64)
    }

 }

#[test]
fn test_initialize_clustering() {

    let result = initialize_clustering(Vec::new());
    assert_eq!(Ok(()), result);
}

pub fn initialize_clustering(grid_list: Vec<RawData>) -> Result<(), String> {
    //update density of all grids in grid_list
    //assign each dense grid to a distinct cluster
    //label all other grids as NO_CLASS; bad grids!
    /*
    do until no change in cluster labels
          foreach cluster c
            foreach outside grid g of c
                foreach neighboring grid h of g
                    if h belongs to cluster c'
                        if |c| > |c'| label all grids in c' as c
                        else label all grids in c as c'
                    else if (h is translational) label h as in c
    end do
    */
    Ok(())
}

pub fn adjust_clustering(grid_list: Vec<RawData>) -> Result<(), String> {
    //update the density of all grids in grid_list
    /*
    foreach grid g whose attribute (dense/sparse/transitional) is changed since last call to adjust_clustering()
        if g is a sparse grid
            delete g from its cluster c, label g as NO_CLASS
            if (c becomes unconnected) split c into two clusters
        else if g is a dense grid
            among all neighboring grids of g, find out the grid h whoe cluster c_h has the largest size
            if h is a dense grid
                if (g is labelled as NO_CLASS) label g as in c_h
                else if (g is in cluster c and |c| > |c_h|)
                    label all grids in c_h as in c
                else if (g is in cluster c and |c| <= |c_h|)
                    label all grids in c as in c_h
            else if h is a transitional grid
                if ((g is NO_CLASS) and (h is an outside grid if g is added to c_h)) label g as in c_h
                else if (g is in cluster c and |c| >= |c_h|)
                    move h from cluster c_h to c
        else if (g is transitional grid)
            among neighboring clusters of g, find the largest one c'
            satisfying that g is an outside grid if added to it and
            label g as in c'
    */

    Ok(())
}<commit_msg>assert on last update vals<commit_after>use na::{Mat2, DMat};
use std::collections::HashMap;
use std::num::*;
use itertools::Itertools;
use std::cell::RefCell;
use std::rc::Rc;

mod test;

impl Default for DStreamProps {
    fn default() -> DStreamProps {
        DStreamProps {
            c_m: 3.0,
            c_l: 0.8,
            lambda: 0.998,
            beta: 0.3,
            i_bins: 10 as usize,
            j_bins: 10 as usize,
            i_range: (-10.0, 10.0),
            j_range: (-10.0, 10.0),
        }
    }
}
pub struct DStreamProps {
    c_m: f64,
    c_l: f64,
    lambda: f64,
    beta: f64,
    i_bins: usize,
    j_bins: usize,
    i_range: (f64, f64),
    j_range: (f64, f64),
}

#[derive(Clone)]
pub struct RawData {
    x: f64,
    y: f64,
    v: f64,
}

#[derive(Clone)]
#[derive(Debug)]
#[derive(Copy)]
struct BucketPoint {
    t: u32,
    v: f64,
}
#[derive(Clone)]
struct GridData {
    i: usize,
    j: usize,
    v: f64,
}
struct TheWorld {
    g_vec: Vec<((usize, usize), DG)>,
}

#[test]
fn test_new_put_works() {
    let raw_data_1 = RawData{x: 1.0, y: -1.0, v: 123.45};
    let raw_data_2 = RawData{x: 5.0, y: -7.0, v: 23.45};
    let raw_data_3 = RawData{x: 5.0, y: -7.0, v: 83.45};
    let raw_data_4 = RawData{x: 15.0, y: -17.0, v: 83.45};

    let rd_vec = vec!(raw_data_1, raw_data_2, raw_data_3, raw_data_4);

    let t = 1;

    let default_vec : Vec<BucketPoint> = Vec::new();
    let mut world = TheWorld{g_vec: Vec::new()};
    world.init(default_vec);
    let res1 = world.put(t, rd_vec.clone());
    let res2 = world.put(t + 1, rd_vec.clone());
    let res3 = world.put(t + 2, rd_vec.clone());

}

impl TheWorld {

    #[test]
    fn test_which_grid() {
        let loc = (-6., 6.);
        let i_rn = (-10.0, 10.0);
        let j_rn = (-10.0, 10.0);
        let i_bins = 10 as usize;
        let j_bins = 10 as usize;

        let result = TheWorld::which_grid(loc, i_rn, j_rn, i_bins, j_bins).unwrap();
        assert_eq!((2, 8), result);

    }
    fn which_grid(val: (f64, f64), i_range: (f64, f64), j_range: (f64, f64), i_bins: usize, j_bins: usize) -> Result<(usize, usize), String> {
        let i_size = (i_range.1 - i_range.0) / i_bins as f64;
        let i_number_of_sizes = ((val.0 - i_range.0) / i_size) as usize;
        let j_size = (j_range.1 - j_range.0) / j_bins as f64;
        let j_number_of_sizes = ((val.1 - j_range.0) / j_size) as usize;

        assert!(i_number_of_sizes < i_bins);
        assert!(j_number_of_sizes < j_bins);

        Ok((i_number_of_sizes, j_number_of_sizes))
    }

    fn init(&mut self, def_bucket: Vec<BucketPoint>) {
        println!("init");
        let props: DStreamProps = DStreamProps { ..Default::default() };

        for i in 0..props.i_bins {
            for j in 0..props.j_bins {
                let z_clone = def_bucket.clone();
                let some_default_dg = DG {i: i, j: j, updates_and_vals: z_clone};
                (self.g_vec).push(((i as usize, j as usize), some_default_dg));
            }
        }
    }
    fn do_time_steps() {}
    fn do_one_time_step(t: u32, data: Vec<RawData>) {}

    fn get_by_idx(&mut self, idx: (usize, usize))-> DG {
        let  vec_f: Vec<((usize, usize), DG)> = self.g_vec.clone().into_iter().filter(|i| i.0 == idx).collect();
        vec_f[0].1.clone()
    }
    fn update_by_idx(&mut self, idx: (usize, usize), dg: DG) -> Result<(), String> {
        self.g_vec.retain(|i| i.0 != idx);
        self.g_vec.push((idx, dg));
        Ok(())
    }
    fn put(&mut self, t: u32, dat: Vec<RawData>) -> Result<(), String> {

        fn validate_range(loc2d: (f64, f64)) -> bool {

            let props: DStreamProps = DStreamProps { ..Default::default() };

            if ((loc2d.0 <= props.i_range.1) &&
            (loc2d.0 >= props.i_range.0) &&
            (loc2d.1 <= props.j_range.1) &&
            (loc2d.1 >= props.j_range.0)) {
                println!("valid!");
            } else {
                println!("invalid! -- bad input range");
                return false
            }
            return true
        }
        let with_idxs: Vec<GridData> = dat
            .iter()
            .filter(|rd| validate_range((rd.x, rd.y)))
            .map(|rd| self.which_idxs(rd).unwrap())
            .collect();

        let props: DStreamProps = DStreamProps { ..Default::default() };

        for (key, group) in with_idxs.iter().group_by(|gd| (gd.i, gd.j)) {
            println!("--put: key, g size: ({},{}) : {}", key.0, key.1, group.len());

            let the_vec_of_vals: Vec<f64> = group.iter().map(|t| t.v).collect();

            let mut some_default_dg = DG {i: key.0, j: key.1, updates_and_vals: Vec::<BucketPoint>::new()};

            let teh_dg: &mut DG = &mut self.get_by_idx(key);
            let update_dg_result = teh_dg.update(t, the_vec_of_vals);
            let udpate_world_result = self.update_by_idx(key, teh_dg.clone());
        }
        Ok(())
    }
    fn which_idxs(&self, dat: &RawData) -> Result<GridData, String> {

        let props: DStreamProps = DStreamProps { ..Default::default() };

        let idxs = TheWorld::which_grid((dat.x, dat.y), props.i_range, props.j_range,props.i_bins, props.j_bins).unwrap();

        Ok((GridData{i:idxs.0,j:idxs.1,v:dat.v}))

    }
}

#[test]
fn test_dg_update_and_get() {
    let mut dg = DG {i: 0, j:0, updates_and_vals: Vec::new()};
    dg.update(1, vec!(100.0));

    dg.update(10, vec!(200.0));
    dg.update(20, vec!(300.0));

    assert_eq!((1, 100.0), dg.get_last_update_and_value_to(2));
    assert_eq!((10, 200.0), dg.get_last_update_and_value_to(14));
    assert_eq!((20, 300.0), dg.get_last_update_and_value_to(22));

    let v_at_t = dg.get_at_time(30);
    println!("v: {}", v_at_t);
}

#[derive(Debug)]
#[derive(Clone)]
//#[derive(Copy)] TODO: how to make this work?
struct DG {
    i: usize,
    j: usize,
    updates_and_vals: Vec<BucketPoint>,
}
impl DG {
    fn get_at_time(&self, t: u32) -> f64 {
        let last_update_time_and_value = self.get_last_update_and_value_to(t);
        let coeff = self.coeff(t, last_update_time_and_value.0);
        coeff * last_update_time_and_value.1 + 1.0
    }
    fn update(&mut self, t: u32, vals: Vec<f64>) -> Result<(), String> {
        let sum = vals.clone().iter().fold(0.0, |sum, x| sum + x);
        self.updates_and_vals.push(BucketPoint {t: t, v: sum});
        println!("  times updated dg: {}", self.updates_and_vals.len());
        Ok(())
    }

    fn get_last_update_and_value_to(&self, t: u32) -> (u32, f64) {
        let a: BucketPoint = self.updates_and_vals.clone().into_iter().filter(|bp| bp.t < t).max_by_key(|bp| bp.t).unwrap();
        let t_l = a.t;
        let v_l = a.v;
        println!("  last update relative to {} is (t: {}, v: {})", t, t_l, v_l);
        (t_l, v_l)
    }

    fn coeff(&self, t_n: u32, t_l: u32) -> f64 {
        let props: DStreamProps = DStreamProps { ..Default::default() };
        props.lambda.powf((t_n - t_l) as f64)
    }

 }

#[test]
fn test_initialize_clustering() {

    let result = initialize_clustering(Vec::new());
    assert_eq!(Ok(()), result);
}

pub fn initialize_clustering(grid_list: Vec<RawData>) -> Result<(), String> {
    //update density of all grids in grid_list
    //assign each dense grid to a distinct cluster
    //label all other grids as NO_CLASS; bad grids!
    /*
    do until no change in cluster labels
          foreach cluster c
            foreach outside grid g of c
                foreach neighboring grid h of g
                    if h belongs to cluster c'
                        if |c| > |c'| label all grids in c' as c
                        else label all grids in c as c'
                    else if (h is translational) label h as in c
    end do
    */
    Ok(())
}

pub fn adjust_clustering(grid_list: Vec<RawData>) -> Result<(), String> {
    //update the density of all grids in grid_list
    /*
    foreach grid g whose attribute (dense/sparse/transitional) is changed since last call to adjust_clustering()
        if g is a sparse grid
            delete g from its cluster c, label g as NO_CLASS
            if (c becomes unconnected) split c into two clusters
        else if g is a dense grid
            among all neighboring grids of g, find out the grid h whoe cluster c_h has the largest size
            if h is a dense grid
                if (g is labelled as NO_CLASS) label g as in c_h
                else if (g is in cluster c and |c| > |c_h|)
                    label all grids in c_h as in c
                else if (g is in cluster c and |c| <= |c_h|)
                    label all grids in c as in c_h
            else if h is a transitional grid
                if ((g is NO_CLASS) and (h is an outside grid if g is added to c_h)) label g as in c_h
                else if (g is in cluster c and |c| >= |c_h|)
                    move h from cluster c_h to c
        else if (g is transitional grid)
            among neighboring clusters of g, find the largest one c'
            satisfying that g is an outside grid if added to it and
            label g as in c'
    */

    Ok(())
}<|endoftext|>