<commit_before>use std::char;
use std::num::ParseIntError;
use std::str::{self, FromStr};

use nom::{
    digit,
    is_alphanumeric,
    IResult
};

/// Parsed StatsD metric.
///
/// See here for more details: https://github.com/b/statsd_spec#metric-types--formats
#[derive(Debug, PartialEq)]
pub enum ParsedMetric {
    Gauge(String, u64),
    Counter(String, u64),
}

pub type ParseResult<'a> = IResult<&'a [u8], ParsedMetric>;

fn bytes_to_u64(i: &[u8]) -> Result<u64, ParseIntError> {
    let s = str::from_utf8(i).unwrap();

    u64::from_str(s)
}

pub fn parse_gauge(i: &[u8]) -> ParseResult {
    chain!(i,
        name: parse_metric_name ~ tag!(":")  ~
        value: parse_value      ~ tag!("|g") ,

        ||{ ParsedMetric::Gauge(name, value) }
    )
}

pub fn parse_counter(i: &[u8]) -> ParseResult {
    chain!(i,
        name: parse_metric_name ~ tag!(":")  ~
        value: parse_value      ~ tag!("|c") ~
        sample_rate: opt!(complete!(parse_sample_rate)) ,

        ||{ ParsedMetric::Counter(name, value) }
    )
}

pub fn parse_value(i: &[u8]) -> IResult<&[u8], u64> {
    map_res!(i,
        digit,
        |value| { bytes_to_u64(value) }
    )
}

pub fn parse_sample_rate(i: &[u8]) -> IResult<&[u8], u64> {
    preceded!(i,
        tag!("|@"),
        map_res!(digit, |rate| { bytes_to_u64(rate) })
    )
}

fn parse_metric_name(i: &[u8]) -> IResult<&[u8], String> {
    #[inline]
    fn is_metric_name_char(i: u8) -> bool {
        let c = char::from_u32(i as u32).unwrap();

        is_alphanumeric(i) || c == '.' || c == '_'
    }

    map!(i,
        take_while!(is_metric_name_char),
        |name| { String::from_utf8_lossy(name).into_owned() }
    )
}

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

    use std::any::Any;
    use nom::IResult;

    fn complete<'a, T>(value: T) -> IResult<&'a [u8], T>
        where T: Any {
        IResult::Done(&b""[..], value)
    }

    #[test]
    fn it_parses_gauge() {
        assert_eq!(
            parse_gauge(&b"foo.bar_baz:12|g"[..]),
            complete(ParsedMetric::Gauge("foo.bar_baz".to_owned(), 12))
        )
    }

    #[test]
    fn it_parses_counter() {
        assert_eq!(
            parse_counter(&b"foo.bar_baz:23|c"[..]),
            complete(ParsedMetric::Counter("foo.bar_baz".to_owned(), 23))
        )
    }

    #[test]
    fn it_parses_counter_with_sample_rate() {
        assert_eq!(
            parse_counter(&b"foo.bar_baz:34|c|@5"[..]),
            complete(ParsedMetric::Counter("foo.bar_baz".to_owned(), 34))
        )
    }
}
<commit_msg>Add parsing of StatsD timers<commit_after>use std::char;
use std::num::ParseIntError;
use std::str::{self, FromStr};

use nom::{
    digit,
    is_alphanumeric,
    IResult
};

/// Parsed StatsD metric.
///
/// See here for more details: https://github.com/b/statsd_spec#metric-types--formats
#[derive(Debug, PartialEq)]
pub enum ParsedMetric {
    Counter(String, u64),
    Gauge(String, u64),
    Timer(String, u64),
}

pub type ParseResult<'a> = IResult<&'a [u8], ParsedMetric>;

fn bytes_to_u64(i: &[u8]) -> Result<u64, ParseIntError> {
    let s = str::from_utf8(i).unwrap();

    u64::from_str(s)
}

pub fn parse_counter(i: &[u8]) -> ParseResult {
    chain!(i,
        name: parse_metric_name ~ tag!(":")  ~
        value: parse_value      ~ tag!("|c") ~
        sample_rate: opt!(complete!(parse_sample_rate)) ,

        ||{ ParsedMetric::Counter(name, value) }
    )
}

pub fn parse_gauge(i: &[u8]) -> ParseResult {
    chain!(i,
        name: parse_metric_name ~ tag!(":")  ~
        value: parse_value      ~ tag!("|g") ,

        ||{ ParsedMetric::Gauge(name, value) }
    )
}

pub fn parse_timer(i: &[u8]) -> ParseResult {
    chain!(i,
        name: parse_metric_name ~ tag!(":")  ~
        value: parse_value      ~ tag!("|ms") ,

        ||{ ParsedMetric::Timer(name, value) }
    )
}

pub fn parse_value(i: &[u8]) -> IResult<&[u8], u64> {
    map_res!(i,
        digit,
        |value| { bytes_to_u64(value) }
    )
}

pub fn parse_sample_rate(i: &[u8]) -> IResult<&[u8], u64> {
    preceded!(i,
        tag!("|@"),
        map_res!(digit, |rate| { bytes_to_u64(rate) })
    )
}

fn parse_metric_name(i: &[u8]) -> IResult<&[u8], String> {
    #[inline]
    fn is_metric_name_char(i: u8) -> bool {
        let c = char::from_u32(i as u32).unwrap();

        is_alphanumeric(i) || c == '.' || c == '_'
    }

    map!(i,
        take_while!(is_metric_name_char),
        |name| { String::from_utf8_lossy(name).into_owned() }
    )
}

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

    use std::any::Any;
    use nom::IResult;

    fn complete<'a, T>(value: T) -> IResult<&'a [u8], T>
        where T: Any {
        IResult::Done(&b""[..], value)
    }

    #[test]
    fn it_parses_gauge() {
        assert_eq!(
            parse_gauge(&b"foo.bar_baz:12|g"[..]),
            complete(ParsedMetric::Gauge("foo.bar_baz".to_owned(), 12))
        )
    }

    #[test]
    fn it_parses_counter() {
        assert_eq!(
            parse_counter(&b"foo.bar_baz:23|c"[..]),
            complete(ParsedMetric::Counter("foo.bar_baz".to_owned(), 23))
        )
    }

    #[test]
    fn it_parses_counter_with_sample_rate() {
        assert_eq!(
            parse_counter(&b"foo.bar_baz:34|c|@5"[..]),
            complete(ParsedMetric::Counter("foo.bar_baz".to_owned(), 34))
        )
    }

    #[test]
    fn it_parses_timer() {
        assert_eq!(
            parse_timer(&b"foo.bar_baz:12|ms"[..]),
            complete(ParsedMetric::Timer("foo.bar_baz".to_owned(), 12))
        )
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::ops::Deref;
use std::fmt;

use serde::{Serialize, Deserialize, Serializer, Deserializer};

bitflags! {
    pub flags FieldFlags: u32 {
        const FIELD_INDEXED = 0b00000001,
        const FIELD_STORED  = 0b00000010,
    }
}

impl Serialize for FieldFlags {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        let mut flag_strings = Vec::new();

        if self.contains(FIELD_INDEXED) {
            flag_strings.push("INDEXED");
        }

        if self.contains(FIELD_STORED) {
            flag_strings.push("STORED");
        }

        serializer.serialize_str(&flag_strings.join("|"))
    }
}

impl Deserialize for FieldFlags {
    fn deserialize<D>(deserializer: D) -> Result<FieldFlags, D::Error>
        where D: Deserializer
    {
        struct Visitor;

        impl ::serde::de::Visitor for Visitor {
            type Value = FieldFlags;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("a string of flag names separated by a '|' character")
            }

            fn visit_str<E>(self, value: &str) -> Result<FieldFlags, E>
                where E: ::serde::de::Error
            {
                let mut flags = FieldFlags::empty();

                for flag_s in value.split("|") {
                    match flag_s {
                        "INDEXED" => {
                            flags |= FIELD_INDEXED;
                        }
                        "STORED" => {
                            flags |= FIELD_STORED;
                        }
                        _ => {} // TODO: error
                    }
                }

                Ok(flags)
            }
        }

        deserializer.deserialize_str(Visitor)
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum FieldType {
    Text,
    PlainString,
    I64,
    Boolean,
    DateTime,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FieldInfo {
    name: String,
    pub field_type: FieldType,
    pub field_flags: FieldFlags,
}

impl FieldInfo {
    pub fn new(name: String, field_type: FieldType, field_flags: FieldFlags) -> FieldInfo {
        FieldInfo {
            name: name,
            field_type: field_type,
            field_flags: field_flags,
        }
    }
}

#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct FieldRef(u32);

impl FieldRef {
    pub fn new(ord: u32) -> FieldRef {
        FieldRef(ord)
    }

    pub fn ord(&self) -> u32 {
        self.0
    }
}

/*
impl Serialize for FieldRef {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        serializer.serialize_i32(self.ord);
    }
}

impl Deserialize for FieldRef {
    fn deserialize<D>(deserializer: D) -> Result<FieldRef, D::Error>
        where D: Deserializer
    {
        Ok(FieldRef(try!(deserializer.deserialize_i32())))
    }
}
*/

#[derive(Debug)]
pub enum AddFieldError {
    FieldAlreadyExists(String),
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Schema {
    next_field_id: u32,
    fields: HashMap<FieldRef, FieldInfo>,
    field_names: HashMap<String, FieldRef>,
}

impl Schema {
    pub fn new() -> Schema {
        Schema {
            next_field_id: 1,
            fields: HashMap::new(),
            field_names: HashMap::new(),
        }
    }

    fn new_field_ref(&mut self) -> FieldRef {
        let field_ref = FieldRef(self.next_field_id);
        self.next_field_id += 1;

        field_ref
    }

    pub fn get_field_by_name(&self, name: &str) -> Option<FieldRef> {
        self.field_names.get(name).cloned()
    }

    pub fn add_field(&mut self, name: String, field_type: FieldType, field_flags: FieldFlags) -> Result<FieldRef, AddFieldError> {
        if self.field_names.contains_key(&name) {
            return Err(AddFieldError::FieldAlreadyExists(name));
        }

        let field_ref = self.new_field_ref();
        let field_info = FieldInfo::new(name.clone(), field_type, field_flags);

        self.fields.insert(field_ref, field_info);
        self.field_names.insert(name, field_ref);

        Ok(field_ref)
    }

    pub fn remove_field(&mut self, field_ref: &FieldRef) -> bool {
        match self.fields.remove(field_ref) {
            Some(removed_field) => {
                self.field_names.remove(&removed_field.name);
                true
            }
            None => false
        }
    }
}

impl Deref for Schema {
    type Target = HashMap<FieldRef, FieldInfo>;

    fn deref(&self) -> &HashMap<FieldRef, FieldInfo> {
        &self.fields
    }
}
<commit_msg>Removed unused code<commit_after>use std::collections::HashMap;
use std::ops::Deref;
use std::fmt;

use serde::{Serialize, Deserialize, Serializer, Deserializer};

bitflags! {
    pub flags FieldFlags: u32 {
        const FIELD_INDEXED = 0b00000001,
        const FIELD_STORED  = 0b00000010,
    }
}

impl Serialize for FieldFlags {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        let mut flag_strings = Vec::new();

        if self.contains(FIELD_INDEXED) {
            flag_strings.push("INDEXED");
        }

        if self.contains(FIELD_STORED) {
            flag_strings.push("STORED");
        }

        serializer.serialize_str(&flag_strings.join("|"))
    }
}

impl Deserialize for FieldFlags {
    fn deserialize<D>(deserializer: D) -> Result<FieldFlags, D::Error>
        where D: Deserializer
    {
        struct Visitor;

        impl ::serde::de::Visitor for Visitor {
            type Value = FieldFlags;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("a string of flag names separated by a '|' character")
            }

            fn visit_str<E>(self, value: &str) -> Result<FieldFlags, E>
                where E: ::serde::de::Error
            {
                let mut flags = FieldFlags::empty();

                for flag_s in value.split("|") {
                    match flag_s {
                        "INDEXED" => {
                            flags |= FIELD_INDEXED;
                        }
                        "STORED" => {
                            flags |= FIELD_STORED;
                        }
                        _ => {} // TODO: error
                    }
                }

                Ok(flags)
            }
        }

        deserializer.deserialize_str(Visitor)
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum FieldType {
    Text,
    PlainString,
    I64,
    Boolean,
    DateTime,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FieldInfo {
    name: String,
    pub field_type: FieldType,
    pub field_flags: FieldFlags,
}

impl FieldInfo {
    pub fn new(name: String, field_type: FieldType, field_flags: FieldFlags) -> FieldInfo {
        FieldInfo {
            name: name,
            field_type: field_type,
            field_flags: field_flags,
        }
    }
}

#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct FieldRef(u32);

impl FieldRef {
    pub fn new(ord: u32) -> FieldRef {
        FieldRef(ord)
    }

    pub fn ord(&self) -> u32 {
        self.0
    }
}

#[derive(Debug)]
pub enum AddFieldError {
    FieldAlreadyExists(String),
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Schema {
    next_field_id: u32,
    fields: HashMap<FieldRef, FieldInfo>,
    field_names: HashMap<String, FieldRef>,
}

impl Schema {
    pub fn new() -> Schema {
        Schema {
            next_field_id: 1,
            fields: HashMap::new(),
            field_names: HashMap::new(),
        }
    }

    fn new_field_ref(&mut self) -> FieldRef {
        let field_ref = FieldRef(self.next_field_id);
        self.next_field_id += 1;

        field_ref
    }

    pub fn get_field_by_name(&self, name: &str) -> Option<FieldRef> {
        self.field_names.get(name).cloned()
    }

    pub fn add_field(&mut self, name: String, field_type: FieldType, field_flags: FieldFlags) -> Result<FieldRef, AddFieldError> {
        if self.field_names.contains_key(&name) {
            return Err(AddFieldError::FieldAlreadyExists(name));
        }

        let field_ref = self.new_field_ref();
        let field_info = FieldInfo::new(name.clone(), field_type, field_flags);

        self.fields.insert(field_ref, field_info);
        self.field_names.insert(name, field_ref);

        Ok(field_ref)
    }

    pub fn remove_field(&mut self, field_ref: &FieldRef) -> bool {
        match self.fields.remove(field_ref) {
            Some(removed_field) => {
                self.field_names.remove(&removed_field.name);
                true
            }
            None => false
        }
    }
}

impl Deref for Schema {
    type Target = HashMap<FieldRef, FieldInfo>;

    fn deref(&self) -> &HashMap<FieldRef, FieldInfo> {
        &self.fields
    }
}
<|endoftext|>


<commit_before>use std::mem;

struct Point {
    x: f64,
    y: f64,
}

struct Rectangle {
    p1: Point,
    p2: Point,
}

fn origin() -> Point {
    Point { x: 0.0, y: 0.0 }
}

fn boxed_origin() -> Box<Point> {
    // Allocate this point in the heap, and return a pointer to it
    box Point { x: 0.0, y: 0.0 }
}

fn main() {
    // (all the type annotations are superfluous)
    // Stack allocated variables
    let point: Point = origin();
    let rectangle: Rectangle = Rectangle {
        p1: origin(),
        p2: Point { x: 3.0, y: 4.0 }
    };

    // Heap allocated rectangle
    let boxed_rectangle: Box<Rectangle> = box Rectangle {
        p1: origin(),
        p2: origin()
    };

    // The output of functions can be boxed
    let boxed_point: Box<Point> = box origin();

    // Double indirection
    let box_in_a_box: Box<Box<Point>> = box boxed_origin();

    println!("Point occupies {} bytes in the stack",
             mem::size_of_val(&point));
    println!("Rectangle occupies {} bytes in the stack",
             mem::size_of_val(&rectangle));

    // box size = pointer size
    println!("Boxed point occupies {} bytes in the stack",
             mem::size_of_val(&boxed_point));
    println!("Boxed rectangle occupies {} bytes in the stack",
             mem::size_of_val(&boxed_rectangle));
    println!("Boxed box occupies {} bytes in the stack",
             mem::size_of_val(&box_in_a_box));

    // Copy the data contained in `boxed_point` into `unboxed_point`
    let unboxed_point: Point = *boxed_point;
    println!("Unboxed point occupies {} bytes in the stack",
             mem::size_of_val(&unboxed_point));

    // Unboxing via a destructuring pattern
    let box another_unboxed_point = boxed_point;
    println!("Another unboxed point occupies {} bytes in the stack",
             mem::size_of_val(&another_unboxed_point));
}
<commit_msg>box: suppress warnings<commit_after>use std::mem;

#[allow(dead_code)]
struct Point {
    x: f64,
    y: f64,
}

#[allow(dead_code)]
struct Rectangle {
    p1: Point,
    p2: Point,
}

fn origin() -> Point {
    Point { x: 0.0, y: 0.0 }
}

fn boxed_origin() -> Box<Point> {
    // Allocate this point in the heap, and return a pointer to it
    box Point { x: 0.0, y: 0.0 }
}

fn main() {
    // (all the type annotations are superfluous)
    // Stack allocated variables
    let point: Point = origin();
    let rectangle: Rectangle = Rectangle {
        p1: origin(),
        p2: Point { x: 3.0, y: 4.0 }
    };

    // Heap allocated rectangle
    let boxed_rectangle: Box<Rectangle> = box Rectangle {
        p1: origin(),
        p2: origin()
    };

    // The output of functions can be boxed
    let boxed_point: Box<Point> = box origin();

    // Double indirection
    let box_in_a_box: Box<Box<Point>> = box boxed_origin();

    println!("Point occupies {} bytes in the stack",
             mem::size_of_val(&point));
    println!("Rectangle occupies {} bytes in the stack",
             mem::size_of_val(&rectangle));

    // box size = pointer size
    println!("Boxed point occupies {} bytes in the stack",
             mem::size_of_val(&boxed_point));
    println!("Boxed rectangle occupies {} bytes in the stack",
             mem::size_of_val(&boxed_rectangle));
    println!("Boxed box occupies {} bytes in the stack",
             mem::size_of_val(&box_in_a_box));

    // Copy the data contained in `boxed_point` into `unboxed_point`
    let unboxed_point: Point = *boxed_point;
    println!("Unboxed point occupies {} bytes in the stack",
             mem::size_of_val(&unboxed_point));

    // Unboxing via a destructuring pattern
    let box another_unboxed_point = boxed_point;
    println!("Another unboxed point occupies {} bytes in the stack",
             mem::size_of_val(&another_unboxed_point));
}
<|endoftext|>


<commit_before>use cssparser;
use libc;

use parsers::Parse;
use parsers::ParseError;
use error::*;
use util::utf8_cstr;

// There are two quirks here:
//
// First, we need to expose the Color algebraic type *and* a parse
// error to C, but we can't repr(C) them plainly.  So, we define a
// ColorKind enum and a ColorSpec struct that can both be represented
// in C.
//
// Second, the C code in librsvg expects ARGB colors passed around as
// guint32.  However, in Rust we'd prefer to use cssparser's RGBA
// structure, which has explicit fields for red/green/blue/alpha.
// We'll do those conversions here, for the benefit of the C code, and
// then just wait until the C code gradually disappears.

// Keep this in sync with rsvg-css.h:RsvgCssColorKind
#[repr(C)]
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ColorKind {
    Inherit,
    CurrentColor,
    ARGB,
    ParseError
}

// Keep this in sync with rsvg-css.h:RsvgCssColorSpec
#[repr(C)]
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct ColorSpec {
    kind: ColorKind,
    argb: u32
}

// Keep in sync with rsvg-css.h:AllowInherit
#[repr(C)]
#[derive(PartialEq, Debug)]
pub enum AllowInherit {
    No,
    Yes
}

// Keep in sync with rsvg-css.h:AllowCurrentColor
#[repr(C)]
#[derive(PartialEq, Debug)]
pub enum AllowCurrentColor {
    No,
    Yes
}

// This is the Rust version of the above
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum Color {
    Inherit,
    CurrentColor,
    RGBA (cssparser::RGBA)
}

impl Parse for Color {
    type Data = (AllowInherit, AllowCurrentColor);
    type Err = AttributeError;

    fn parse (s: &str, (allow_inherit, allow_current_color): (AllowInherit, AllowCurrentColor)) -> Result<Color, AttributeError> {
        if s == "inherit" {
            if allow_inherit == AllowInherit::Yes {
                Ok (Color::Inherit)
            } else {
                Err (AttributeError::Value ("inherit is not allowed here".to_string ()))
            }
        } else {
            let mut input = cssparser::ParserInput::new (s);
            match cssparser::Color::parse (&mut cssparser::Parser::new (&mut input)) {
                Ok (cssparser::Color::CurrentColor) => {
                    if allow_current_color == AllowCurrentColor::Yes {
                        Ok (Color::CurrentColor)
                    } else {
                        Err (AttributeError::Value ("currentColor is not allowed here".to_string ()))
                    }
                },

                Ok (csscolor) => Ok (Color::from (csscolor)),

                _ => Err (AttributeError::Parse (ParseError::new ("invalid syntax for color")))
            }
        }
    }

}

impl Color {
    pub fn from_color_spec (spec: &ColorSpec) -> Result <Color, AttributeError> {
        match *spec {
            ColorSpec { kind: ColorKind::Inherit, .. }      => Ok (Color::Inherit),

            ColorSpec { kind: ColorKind::CurrentColor, .. } => Ok (Color::CurrentColor),

            ColorSpec { kind: ColorKind::ARGB, argb } => Ok (Color::RGBA (rgba_from_argb (argb))),

            ColorSpec { kind: ColorKind::ParseError, .. } => Err (AttributeError::Parse (ParseError::new ("parse error")))
        }
    }
}

fn rgba_from_argb (argb: u32) -> cssparser::RGBA {
    cssparser::RGBA::new (((argb & 0x00ff_0000) >> 16) as u8,
                          ((argb & 0x0000_ff00) >> 8) as u8,
                          ((argb & 0x0000_00ff) as u8),
                          ((argb & 0xff00_0000) >> 24) as u8)
}

impl From<cssparser::Color> for Color {
    fn from (c: cssparser::Color) -> Color {
        match c {
            cssparser::Color::CurrentColor => Color::CurrentColor,
            cssparser::Color::RGBA (rgba) => Color::RGBA (rgba)
        }
    }
}

impl From<u32> for Color {
    fn from (argb: u32) -> Color {
        Color::RGBA (rgba_from_argb (argb))
    }
}

impl From<Result<Color, AttributeError>> for ColorSpec {
    fn from (result: Result<Color, AttributeError>) -> ColorSpec {
        match result {
            Ok (Color::Inherit) =>
                ColorSpec {
                    kind: ColorKind::Inherit,
                    argb: 0
                },

            Ok (Color::CurrentColor) =>
                ColorSpec {
                    kind: ColorKind::CurrentColor,
                    argb: 0
                },

            Ok (Color::RGBA (rgba)) =>
                ColorSpec {
                    kind: ColorKind::ARGB,
                    argb: (u32::from(rgba.alpha) << 24 |
                           u32::from(rgba.red)   << 16 |
                           u32::from(rgba.green) << 8  |
                           u32::from(rgba.blue))
                },

            _ =>
                ColorSpec {
                    kind: ColorKind::ParseError,
                    argb: 0
                }
        }
    }
}

#[no_mangle]
pub extern fn rsvg_css_parse_color (string: *const libc::c_char,
                                    allow_inherit: AllowInherit,
                                    allow_current_color: AllowCurrentColor) -> ColorSpec {
    let s = unsafe { utf8_cstr(string) };

    ColorSpec::from (Color::parse (s, (allow_inherit, allow_current_color)))
}

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

    fn parse (s: &str) -> ColorSpec {
        // ColorSpec::from (Color::parse (s, (AllowInherit::Yes, AllowCurrentColor::Yes)))
        rsvg_css_parse_color (s.to_glib_none ().0, AllowInherit::Yes, AllowCurrentColor::Yes)
    }

    #[test]
    fn parses_hash_hex_colors () {
        assert_eq! (parse ("#AB10fa20"), ColorSpec { kind: ColorKind::ARGB, argb: 0x20ab10fa });
        assert_eq! (parse ("#10fa20"),   ColorSpec { kind: ColorKind::ARGB, argb: 0xff10fa20 });
        assert_eq! (parse ("#abcd"),     ColorSpec { kind: ColorKind::ARGB, argb: 0xddaabbcc });
        assert_eq! (parse ("#123"),      ColorSpec { kind: ColorKind::ARGB, argb: 0xff112233 });
    }

    #[test]
    fn parses_color_keywords () {
        assert_eq! (parse ("red"),  ColorSpec { kind: ColorKind::ARGB, argb: 0xffff0000 });
        assert_eq! (parse ("lime"), ColorSpec { kind: ColorKind::ARGB, argb: 0xff00ff00 });
        assert_eq! (parse ("blue"), ColorSpec { kind: ColorKind::ARGB, argb: 0xff0000ff });
    }

    #[test]
    fn parses_color_functions () {
        assert_eq! (parse ("rgb(255, 0, 0)"), ColorSpec { kind: ColorKind::ARGB, argb: 0xffff0000 });
        assert_eq! (parse ("rgb(0, 255, 0)"), ColorSpec { kind: ColorKind::ARGB, argb: 0xff00ff00 });
        assert_eq! (parse ("rgb(0, 0, 255)"), ColorSpec { kind: ColorKind::ARGB, argb: 0xff0000ff });
    }

    #[test]
    fn parses_current_color () {
        assert_eq! (parse ("currentColor"), ColorSpec { kind: ColorKind::CurrentColor, argb: 0 });
    }

    fn make_error () -> ColorSpec {
        ColorSpec {
            kind: ColorKind::ParseError,
            argb: 0
        }
    }

    #[test]
    fn invalid_hash_hex_colors_yield_error () {
        assert_eq! (parse ("#"), make_error ());
        assert_eq! (parse ("#xyz"), make_error ());
        assert_eq! (parse ("#112233gg"), make_error ());
    }

    #[test]
    fn invalid_colors_yield_error () {
        assert_eq! (parse (""), make_error ());
        assert_eq! (parse ("foo"), make_error ());
        assert_eq! (parse ("rgb(chilaquil)"), make_error ());
        assert_eq! (parse ("rgb(1, 2, 3, 4, 5)"), make_error ());
    }

    #[test]
    fn yields_error_on_disallowed_current_color () {
        assert_eq! (ColorSpec::from (Color::parse ("currentColor", (AllowInherit::Yes, AllowCurrentColor::No))),
                    make_error ());
    }

    #[test]
    fn yields_error_on_disallowed_inherit () {
        assert_eq! (ColorSpec::from (Color::parse ("inherit", (AllowInherit::No, AllowCurrentColor::Yes))),
                    make_error ());
    }

    fn test_roundtrip (s: &str) {
        let result = Color::parse (s, (AllowInherit::Yes, AllowCurrentColor::Yes));
        let result2 = result.clone ();
        let spec = ColorSpec::from (result2);

        if result.is_ok () {
            assert_eq! (Color::from_color_spec (&spec), result);
        } else {
            assert! (Color::from_color_spec (&spec).is_err ());
        }
    }

    #[test]
    fn roundtrips () {
        test_roundtrip ("inherit");
        test_roundtrip ("currentColor");
        test_roundtrip ("#aabbccdd");
        test_roundtrip ("papadzul");
    }

    #[test]
    fn from_argb () {
        assert_eq! (Color::from (0xaabbccdd),
                    Color::RGBA (cssparser::RGBA::new (0xbb, 0xcc, 0xdd, 0xaa)));
    }
}
<commit_msg>cargo-clippy: Remove unnecessary parentheses<commit_after>use cssparser;
use libc;

use parsers::Parse;
use parsers::ParseError;
use error::*;
use util::utf8_cstr;

// There are two quirks here:
//
// First, we need to expose the Color algebraic type *and* a parse
// error to C, but we can't repr(C) them plainly.  So, we define a
// ColorKind enum and a ColorSpec struct that can both be represented
// in C.
//
// Second, the C code in librsvg expects ARGB colors passed around as
// guint32.  However, in Rust we'd prefer to use cssparser's RGBA
// structure, which has explicit fields for red/green/blue/alpha.
// We'll do those conversions here, for the benefit of the C code, and
// then just wait until the C code gradually disappears.

// Keep this in sync with rsvg-css.h:RsvgCssColorKind
#[repr(C)]
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ColorKind {
    Inherit,
    CurrentColor,
    ARGB,
    ParseError
}

// Keep this in sync with rsvg-css.h:RsvgCssColorSpec
#[repr(C)]
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct ColorSpec {
    kind: ColorKind,
    argb: u32
}

// Keep in sync with rsvg-css.h:AllowInherit
#[repr(C)]
#[derive(PartialEq, Debug)]
pub enum AllowInherit {
    No,
    Yes
}

// Keep in sync with rsvg-css.h:AllowCurrentColor
#[repr(C)]
#[derive(PartialEq, Debug)]
pub enum AllowCurrentColor {
    No,
    Yes
}

// This is the Rust version of the above
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum Color {
    Inherit,
    CurrentColor,
    RGBA (cssparser::RGBA)
}

impl Parse for Color {
    type Data = (AllowInherit, AllowCurrentColor);
    type Err = AttributeError;

    fn parse (s: &str, (allow_inherit, allow_current_color): (AllowInherit, AllowCurrentColor)) -> Result<Color, AttributeError> {
        if s == "inherit" {
            if allow_inherit == AllowInherit::Yes {
                Ok (Color::Inherit)
            } else {
                Err (AttributeError::Value ("inherit is not allowed here".to_string ()))
            }
        } else {
            let mut input = cssparser::ParserInput::new (s);
            match cssparser::Color::parse (&mut cssparser::Parser::new (&mut input)) {
                Ok (cssparser::Color::CurrentColor) => {
                    if allow_current_color == AllowCurrentColor::Yes {
                        Ok (Color::CurrentColor)
                    } else {
                        Err (AttributeError::Value ("currentColor is not allowed here".to_string ()))
                    }
                },

                Ok (csscolor) => Ok (Color::from (csscolor)),

                _ => Err (AttributeError::Parse (ParseError::new ("invalid syntax for color")))
            }
        }
    }

}

impl Color {
    pub fn from_color_spec (spec: &ColorSpec) -> Result <Color, AttributeError> {
        match *spec {
            ColorSpec { kind: ColorKind::Inherit, .. }      => Ok (Color::Inherit),

            ColorSpec { kind: ColorKind::CurrentColor, .. } => Ok (Color::CurrentColor),

            ColorSpec { kind: ColorKind::ARGB, argb } => Ok (Color::RGBA (rgba_from_argb (argb))),

            ColorSpec { kind: ColorKind::ParseError, .. } => Err (AttributeError::Parse (ParseError::new ("parse error")))
        }
    }
}

fn rgba_from_argb (argb: u32) -> cssparser::RGBA {
    cssparser::RGBA::new (((argb & 0x00ff_0000) >> 16) as u8,
                          ((argb & 0x0000_ff00) >> 8) as u8,
                          (argb & 0x0000_00ff) as u8,
                          ((argb & 0xff00_0000) >> 24) as u8)
}

impl From<cssparser::Color> for Color {
    fn from (c: cssparser::Color) -> Color {
        match c {
            cssparser::Color::CurrentColor => Color::CurrentColor,
            cssparser::Color::RGBA (rgba) => Color::RGBA (rgba)
        }
    }
}

impl From<u32> for Color {
    fn from (argb: u32) -> Color {
        Color::RGBA (rgba_from_argb (argb))
    }
}

impl From<Result<Color, AttributeError>> for ColorSpec {
    fn from (result: Result<Color, AttributeError>) -> ColorSpec {
        match result {
            Ok (Color::Inherit) =>
                ColorSpec {
                    kind: ColorKind::Inherit,
                    argb: 0
                },

            Ok (Color::CurrentColor) =>
                ColorSpec {
                    kind: ColorKind::CurrentColor,
                    argb: 0
                },

            Ok (Color::RGBA (rgba)) =>
                ColorSpec {
                    kind: ColorKind::ARGB,
                    argb: (u32::from(rgba.alpha) << 24 |
                           u32::from(rgba.red)   << 16 |
                           u32::from(rgba.green) << 8  |
                           u32::from(rgba.blue))
                },

            _ =>
                ColorSpec {
                    kind: ColorKind::ParseError,
                    argb: 0
                }
        }
    }
}

#[no_mangle]
pub extern fn rsvg_css_parse_color (string: *const libc::c_char,
                                    allow_inherit: AllowInherit,
                                    allow_current_color: AllowCurrentColor) -> ColorSpec {
    let s = unsafe { utf8_cstr(string) };

    ColorSpec::from (Color::parse (s, (allow_inherit, allow_current_color)))
}

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

    fn parse (s: &str) -> ColorSpec {
        // ColorSpec::from (Color::parse (s, (AllowInherit::Yes, AllowCurrentColor::Yes)))
        rsvg_css_parse_color (s.to_glib_none ().0, AllowInherit::Yes, AllowCurrentColor::Yes)
    }

    #[test]
    fn parses_hash_hex_colors () {
        assert_eq! (parse ("#AB10fa20"), ColorSpec { kind: ColorKind::ARGB, argb: 0x20ab10fa });
        assert_eq! (parse ("#10fa20"),   ColorSpec { kind: ColorKind::ARGB, argb: 0xff10fa20 });
        assert_eq! (parse ("#abcd"),     ColorSpec { kind: ColorKind::ARGB, argb: 0xddaabbcc });
        assert_eq! (parse ("#123"),      ColorSpec { kind: ColorKind::ARGB, argb: 0xff112233 });
    }

    #[test]
    fn parses_color_keywords () {
        assert_eq! (parse ("red"),  ColorSpec { kind: ColorKind::ARGB, argb: 0xffff0000 });
        assert_eq! (parse ("lime"), ColorSpec { kind: ColorKind::ARGB, argb: 0xff00ff00 });
        assert_eq! (parse ("blue"), ColorSpec { kind: ColorKind::ARGB, argb: 0xff0000ff });
    }

    #[test]
    fn parses_color_functions () {
        assert_eq! (parse ("rgb(255, 0, 0)"), ColorSpec { kind: ColorKind::ARGB, argb: 0xffff0000 });
        assert_eq! (parse ("rgb(0, 255, 0)"), ColorSpec { kind: ColorKind::ARGB, argb: 0xff00ff00 });
        assert_eq! (parse ("rgb(0, 0, 255)"), ColorSpec { kind: ColorKind::ARGB, argb: 0xff0000ff });
    }

    #[test]
    fn parses_current_color () {
        assert_eq! (parse ("currentColor"), ColorSpec { kind: ColorKind::CurrentColor, argb: 0 });
    }

    fn make_error () -> ColorSpec {
        ColorSpec {
            kind: ColorKind::ParseError,
            argb: 0
        }
    }

    #[test]
    fn invalid_hash_hex_colors_yield_error () {
        assert_eq! (parse ("#"), make_error ());
        assert_eq! (parse ("#xyz"), make_error ());
        assert_eq! (parse ("#112233gg"), make_error ());
    }

    #[test]
    fn invalid_colors_yield_error () {
        assert_eq! (parse (""), make_error ());
        assert_eq! (parse ("foo"), make_error ());
        assert_eq! (parse ("rgb(chilaquil)"), make_error ());
        assert_eq! (parse ("rgb(1, 2, 3, 4, 5)"), make_error ());
    }

    #[test]
    fn yields_error_on_disallowed_current_color () {
        assert_eq! (ColorSpec::from (Color::parse ("currentColor", (AllowInherit::Yes, AllowCurrentColor::No))),
                    make_error ());
    }

    #[test]
    fn yields_error_on_disallowed_inherit () {
        assert_eq! (ColorSpec::from (Color::parse ("inherit", (AllowInherit::No, AllowCurrentColor::Yes))),
                    make_error ());
    }

    fn test_roundtrip (s: &str) {
        let result = Color::parse (s, (AllowInherit::Yes, AllowCurrentColor::Yes));
        let result2 = result.clone ();
        let spec = ColorSpec::from (result2);

        if result.is_ok () {
            assert_eq! (Color::from_color_spec (&spec), result);
        } else {
            assert! (Color::from_color_spec (&spec).is_err ());
        }
    }

    #[test]
    fn roundtrips () {
        test_roundtrip ("inherit");
        test_roundtrip ("currentColor");
        test_roundtrip ("#aabbccdd");
        test_roundtrip ("papadzul");
    }

    #[test]
    fn from_argb () {
        assert_eq! (Color::from (0xaabbccdd),
                    Color::RGBA (cssparser::RGBA::new (0xbb, 0xcc, 0xdd, 0xaa)));
    }
}
<|endoftext|>


<commit_before>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use crate as aptos_telemetry;
use crate::{service::TelemetryEvent, utils};
use std::collections::BTreeMap;

/// Build information event name
const APTOS_NODE_BUILD_INFORMATION: &str = "APTOS_NODE_BUILD_INFORMATION";

/// Build information keys
pub const BUILD_BRANCH: &str = "build_branch";
pub const BUILD_CARGO_VERSION: &str = "build_cargo_version";
pub const BUILD_CHAIN_ID: &str = "build_chain_id";
pub const BUILD_CLAP_VERSION: &str = "build_clap_version";
pub const BUILD_COMMIT_HASH: &str = "build_commit_hash";
pub const BUILD_OS: &str = "build_os";
pub const BUILD_PKG_VERSION: &str = "build_pkg_version";
pub const BUILD_PROJECT_NAME: &str = "build_project_name";
pub const BUILD_RUST_CHANNEL: &str = "build_rust_channel";
pub const BUILD_RUST_VERSION: &str = "build_rust_version";
pub const BUILD_TAG: &str = "build_tag";
pub const BUILD_TARGET: &str = "build_target";
pub const BUILD_TARGET_ARCH: &str = "build_target_arch";
pub const BUILD_TIME: &str = "build_time";
pub const BUILD_VERSION: &str = "build_version";

// Used by external crates to collect crate specific build information
#[macro_export]
macro_rules! collect_build_information {
    () => {{
        println!("calling collect {:?}", std::env::var("GIT_SHA"));
        // Collect and return the build information
        let mut build_information: std::collections::BTreeMap<String, String> = BTreeMap::new();

        // Get Git metadata from environment variables set during build-time.
        // This is applicable for docker based builds.
        if let Ok(git_branch) = std::env::var("GIT_SHA") {
            build_information.insert(
                aptos_telemetry::build_information::BUILD_COMMIT_HASH.into(),
                git_branch,
            );
        }

        if let Ok(git_hash) = std::env::var("GIT_BRANCH") {
            build_information.insert(
                aptos_telemetry::build_information::BUILD_BRANCH.into(),
                git_hash,
            );
        }

        if let Ok(git_tag) = std::env::var("GIT_TAG") {
            build_information.insert(
                aptos_telemetry::build_information::BUILD_TAG.into(),
                git_tag,
            );
        }

        if let Ok(build_date) = std::env::var("BUILD_DATE") {
            build_information.insert(
                aptos_telemetry::build_information::BUILD_TIME.into(),
                build_date,
            );
        }

        build_information
    }};
}

/// Collects and sends the build information via telemetry
pub(crate) async fn create_build_info_telemetry_event(chain_id: String) -> TelemetryEvent {
    // Collect the build information
    let build_information = get_build_information(Some(chain_id));

    // Create and return a new telemetry event
    TelemetryEvent {
        name: APTOS_NODE_BUILD_INFORMATION.into(),
        params: build_information,
    }
}

/// Used to collect build information
pub(crate) fn get_build_information(chain_id: Option<String>) -> BTreeMap<String, String> {
    let mut build_information = collect_build_information!();
    utils::insert_optional_value(&mut build_information, BUILD_CHAIN_ID, chain_id);
    build_information
}

#[test]
fn test_get_build_information() {
    let commit_hash = String::from("COMMIT-HASH-1");
    let build_branch = String::from("branch-1");
    let build_tag = String::from("release-1");

    std::env::set_var("GIT_SHA", commit_hash.clone());
    std::env::set_var("GIT_BRANCH", build_branch.clone());
    std::env::set_var("GIT_TAG", build_tag.clone());

    let info = get_build_information(None);

    assert!(info.contains_key(BUILD_COMMIT_HASH));
    assert_eq!(info.get(BUILD_COMMIT_HASH), Some(&commit_hash));

    assert!(info.contains_key(BUILD_BRANCH));
    assert_eq!(info.get(BUILD_BRANCH), Some(&build_branch));

    assert!(info.contains_key(BUILD_TAG));
    assert_eq!(info.get(BUILD_TAG), Some(&build_tag));
}
<commit_msg>[aptos-telemetry] Remove println<commit_after>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use crate as aptos_telemetry;
use crate::{service::TelemetryEvent, utils};
use std::collections::BTreeMap;

/// Build information event name
const APTOS_NODE_BUILD_INFORMATION: &str = "APTOS_NODE_BUILD_INFORMATION";

/// Build information keys
pub const BUILD_BRANCH: &str = "build_branch";
pub const BUILD_CARGO_VERSION: &str = "build_cargo_version";
pub const BUILD_CHAIN_ID: &str = "build_chain_id";
pub const BUILD_CLAP_VERSION: &str = "build_clap_version";
pub const BUILD_COMMIT_HASH: &str = "build_commit_hash";
pub const BUILD_OS: &str = "build_os";
pub const BUILD_PKG_VERSION: &str = "build_pkg_version";
pub const BUILD_PROJECT_NAME: &str = "build_project_name";
pub const BUILD_RUST_CHANNEL: &str = "build_rust_channel";
pub const BUILD_RUST_VERSION: &str = "build_rust_version";
pub const BUILD_TAG: &str = "build_tag";
pub const BUILD_TARGET: &str = "build_target";
pub const BUILD_TARGET_ARCH: &str = "build_target_arch";
pub const BUILD_TIME: &str = "build_time";
pub const BUILD_VERSION: &str = "build_version";

// Used by external crates to collect crate specific build information
#[macro_export]
macro_rules! collect_build_information {
    () => {{
        // Collect and return the build information
        let mut build_information: std::collections::BTreeMap<String, String> = BTreeMap::new();

        // Get Git metadata from environment variables set during build-time.
        // This is applicable for docker based builds.
        if let Ok(git_branch) = std::env::var("GIT_SHA") {
            build_information.insert(
                aptos_telemetry::build_information::BUILD_COMMIT_HASH.into(),
                git_branch,
            );
        }

        if let Ok(git_hash) = std::env::var("GIT_BRANCH") {
            build_information.insert(
                aptos_telemetry::build_information::BUILD_BRANCH.into(),
                git_hash,
            );
        }

        if let Ok(git_tag) = std::env::var("GIT_TAG") {
            build_information.insert(
                aptos_telemetry::build_information::BUILD_TAG.into(),
                git_tag,
            );
        }

        if let Ok(build_date) = std::env::var("BUILD_DATE") {
            build_information.insert(
                aptos_telemetry::build_information::BUILD_TIME.into(),
                build_date,
            );
        }

        build_information
    }};
}

/// Collects and sends the build information via telemetry
pub(crate) async fn create_build_info_telemetry_event(chain_id: String) -> TelemetryEvent {
    // Collect the build information
    let build_information = get_build_information(Some(chain_id));

    // Create and return a new telemetry event
    TelemetryEvent {
        name: APTOS_NODE_BUILD_INFORMATION.into(),
        params: build_information,
    }
}

/// Used to collect build information
pub(crate) fn get_build_information(chain_id: Option<String>) -> BTreeMap<String, String> {
    let mut build_information = collect_build_information!();
    utils::insert_optional_value(&mut build_information, BUILD_CHAIN_ID, chain_id);
    build_information
}

#[test]
fn test_get_build_information() {
    let commit_hash = String::from("COMMIT-HASH-1");
    let build_branch = String::from("branch-1");
    let build_tag = String::from("release-1");

    std::env::set_var("GIT_SHA", commit_hash.clone());
    std::env::set_var("GIT_BRANCH", build_branch.clone());
    std::env::set_var("GIT_TAG", build_tag.clone());

    let info = get_build_information(None);

    assert!(info.contains_key(BUILD_COMMIT_HASH));
    assert_eq!(info.get(BUILD_COMMIT_HASH), Some(&commit_hash));

    assert!(info.contains_key(BUILD_BRANCH));
    assert_eq!(info.get(BUILD_BRANCH), Some(&build_branch));

    assert!(info.contains_key(BUILD_TAG));
    assert_eq!(info.get(BUILD_TAG), Some(&build_tag));
}
<|endoftext|>


<commit_before>// GPU Command Assembly Parser

use std::string::String;
use super::parsetools::ParseTools;

#[derive(Debug)]
pub enum ParseError { SyntaxError, DelimiterNotEnclosed }
pub type ParseResult<T> = Result<T, ParseError>;
#[derive(Debug, PartialEq)]
pub enum ExpressionNode<'a>
{
	Number(u64), Floating(f64), ConstantRef(&'a [char]),
	Negated(Box<ExpressionNode<'a>>),
	Add(Box<ExpressionNode<'a>>, Box<ExpressionNode<'a>>),
	Sub(Box<ExpressionNode<'a>>, Box<ExpressionNode<'a>>),
	Mul(Box<ExpressionNode<'a>>, Box<ExpressionNode<'a>>),
	Div(Box<ExpressionNode<'a>>, Box<ExpressionNode<'a>>),
	Mod(Box<ExpressionNode<'a>>, Box<ExpressionNode<'a>>),
	And(Box<ExpressionNode<'a>>, Box<ExpressionNode<'a>>),
	Or(Box<ExpressionNode<'a>>, Box<ExpressionNode<'a>>),
	Xor(Box<ExpressionNode<'a>>, Box<ExpressionNode<'a>>)
}

fn is_space(chr: char) -> bool { chr == ' ' || chr == '\t' }
fn split_of_ident(ch: char) -> bool
{
	is_space(ch) || ch == '\n' || ch == '#' || ch == ',' || ch == '.'
}
pub fn parse_define(line: &[char]) -> ParseResult<(String, String)>
{
	if line[..7] != ['.', 'd', 'e', 'f', 'i', 'n', 'e'] { Err(ParseError::SyntaxError) }
	else if line[7] != ' ' && line[7] != '\t' { Err(ParseError::SyntaxError) }
	else
	{
		let (name, rest) = (&line[7..]).skip_while(is_space).take_until(is_space);
		let value = rest.skip_while(is_space);
		Ok((name.clone_as_string(), value.clone_as_string()))
	}
}
pub fn parse_primary_terms(input: &[char]) -> (ParseResult<ExpressionNode>, &[char])
{
	if input.is_front_of('(')
	{
		// Nested Expression
		let (inner, rest) = parse_expression(input.drop(1).skip_while(is_space));
		match inner
		{
			Err(_) => (inner, rest),
			Ok(_) =>
			{
				let rest = rest.skip_while(is_space);
				if rest.is_front_of(')') { (inner, &rest[1..]) }
				else { (Err(ParseError::DelimiterNotEnclosed), rest) }
			}
		}
	}
	else if input.is_front_of('-')
	{
		// Negated
		let (inner, rest) = parse_primary_terms(input.drop(1).skip_while(is_space));
		(inner.map(|ner| ExpressionNode::Negated(Box::new(ner))), rest)
	}
	else if input.is_front(|&c| '0' <= c && c <= '9')
	{
		// Numeric
		let mut num_ipart = input[0] as u64 - '0' as u64;
		let mut rest = &input[1..];
		while rest.is_front(|&c| '0' <= c && c <= '9')
		{
			num_ipart = num_ipart * 10 + (rest[0] as u64 - '0' as u64);
			rest = &rest[1..];
		}
		(if rest.is_front_of('.')
		{
			// fp
			let mut num_fpart = 0.0f64;
			let mut divs_fpart = 10.0f64;
			rest = &rest[1..];
			while rest.is_front(|&c| '0' <= c && c <= '9')
			{
				num_fpart += (rest[0] as u64 - '0' as u64) as f64 / divs_fpart;
				divs_fpart *= 10.0;
				rest = &rest[1..];
			}
			Ok(ExpressionNode::Floating(num_ipart as f64 + num_fpart))
		}
		else { Ok(ExpressionNode::Number(num_ipart)) }, rest)
	}
	else
	{
		// ConstantRef
		let (cref_name, rest) = input.take_until(split_of_ident);
		(if cref_name.is_empty() { Err(ParseError::SyntaxError) }
		else { Ok(ExpressionNode::ConstantRef(cref_name)) }, rest)
	}
}
pub fn parse_muldiv_expr(input: &[char]) -> (ParseResult<ExpressionNode>, &[char])
{
	let (lhs, rest) = parse_primary_terms(input);
	match lhs
	{
		Err(_) => (lhs, rest),
		Ok(e) =>
		{
			fn recursive<'a>(current_expr: ExpressionNode<'a>, rest: &'a [char])
				-> (ParseResult<ExpressionNode<'a>>, &'a [char])
			{
				let rest = rest.skip_while(is_space);
				if rest.is_front_of('*')
				{
					let rest = rest.drop(1).skip_while(is_space);
					let (rhs, rest_r) = parse_primary_terms(rest);
					match rhs
					{
						Err(_) => (rhs, rest_r),
						Ok(er) => recursive(ExpressionNode::Mul(Box::new(current_expr), Box::new(er)), rest_r)
					}
				}
				else if rest.is_front_of('/')
				{
					let rest = rest.drop(1).skip_while(is_space);
					let (rhs, rest_r) = parse_primary_terms(rest);
					match rhs
					{
						Err(_) => (rhs, rest_r),
						Ok(er) => recursive(ExpressionNode::Div(Box::new(current_expr), Box::new(er)), rest_r)
					}
				}
				else if rest.is_front_of('%')
				{
					let rest = rest.drop(1).skip_while(is_space);
					let (rhs, rest_r) = parse_primary_terms(rest);
					match rhs
					{
						Err(_) => (rhs, rest_r),
						Ok(er) => recursive(ExpressionNode::Mod(Box::new(current_expr), Box::new(er)), rest_r)
					}
				}
				else { (Ok(current_expr), rest) }
			}
			recursive(e, rest)
		}
	}
}
pub fn parse_addsub_expr(input: &[char]) -> (ParseResult<ExpressionNode>, &[char])
{
	let (lhs, rest) = parse_muldiv_expr(input);
	match lhs
	{
		Err(_) => (lhs, rest),
		Ok(e) =>
		{
			fn recursive<'a>(current_expr: ExpressionNode<'a>, rest: &'a [char])
				-> (ParseResult<ExpressionNode<'a>>, &'a [char])
			{
				let rest = rest.skip_while(is_space);
				if rest.is_front_of('+')
				{
					let rest = rest.drop(1).skip_while(is_space);
					let (rhs, rest_r) = parse_muldiv_expr(rest);
					match rhs
					{
						Err(_) => (rhs, rest_r),
						Ok(er) => recursive(ExpressionNode::Add(Box::new(current_expr), Box::new(er)), rest_r)
					}
				}
				else if rest.is_front_of('-')
				{
					let rest = rest.drop(1).skip_while(is_space);
					let (rhs, rest_r) = parse_muldiv_expr(rest);
					match rhs
					{
						Err(_) => (rhs, rest_r),
						Ok(er) => recursive(ExpressionNode::Sub(Box::new(current_expr), Box::new(er)), rest_r)
					}
				}
				else { (Ok(current_expr), rest) }
			}
			recursive(e, rest)
		}
	}
}
pub fn parse_bit_expr(input: &[char]) -> (ParseResult<ExpressionNode>, &[char])
{
	let (lhs, rest) = parse_addsub_expr(input);
	match lhs
	{
		Err(_) => (lhs, rest),
		Ok(e) =>
		{
			fn recursive<'a>(current_expr: ExpressionNode<'a>, rest: &'a [char])
				-> (ParseResult<ExpressionNode<'a>>, &'a [char])
			{
				let rest = rest.skip_while(is_space);
				if rest.is_front_of('&')
				{
					let rest = rest.drop(1).skip_while(is_space);
					let (rhs, rest_r) = parse_addsub_expr(rest);
					match rhs
					{
						Err(_) => (rhs, rest_r),
						Ok(er) => recursive(ExpressionNode::And(Box::new(current_expr), Box::new(er)), rest_r)
					}
				}
				else if rest.is_front_of('|')
				{
					let rest = rest.drop(1).skip_while(is_space);
					let (rhs, rest_r) = parse_addsub_expr(rest);
					match rhs
					{
						Err(_) => (rhs, rest_r),
						Ok(er) => recursive(ExpressionNode::Or(Box::new(current_expr), Box::new(er)), rest_r)
					}
				}
				else if rest.is_front_of('^')
				{
					let rest = rest.drop(1).skip_while(is_space);
					let (rhs, rest_r) = parse_addsub_expr(rest);
					match rhs
					{
						Err(_) => (rhs, rest_r),
						Ok(er) => recursive(ExpressionNode::Xor(Box::new(current_expr), Box::new(er)), rest_r)
					}
				}
				else { (Ok(current_expr), rest) }
			}
			recursive(e, rest)
		}
	}
}
pub fn parse_expression(input: &[char]) -> (ParseResult<ExpressionNode>, &[char])
{
	parse_bit_expr(input)
}

#[cfg(test)]
mod test
{
	use itertools::Itertools;

	#[test] fn parse_define()
	{
		let testcase = ".define DEFAULT_BITS	2";
		assert_eq!(super::parse_define(&testcase.chars().collect_vec()).unwrap(), ("DEFAULT_BITS".to_owned(), "2".to_owned()));
	}
	#[test] fn parse_primary_terms()
	{
		let testcase = "PS_RENDER_BACKGROUND,";
		let testcase_collect = testcase.chars().collect_vec();
		let res = super::parse_primary_terms(&testcase_collect);
		assert_eq!(res.0.unwrap(), super::ExpressionNode::ConstantRef(&testcase_collect[..20]));
		assert_eq!(res.1, &testcase_collect[20..]);
		let testcase = "2.0";
		let testcase_collect = testcase.chars().collect_vec();
		let res = super::parse_primary_terms(&testcase_collect);
		assert_eq!(res.0.unwrap(), super::ExpressionNode::Floating(2.0));
		let testcase = "-6";
		let testcase_collect = testcase.chars().collect_vec();
		let res = super::parse_primary_terms(&testcase_collect);
		assert_eq!(res.0.unwrap(), super::ExpressionNode::Negated(Box::new(super::ExpressionNode::Number(6))));
	}
	#[test] fn parse_expression()
	{
		let testcase = "2 + 3";
		let testcase_collect = testcase.chars().collect_vec();
		let res = super::parse_expression(&testcase_collect);
		assert_eq!(res.0.unwrap(), super::ExpressionNode::Add(Box::new(super::ExpressionNode::Number(2)), Box::new(super::ExpressionNode::Number(3))));
		let testcase = "TOP | TRANSFER + 2, ";
		let testcase_collect = testcase.chars().collect_vec();
		let res = super::parse_expression(&testcase_collect);
		assert_eq!(res.0.unwrap(), super::ExpressionNode::Or(
			Box::new(super::ExpressionNode::ConstantRef(&testcase_collect[..3])),
			Box::new(super::ExpressionNode::Add(
				Box::new(super::ExpressionNode::ConstantRef(&testcase_collect[6..14])),
				Box::new(super::ExpressionNode::Number(2))
			))
		));
		assert_eq!(res.1, &testcase_collect[18..]);
	}
}
<commit_msg>added expression parser<commit_after>// GPU Command Assembly Parser

use std::string::String;
use super::parsetools::ParseTools;

#[derive(Debug)]
pub enum ParseError { SyntaxError, DelimiterNotEnclosed }
pub type ParseResult<T> = Result<T, ParseError>;
#[derive(Debug, PartialEq)]
pub enum ExpressionNode<'a>
{
	Number(u64), Floating(f64), ConstantRef(&'a [char]),
	Negated(Box<ExpressionNode<'a>>),
	Add(Box<ExpressionNode<'a>>, Box<ExpressionNode<'a>>),
	Sub(Box<ExpressionNode<'a>>, Box<ExpressionNode<'a>>),
	Mul(Box<ExpressionNode<'a>>, Box<ExpressionNode<'a>>),
	Div(Box<ExpressionNode<'a>>, Box<ExpressionNode<'a>>),
	Mod(Box<ExpressionNode<'a>>, Box<ExpressionNode<'a>>),
	And(Box<ExpressionNode<'a>>, Box<ExpressionNode<'a>>),
	Or(Box<ExpressionNode<'a>>, Box<ExpressionNode<'a>>),
	Xor(Box<ExpressionNode<'a>>, Box<ExpressionNode<'a>>)
}

fn is_space(chr: char) -> bool { chr == ' ' || chr == '\t' }
fn split_of_ident(ch: char) -> bool
{
	is_space(ch) || ch == '\n' || ch == '#' || ch == ',' || ch == '.'
}
pub fn parse_define(line: &[char]) -> ParseResult<(String, String)>
{
	if line[..7] != ['.', 'd', 'e', 'f', 'i', 'n', 'e'] { Err(ParseError::SyntaxError) }
	else if line[7] != ' ' && line[7] != '\t' { Err(ParseError::SyntaxError) }
	else
	{
		let (name, rest) = (&line[7..]).skip_while(is_space).take_until(is_space);
		let value = rest.skip_while(is_space);
		Ok((name.clone_as_string(), value.clone_as_string()))
	}
}
pub fn parse_primary_terms(input: &[char]) -> (ParseResult<ExpressionNode>, &[char])
{
	if input.is_front_of('(')
	{
		// Nested Expression
		let (inner, rest) = parse_expression(input.drop(1).skip_while(is_space));
		match inner
		{
			Err(_) => (inner, rest),
			Ok(_) =>
			{
				let rest = rest.skip_while(is_space);
				if rest.is_front_of(')') { (inner, &rest[1..]) }
				else { (Err(ParseError::DelimiterNotEnclosed), rest) }
			}
		}
	}
	else if input.is_front_of('-')
	{
		// Negated
		let (inner, rest) = parse_primary_terms(input.drop(1).skip_while(is_space));
		(inner.map(|ner| ExpressionNode::Negated(Box::new(ner))), rest)
	}
	else if input.is_front(|&c| '0' <= c && c <= '9')
	{
		// Numeric
		let mut num_ipart = input[0] as u64 - '0' as u64;
		let mut rest = &input[1..];
		while rest.is_front(|&c| '0' <= c && c <= '9')
		{
			num_ipart = num_ipart * 10 + (rest[0] as u64 - '0' as u64);
			rest = &rest[1..];
		}
		(if rest.is_front_of('.')
		{
			// fp
			let mut num_fpart = 0.0f64;
			let mut divs_fpart = 10.0f64;
			rest = &rest[1..];
			while rest.is_front(|&c| '0' <= c && c <= '9')
			{
				num_fpart += (rest[0] as u64 - '0' as u64) as f64 / divs_fpart;
				divs_fpart *= 10.0;
				rest = &rest[1..];
			}
			Ok(ExpressionNode::Floating(num_ipart as f64 + num_fpart))
		}
		else { Ok(ExpressionNode::Number(num_ipart)) }, rest)
	}
	else
	{
		// ConstantRef
		let (cref_name, rest) = input.take_until(split_of_ident);
		(if cref_name.is_empty() { Err(ParseError::SyntaxError) }
		else { Ok(ExpressionNode::ConstantRef(cref_name)) }, rest)
	}
}
macro_rules!CombinateBinaryExpressionParser
{
	($name: ident = $parent_term: path { $($op: expr: $node_variant: path),* }) =>
	{
		pub fn $name(input: &[char]) -> (ParseResult<ExpressionNode>, &[char])
		{
			let (lhs, rest) = $parent_term(input);
			match lhs
			{
				Err(_) => (lhs, rest),
				Ok(e) =>
				{
					fn recursive<'a>(current_expr: ExpressionNode<'a>, rest: &'a [char])
						-> (ParseResult<ExpressionNode<'a>>, &'a [char])
					{
						let rest = rest.skip_while(is_space);
						$(
							if rest.is_front_of($op)
							{
								let rest = rest.drop(1).skip_while(is_space);
								let (rhs, rest_r) = $parent_term(rest);
								match rhs
								{
									Err(_) => (rhs, rest_r),
									Ok(er) => recursive($node_variant(Box::new(current_expr), Box::new(er)), rest_r)
								}
							}
						)else*
						else { (Ok(current_expr), rest) }
					}
					recursive(e, rest)
				}
			}
		}
	}
}
CombinateBinaryExpressionParser!(parse_muldiv_expr = parse_primary_terms
{
	'*': ExpressionNode::Mul,
	'/': ExpressionNode::Div,
	'%': ExpressionNode::Mod
})
pub fn parse_addsub_expr(input: &[char]) -> (ParseResult<ExpressionNode>, &[char])
{
	let (lhs, rest) = parse_muldiv_expr(input);
	match lhs
	{
		Err(_) => (lhs, rest),
		Ok(e) =>
		{
			fn recursive<'a>(current_expr: ExpressionNode<'a>, rest: &'a [char])
				-> (ParseResult<ExpressionNode<'a>>, &'a [char])
			{
				let rest = rest.skip_while(is_space);
				if rest.is_front_of('+')
				{
					let rest = rest.drop(1).skip_while(is_space);
					let (rhs, rest_r) = parse_muldiv_expr(rest);
					match rhs
					{
						Err(_) => (rhs, rest_r),
						Ok(er) => recursive(ExpressionNode::Add(Box::new(current_expr), Box::new(er)), rest_r)
					}
				}
				else if rest.is_front_of('-')
				{
					let rest = rest.drop(1).skip_while(is_space);
					let (rhs, rest_r) = parse_muldiv_expr(rest);
					match rhs
					{
						Err(_) => (rhs, rest_r),
						Ok(er) => recursive(ExpressionNode::Sub(Box::new(current_expr), Box::new(er)), rest_r)
					}
				}
				else { (Ok(current_expr), rest) }
			}
			recursive(e, rest)
		}
	}
}
pub fn parse_bit_expr(input: &[char]) -> (ParseResult<ExpressionNode>, &[char])
{
	let (lhs, rest) = parse_addsub_expr(input);
	match lhs
	{
		Err(_) => (lhs, rest),
		Ok(e) =>
		{
			fn recursive<'a>(current_expr: ExpressionNode<'a>, rest: &'a [char])
				-> (ParseResult<ExpressionNode<'a>>, &'a [char])
			{
				let rest = rest.skip_while(is_space);
				if rest.is_front_of('&')
				{
					let rest = rest.drop(1).skip_while(is_space);
					let (rhs, rest_r) = parse_addsub_expr(rest);
					match rhs
					{
						Err(_) => (rhs, rest_r),
						Ok(er) => recursive(ExpressionNode::And(Box::new(current_expr), Box::new(er)), rest_r)
					}
				}
				else if rest.is_front_of('|')
				{
					let rest = rest.drop(1).skip_while(is_space);
					let (rhs, rest_r) = parse_addsub_expr(rest);
					match rhs
					{
						Err(_) => (rhs, rest_r),
						Ok(er) => recursive(ExpressionNode::Or(Box::new(current_expr), Box::new(er)), rest_r)
					}
				}
				else if rest.is_front_of('^')
				{
					let rest = rest.drop(1).skip_while(is_space);
					let (rhs, rest_r) = parse_addsub_expr(rest);
					match rhs
					{
						Err(_) => (rhs, rest_r),
						Ok(er) => recursive(ExpressionNode::Xor(Box::new(current_expr), Box::new(er)), rest_r)
					}
				}
				else { (Ok(current_expr), rest) }
			}
			recursive(e, rest)
		}
	}
}
pub fn parse_expression(input: &[char]) -> (ParseResult<ExpressionNode>, &[char])
{
	parse_bit_expr(input)
}

#[cfg(test)]
mod test
{
	use itertools::Itertools;

	#[test] fn parse_define()
	{
		let testcase = ".define DEFAULT_BITS	2";
		assert_eq!(super::parse_define(&testcase.chars().collect_vec()).unwrap(), ("DEFAULT_BITS".to_owned(), "2".to_owned()));
	}
	#[test] fn parse_primary_terms()
	{
		let testcase = "PS_RENDER_BACKGROUND,";
		let testcase_collect = testcase.chars().collect_vec();
		let res = super::parse_primary_terms(&testcase_collect);
		assert_eq!(res.0.unwrap(), super::ExpressionNode::ConstantRef(&testcase_collect[..20]));
		assert_eq!(res.1, &testcase_collect[20..]);
		let testcase = "2.0";
		let testcase_collect = testcase.chars().collect_vec();
		let res = super::parse_primary_terms(&testcase_collect);
		assert_eq!(res.0.unwrap(), super::ExpressionNode::Floating(2.0));
		let testcase = "-6";
		let testcase_collect = testcase.chars().collect_vec();
		let res = super::parse_primary_terms(&testcase_collect);
		assert_eq!(res.0.unwrap(), super::ExpressionNode::Negated(Box::new(super::ExpressionNode::Number(6))));
	}
	#[test] fn parse_expression()
	{
		let testcase = "2 + 3";
		let testcase_collect = testcase.chars().collect_vec();
		let res = super::parse_expression(&testcase_collect);
		assert_eq!(res.0.unwrap(), super::ExpressionNode::Add(Box::new(super::ExpressionNode::Number(2)), Box::new(super::ExpressionNode::Number(3))));
		let testcase = "TOP | TRANSFER + 2, ";
		let testcase_collect = testcase.chars().collect_vec();
		let res = super::parse_expression(&testcase_collect);
		assert_eq!(res.0.unwrap(), super::ExpressionNode::Or(
			Box::new(super::ExpressionNode::ConstantRef(&testcase_collect[..3])),
			Box::new(super::ExpressionNode::Add(
				Box::new(super::ExpressionNode::ConstantRef(&testcase_collect[6..14])),
				Box::new(super::ExpressionNode::Number(2))
			))
		));
		assert_eq!(res.1, &testcase_collect[18..]);
	}
}
<|endoftext|>


<commit_before>use glib::object::Cast;
use glib::translate::ToGlibPtr;
use gtk::{self, BoxExt, ButtonSignals, ContainerExt, DialogExt, ScrolledWindowExt};
use gtk::{WidgetExt, WindowExt};
use gtk_sys;
use pango_sys::PangoWrapMode;
use sysinfo;

pub fn create_process_dialog(process: &sysinfo::Process, window: &gtk::Window,
                             start_time: u64, running_since: u64) {
    let flags = gtk_sys::GTK_DIALOG_DESTROY_WITH_PARENT |
                gtk_sys::GTK_DIALOG_USE_HEADER_BAR;
    let scroll = gtk::ScrolledWindow::new(None, None);
    let close_button = gtk::Button::new_with_label("Close");
    let vertical_layout = gtk::Box::new(gtk::Orientation::Vertical, 0);
    scroll.set_policy(gtk::PolicyType::Never, gtk::PolicyType::Automatic);
    let popup = gtk::Dialog::new_with_buttons(Some(&format!("Information about {}", process.name)),
                                              Some(window),
                                              flags,
                                              &[]);
    let area = popup.get_content_area();
    let running_since = if start_time > process.start_time {
        start_time - process.start_time + running_since
    } else {
        start_time + running_since - process.start_time
    };
    let mut text = format!("name: {}\n\
                            pid: {}\n\
                            command: {}\n\
                            executable path: {}\n\
                            current working directory: {}\n\
                            root directory: {}\n\
                            memory usage: {} kB\n\
                            cpu usage: {}%\n\n\
                            Running since {} seconds\n\n\
                            environment:",
                            process.name,
                            process.pid,
                            process.cmd,
                            process.exe,
                            process.cwd,
                            process.root,
                            process.memory,
                            process.cpu_usage,
                            running_since);
    for env in process.environ.iter() {
        text.push_str(&format!("\n{:?}", env));
    }
    let label = gtk::Label::new(Some(&text));
    label.set_selectable(true);
    label.set_line_wrap(true);
    //label.set_line_wrap_mode(gtk::WrapMode::Char);
    unsafe { gtk_sys::gtk_label_set_line_wrap_mode(label.to_glib_none().0, PangoWrapMode::Char) };
    scroll.add(&label);
    vertical_layout.pack_start(&scroll, true, true, 0);
    vertical_layout.pack_start(&close_button, false, true, 0);
    vertical_layout.set_spacing(10);
    area.pack_start(&vertical_layout, true, true, 0);
    popup.set_size_request(400, 600);
    let popup = popup.upcast::<gtk::Window>();
    popup.set_resizable(false);
    popup.show_all();
    close_button.connect_clicked(move |_| {
        popup.destroy();
    });
}
<commit_msg>Fix backline issue in information dialog<commit_after>use glib::object::Cast;
use glib::translate::ToGlibPtr;
use gtk::{self, BoxExt, ButtonSignals, ContainerExt, DialogExt, ScrolledWindowExt};
use gtk::{WidgetExt, WindowExt};
use gtk_sys;
use pango_sys::PangoWrapMode;
use sysinfo;

pub fn create_process_dialog(process: &sysinfo::Process, window: &gtk::Window,
                             start_time: u64, running_since: u64) {
    let flags = gtk_sys::GTK_DIALOG_DESTROY_WITH_PARENT |
                gtk_sys::GTK_DIALOG_USE_HEADER_BAR;
    let scroll = gtk::ScrolledWindow::new(None, None);
    let close_button = gtk::Button::new_with_label("Close");
    let vertical_layout = gtk::Box::new(gtk::Orientation::Vertical, 0);
    scroll.set_policy(gtk::PolicyType::Automatic, gtk::PolicyType::Automatic);
    let popup = gtk::Dialog::new_with_buttons(Some(&format!("Information about {}", process.name)),
                                              Some(window),
                                              flags,
                                              &[]);
    let area = popup.get_content_area();
    let running_since = if start_time > process.start_time {
        start_time - process.start_time + running_since
    } else {
        start_time + running_since - process.start_time
    };
    let mut text = format!("name: {}\n\
                            pid: {}\n\
                            command: {}\n\
                            executable path: {}\n\
                            current working directory: {}\n\
                            root directory: {}\n\
                            memory usage: {} kB\n\
                            cpu usage: {}%\n\n\
                            Running since {} seconds\n\n\
                            environment:",
                            process.name,
                            process.pid,
                            process.cmd,
                            process.exe,
                            process.cwd,
                            process.root,
                            process.memory,
                            process.cpu_usage,
                            running_since);
    for env in process.environ.iter() {
        text.push_str(&format!("\n{:?}", env));
    }
    let label = gtk::Label::new(Some(&text));
    label.set_selectable(true);
    label.set_line_wrap(true);
    //label.set_line_wrap_mode(gtk::WrapMode::Char);
    unsafe { gtk_sys::gtk_label_set_line_wrap_mode(label.to_glib_none().0, PangoWrapMode::Char) };
    scroll.add(&label);
    vertical_layout.pack_start(&scroll, true, true, 0);
    vertical_layout.pack_start(&close_button, false, true, 0);
    vertical_layout.set_spacing(10);
    area.pack_start(&vertical_layout, true, true, 0);
    popup.set_size_request(500, 700);
    let popup = popup.upcast::<gtk::Window>();
    popup.set_resizable(false);
    popup.show_all();
    close_button.connect_clicked(move |_| {
        popup.destroy();
    });
}
<|endoftext|>


<commit_before>#![crate_type = "bin"]

extern crate gtk;
extern crate glib;
extern crate sysinfo;

use gtk::{Orientation, Type, Widget};
use gtk::prelude::*;

use sysinfo::*;

use std::cell::{Cell, RefCell};
use std::collections::{HashMap, HashSet};
use std::rc::Rc;

struct NoteBook {
    notebook: gtk::Notebook,
    tabs: Vec<gtk::Box>,
}

impl NoteBook {
    fn new() -> NoteBook {
        NoteBook {
            notebook: gtk::Notebook::new(),
            tabs: Vec::new(),
        }
    }

    fn create_tab(&mut self, title: &str, widget: &Widget) -> Option<u32> {
        let label = gtk::Label::new(Some(title));
        let tab = gtk::Box::new(Orientation::Horizontal, 0);

        tab.pack_start(&label, false, false, 0);
        tab.show_all();

        let index = self.notebook.append_page(widget, Some(&tab));

        self.tabs.push(tab);

        Some(index)
    }
}

#[allow(dead_code)]
struct Procs {
    left_tree: gtk::TreeView,
    scroll: gtk::ScrolledWindow,
    current_pid: Rc<Cell<Option<i64>>>,
    kill_button: gtk::Button,
    vertical_layout: gtk::Box,
    list_store: gtk::ListStore,
    columns: Vec<gtk::TreeViewColumn>,
}

impl Procs {
    pub fn new(proc_list: &HashMap<usize, Process>, note: &mut NoteBook) -> Procs {
        let left_tree = gtk::TreeView::new();
        let scroll = gtk::ScrolledWindow::new(None, None);
        let current_pid = Rc::new(Cell::new(None));
        let kill_button = gtk::Button::new_with_label("End task");
        let current_pid1 = current_pid.clone();
        let kill_button1 = kill_button.clone();

        scroll.set_min_content_height(800);
        scroll.set_min_content_width(600);

        let mut columns : Vec<gtk::TreeViewColumn> = Vec::new();

        let list_store = gtk::ListStore::new(&[
            // The first four columns of the model are going to be visible in the view.
            Type::I64,       // pid
            Type::String,    // name
            Type::String,    // CPU
            Type::U32,       // mem
            // These two will serve as keys when sorting by process name and CPU usage.
            Type::String,    // name_lowercase
            Type::F32,       // CPU_f32
        ]);

        append_column("pid", &mut columns, &left_tree);
        append_column("process name", &mut columns, &left_tree);
        append_column("cpu usage", &mut columns, &left_tree);
        append_column("memory usage (in kB)", &mut columns, &left_tree);

        // When we click the "name" column the order is defined by the
        // "name_lowercase" effectively making the built-in comparator ignore case.
        columns[1].set_sort_column_id(4);
        // Likewise clicking the "CPU" column sorts by the "CPU_f32" one because
        // we want the order to be numerical not lexicographical.
        columns[2].set_sort_column_id(5);

        for (_, pro) in proc_list {
            create_and_fill_model(&list_store, pro.pid, &pro.cmd, &pro.name, pro.cpu_usage,
                                  pro.memory);
        }

        left_tree.set_model(Some(&list_store));
        left_tree.set_headers_visible(true);
        scroll.add(&left_tree);
        let vertical_layout = gtk::Box::new(gtk::Orientation::Vertical, 0);

        left_tree.connect_cursor_changed(move |tree_view| {
            let selection = tree_view.get_selection();
            if let Some((model, iter)) = selection.get_selected() {
                let pid = Some(model.get_value(&iter, 0).get().unwrap());
                current_pid1.set(pid);
                kill_button1.set_sensitive(true);
            } else {
                current_pid1.set(None);
                kill_button1.set_sensitive(false);
            }
        });
        kill_button.set_sensitive(false);

        vertical_layout.add(&scroll);
        vertical_layout.add(&kill_button);
        let vertical_layout : Widget = vertical_layout.upcast();

        note.create_tab("Process list", &vertical_layout);
        Procs {
            left_tree: left_tree,
            scroll: scroll,
            current_pid: current_pid,
            kill_button: kill_button.clone(),
            vertical_layout: vertical_layout.downcast::<gtk::Box>().unwrap(),
            list_store: list_store,
            columns: columns,
        }
    }
}

fn append_column(title: &str, v: &mut Vec<gtk::TreeViewColumn>, left_tree: &gtk::TreeView) {
    let id = v.len() as i32;
    let renderer = gtk::CellRendererText::new();

    let column = gtk::TreeViewColumn::new();
    column.set_title(title);
    column.set_resizable(true);
    column.pack_start(&renderer, true);
    column.add_attribute(&renderer, "text", id);
    column.set_clickable(true);
    column.set_sort_column_id(id);
    left_tree.append_column(&column);
    v.push(column);
}

fn create_and_fill_model(list_store: &gtk::ListStore, pid: i64, cmdline: &str, name: &str,
                         cpu: f32, memory: u64) {
    if cmdline.len() < 1 {
        return;
    }
    list_store.insert_with_values(None,
                                  &[0, 1, 2, 3, 4, 5],
                                  &[&pid,
                                    &name,
                                    &format!("{:.1}", cpu),
                                    &memory,
                                    &name.to_lowercase(),
                                    &cpu
                                   ]);
}

fn update_window(list: &gtk::ListStore, system: &Rc<RefCell<sysinfo::System>>,
                 info: &mut DisplaySysInfo) {
    let mut system = system.borrow_mut();
    system.refresh_all();
    info.update_ram_display(&system);
    info.update_process_display(&system);
    let entries: &HashMap<usize, Process> = system.get_process_list();
    let mut seen: HashSet<usize> = HashSet::new();

    if let Some(mut iter) = list.get_iter_first() {
        let mut valid = true;
        while valid {
            let pid = list.get_value(&iter, 0).get::<i64>().unwrap() as usize;
            if let Some(p) = entries.get(&(pid)) {
                list.set(&iter,
                         &[2, 3, 5],
                         &[&format!("{:.1}", p.cpu_usage), &p.memory, &p.cpu_usage]);
                valid = list.iter_next(&mut iter);
                seen.insert(pid);
            } else {
                valid = list.remove(&mut iter);
            }
        }
    }

    for (pid, pro) in entries.iter() {
        if !seen.contains(pid) {
            create_and_fill_model(list, pro.pid, &pro.cmd, &pro.name, pro.cpu_usage, pro.memory);
        }
    }
}

#[allow(dead_code)]
struct DisplaySysInfo {
    procs : Rc<RefCell<Vec<gtk::ProgressBar>>>,
    ram : gtk::ProgressBar,
    swap : gtk::ProgressBar,
    vertical_layout : gtk::Box,
    components: Vec<gtk::Label>,
}

impl DisplaySysInfo {
    pub fn new(sys1: Rc<RefCell<sysinfo::System>>, note: &mut NoteBook) -> DisplaySysInfo {
        let vertical_layout = gtk::Box::new(gtk::Orientation::Vertical, 0);
        let mut procs = Vec::new();
        let ram = gtk::ProgressBar::new();
        let swap = gtk::ProgressBar::new();
        let scroll = gtk::ScrolledWindow::new(None, None);
        let mut components = vec!();

        ram.set_show_text(true);
        swap.set_show_text(true);
        vertical_layout.set_spacing(5);

        let mut i = 0;
        let mut total = false;

        vertical_layout.pack_start(&gtk::Label::new(Some("Memory usage")), false, false, 15);
        vertical_layout.add(&ram);
        vertical_layout.pack_start(&gtk::Label::new(Some("Swap usage")), false, false, 15);
        vertical_layout.add(&swap);
        vertical_layout.pack_start(&gtk::Label::new(Some("Total CPU usage")), false, false, 15);
        for pro in sys1.borrow().get_processor_list() {
            if total {
                procs.push(gtk::ProgressBar::new());
                let p : &gtk::ProgressBar = &procs[i];
                let l = gtk::Label::new(Some(&format!("{}", i)));
                let horizontal_layout = gtk::Box::new(gtk::Orientation::Horizontal, 0);

                p.set_text(Some(&format!("{:.2} %", pro.get_cpu_usage() * 100.)));
                p.set_show_text(true);
                p.set_fraction(pro.get_cpu_usage() as f64);
                horizontal_layout.pack_start(&l, false, false, 5);
                horizontal_layout.pack_start(p, true, true, 5);
                vertical_layout.add(&horizontal_layout);
            } else {
                procs.push(gtk::ProgressBar::new());
                let p : &gtk::ProgressBar = &procs[i];

                p.set_text(Some(&format!("{:.2} %", pro.get_cpu_usage() * 100.)));
                p.set_show_text(true);
                p.set_fraction(pro.get_cpu_usage() as f64);

                vertical_layout.add(p);
                vertical_layout.pack_start(&gtk::Label::new(Some("Process usage")), false,
                                           false, 15);
                total = true;
            }
            i += 1;
        }
        if sys1.borrow().get_components_list().len() > 0 {
            vertical_layout.pack_start(&gtk::Label::new(Some("Components' temperature")), false, false, 15);
            for component in sys1.borrow().get_components_list() {
                let horizontal_layout = gtk::Box::new(gtk::Orientation::Horizontal, 10);
                let temp = gtk::Label::new(Some(&format!("{:.1} °C", component.temperature)));
                horizontal_layout.pack_start(&gtk::Label::new(Some(&component.label)), true, false, 0);
                horizontal_layout.pack_start(&temp, true, false, 0);
                horizontal_layout.set_homogeneous(true);
                vertical_layout.add(&horizontal_layout);
                components.push(temp);
            }
        }

        scroll.add(&vertical_layout);
        let scroll : Widget = scroll.upcast();
        note.create_tab("System usage", &scroll);
        let vertical_layout : gtk::Box = vertical_layout.downcast::<gtk::Box>().unwrap();

        let mut tmp = DisplaySysInfo {
            procs: Rc::new(RefCell::new(procs)),
            ram: ram,
            swap: swap,
            vertical_layout: vertical_layout,
            components: components,
        };
        tmp.update_ram_display(&sys1.borrow());
        tmp
    }

    pub fn update_ram_display(&mut self, sys: &sysinfo::System) {
        let total = sys.get_total_memory();
        let used = sys.get_used_memory();
        let disp = if total < 100000 {
            format!("{} / {}KB", used, total)
        } else if total < 10000000 {
            format!("{} / {}MB", used / 1000, total / 1000)
        } else if total < 10000000000 {
            format!("{} / {}GB", used / 1000000, total / 1000000)
        } else {
            format!("{} / {}TB", used / 1000000000, total / 1000000000)
        };

        self.ram.set_text(Some(&disp));
        self.ram.set_fraction(used as f64 / total as f64);

        let total = sys.get_total_swap();
        let used = total - sys.get_used_swap();
        let disp = if total < 100000 {
            format!("{} / {}KB", used, total)
        } else if total < 10000000 {
            format!("{} / {}MB", used / 1000, total / 1000)
        } else if total < 10000000000 {
            format!("{} / {}GB", used / 1000000, total / 1000000)
        } else {
            format!("{} / {}TB", used / 1000000000, total / 1000000000)
        };

        self.swap.set_text(Some(&disp));
        self.swap.set_fraction(used as f64 / total as f64);

        for (component, label) in sys.get_components_list().iter().zip(self.components.iter()) {
            label.set_text(&format!("{:.1} °C", component.temperature));
        }
    }

    pub fn update_process_display(&mut self, sys: &sysinfo::System) {
        let v = &*self.procs.borrow_mut();
        let mut i = 0;

        for pro in sys.get_processor_list() {
            v[i].set_text(Some(&format!("{:.1} %", pro.get_cpu_usage() * 100.)));
            v[i].set_show_text(true);
            v[i].set_fraction(pro.get_cpu_usage() as f64);
            i += 1;
        }
    }
}

fn main() {
    gtk::init().expect("GTK couldn't start normally");

    let window = gtk::Window::new(gtk::WindowType::Toplevel);
    let sys = Rc::new(RefCell::new(sysinfo::System::new()));
    let mut note = NoteBook::new();
    let procs = Procs::new(sys.borrow().get_process_list(), &mut note);
    let current_pid = procs.current_pid.clone();
    let sys1 = sys.clone();

    window.set_title("Process viewer");
    window.set_position(gtk::WindowPosition::Center);

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(false)
    });

    sys.borrow_mut().refresh_all();
    procs.kill_button.connect_clicked(move |_| {
        let sys = sys1.borrow();
        if let Some(process) = current_pid.get().and_then(|pid| sys.get_process(pid)) {
            process.kill(Signal::Kill);
        }
    });

    let mut display_tab = DisplaySysInfo::new(sys.clone(), &mut note);

    gtk::timeout_add(1500, move || {
        // first part, deactivate sorting
        let sorted = procs.list_store.get_sort_column_id();
        procs.list_store.set_unsorted();

        // we update the tree view
        update_window(&procs.list_store, &sys, &mut display_tab);

        // we re-enable the sorting
        if let Some((col, order)) = sorted {
            procs.list_store.set_sort_column_id(col, order);
        }
        glib::Continue(true)
    });

    window.add(&note.notebook);
    window.show_all();
    gtk::main();
}
<commit_msg>Expand scrolledWindow by default<commit_after>#![crate_type = "bin"]

extern crate gtk;
extern crate glib;
extern crate sysinfo;

use gtk::{Orientation, Type, Widget};
use gtk::prelude::*;

use sysinfo::*;

use std::cell::{Cell, RefCell};
use std::collections::{HashMap, HashSet};
use std::rc::Rc;

struct NoteBook {
    notebook: gtk::Notebook,
    tabs: Vec<gtk::Box>,
}

impl NoteBook {
    fn new() -> NoteBook {
        NoteBook {
            notebook: gtk::Notebook::new(),
            tabs: Vec::new(),
        }
    }

    fn create_tab(&mut self, title: &str, widget: &Widget) -> Option<u32> {
        let label = gtk::Label::new(Some(title));
        let tab = gtk::Box::new(Orientation::Horizontal, 0);

        tab.pack_start(&label, false, false, 0);
        tab.show_all();

        let index = self.notebook.append_page(widget, Some(&tab));

        self.tabs.push(tab);

        Some(index)
    }
}

#[allow(dead_code)]
struct Procs {
    left_tree: gtk::TreeView,
    scroll: gtk::ScrolledWindow,
    current_pid: Rc<Cell<Option<i64>>>,
    kill_button: gtk::Button,
    vertical_layout: gtk::Box,
    list_store: gtk::ListStore,
    columns: Vec<gtk::TreeViewColumn>,
}

impl Procs {
    pub fn new(proc_list: &HashMap<usize, Process>, note: &mut NoteBook) -> Procs {
        let left_tree = gtk::TreeView::new();
        let scroll = gtk::ScrolledWindow::new(None, None);
        let current_pid = Rc::new(Cell::new(None));
        let kill_button = gtk::Button::new_with_label("End task");
        let current_pid1 = current_pid.clone();
        let kill_button1 = kill_button.clone();

        scroll.set_min_content_height(800);
        scroll.set_min_content_width(600);

        let mut columns : Vec<gtk::TreeViewColumn> = Vec::new();

        let list_store = gtk::ListStore::new(&[
            // The first four columns of the model are going to be visible in the view.
            Type::I64,       // pid
            Type::String,    // name
            Type::String,    // CPU
            Type::U32,       // mem
            // These two will serve as keys when sorting by process name and CPU usage.
            Type::String,    // name_lowercase
            Type::F32,       // CPU_f32
        ]);

        append_column("pid", &mut columns, &left_tree);
        append_column("process name", &mut columns, &left_tree);
        append_column("cpu usage", &mut columns, &left_tree);
        append_column("memory usage (in kB)", &mut columns, &left_tree);

        // When we click the "name" column the order is defined by the
        // "name_lowercase" effectively making the built-in comparator ignore case.
        columns[1].set_sort_column_id(4);
        // Likewise clicking the "CPU" column sorts by the "CPU_f32" one because
        // we want the order to be numerical not lexicographical.
        columns[2].set_sort_column_id(5);

        for (_, pro) in proc_list {
            create_and_fill_model(&list_store, pro.pid, &pro.cmd, &pro.name, pro.cpu_usage,
                                  pro.memory);
        }

        left_tree.set_model(Some(&list_store));
        left_tree.set_headers_visible(true);
        scroll.add(&left_tree);
        let vertical_layout = gtk::Box::new(gtk::Orientation::Vertical, 0);

        left_tree.connect_cursor_changed(move |tree_view| {
            let selection = tree_view.get_selection();
            if let Some((model, iter)) = selection.get_selected() {
                let pid = Some(model.get_value(&iter, 0).get().unwrap());
                current_pid1.set(pid);
                kill_button1.set_sensitive(true);
            } else {
                current_pid1.set(None);
                kill_button1.set_sensitive(false);
            }
        });
        kill_button.set_sensitive(false);

        vertical_layout.pack_start(&scroll, true, true, 0);
        vertical_layout.pack_start(&kill_button, false, true, 0);
        let vertical_layout : Widget = vertical_layout.upcast();

        note.create_tab("Process list", &vertical_layout);
        Procs {
            left_tree: left_tree,
            scroll: scroll,
            current_pid: current_pid,
            kill_button: kill_button.clone(),
            vertical_layout: vertical_layout.downcast::<gtk::Box>().unwrap(),
            list_store: list_store,
            columns: columns,
        }
    }
}

fn append_column(title: &str, v: &mut Vec<gtk::TreeViewColumn>, left_tree: &gtk::TreeView) {
    let id = v.len() as i32;
    let renderer = gtk::CellRendererText::new();

    let column = gtk::TreeViewColumn::new();
    column.set_title(title);
    column.set_resizable(true);
    column.pack_start(&renderer, true);
    column.add_attribute(&renderer, "text", id);
    column.set_clickable(true);
    column.set_sort_column_id(id);
    left_tree.append_column(&column);
    v.push(column);
}

fn create_and_fill_model(list_store: &gtk::ListStore, pid: i64, cmdline: &str, name: &str,
                         cpu: f32, memory: u64) {
    if cmdline.len() < 1 {
        return;
    }
    list_store.insert_with_values(None,
                                  &[0, 1, 2, 3, 4, 5],
                                  &[&pid,
                                    &name,
                                    &format!("{:.1}", cpu),
                                    &memory,
                                    &name.to_lowercase(),
                                    &cpu
                                   ]);
}

fn update_window(list: &gtk::ListStore, system: &Rc<RefCell<sysinfo::System>>,
                 info: &mut DisplaySysInfo) {
    let mut system = system.borrow_mut();
    system.refresh_all();
    info.update_ram_display(&system);
    info.update_process_display(&system);
    let entries: &HashMap<usize, Process> = system.get_process_list();
    let mut seen: HashSet<usize> = HashSet::new();

    if let Some(mut iter) = list.get_iter_first() {
        let mut valid = true;
        while valid {
            let pid = list.get_value(&iter, 0).get::<i64>().unwrap() as usize;
            if let Some(p) = entries.get(&(pid)) {
                list.set(&iter,
                         &[2, 3, 5],
                         &[&format!("{:.1}", p.cpu_usage), &p.memory, &p.cpu_usage]);
                valid = list.iter_next(&mut iter);
                seen.insert(pid);
            } else {
                valid = list.remove(&mut iter);
            }
        }
    }

    for (pid, pro) in entries.iter() {
        if !seen.contains(pid) {
            create_and_fill_model(list, pro.pid, &pro.cmd, &pro.name, pro.cpu_usage, pro.memory);
        }
    }
}

#[allow(dead_code)]
struct DisplaySysInfo {
    procs : Rc<RefCell<Vec<gtk::ProgressBar>>>,
    ram : gtk::ProgressBar,
    swap : gtk::ProgressBar,
    vertical_layout : gtk::Box,
    components: Vec<gtk::Label>,
}

impl DisplaySysInfo {
    pub fn new(sys1: Rc<RefCell<sysinfo::System>>, note: &mut NoteBook) -> DisplaySysInfo {
        let vertical_layout = gtk::Box::new(gtk::Orientation::Vertical, 0);
        let mut procs = Vec::new();
        let ram = gtk::ProgressBar::new();
        let swap = gtk::ProgressBar::new();
        let scroll = gtk::ScrolledWindow::new(None, None);
        let mut components = vec!();

        ram.set_show_text(true);
        swap.set_show_text(true);
        vertical_layout.set_spacing(5);

        let mut i = 0;
        let mut total = false;

        vertical_layout.pack_start(&gtk::Label::new(Some("Memory usage")), false, false, 15);
        vertical_layout.add(&ram);
        vertical_layout.pack_start(&gtk::Label::new(Some("Swap usage")), false, false, 15);
        vertical_layout.add(&swap);
        vertical_layout.pack_start(&gtk::Label::new(Some("Total CPU usage")), false, false, 15);
        for pro in sys1.borrow().get_processor_list() {
            if total {
                procs.push(gtk::ProgressBar::new());
                let p : &gtk::ProgressBar = &procs[i];
                let l = gtk::Label::new(Some(&format!("{}", i)));
                let horizontal_layout = gtk::Box::new(gtk::Orientation::Horizontal, 0);

                p.set_text(Some(&format!("{:.2} %", pro.get_cpu_usage() * 100.)));
                p.set_show_text(true);
                p.set_fraction(pro.get_cpu_usage() as f64);
                horizontal_layout.pack_start(&l, false, false, 5);
                horizontal_layout.pack_start(p, true, true, 5);
                vertical_layout.add(&horizontal_layout);
            } else {
                procs.push(gtk::ProgressBar::new());
                let p : &gtk::ProgressBar = &procs[i];

                p.set_text(Some(&format!("{:.2} %", pro.get_cpu_usage() * 100.)));
                p.set_show_text(true);
                p.set_fraction(pro.get_cpu_usage() as f64);

                vertical_layout.add(p);
                vertical_layout.pack_start(&gtk::Label::new(Some("Process usage")), false,
                                           false, 15);
                total = true;
            }
            i += 1;
        }
        if sys1.borrow().get_components_list().len() > 0 {
            vertical_layout.pack_start(&gtk::Label::new(Some("Components' temperature")), false, false, 15);
            for component in sys1.borrow().get_components_list() {
                let horizontal_layout = gtk::Box::new(gtk::Orientation::Horizontal, 10);
                let temp = gtk::Label::new(Some(&format!("{:.1} °C", component.temperature)));
                horizontal_layout.pack_start(&gtk::Label::new(Some(&component.label)), true, false, 0);
                horizontal_layout.pack_start(&temp, true, false, 0);
                horizontal_layout.set_homogeneous(true);
                vertical_layout.add(&horizontal_layout);
                components.push(temp);
            }
        }

        scroll.add(&vertical_layout);
        let scroll : Widget = scroll.upcast();
        note.create_tab("System usage", &scroll);
        let vertical_layout : gtk::Box = vertical_layout.downcast::<gtk::Box>().unwrap();

        let mut tmp = DisplaySysInfo {
            procs: Rc::new(RefCell::new(procs)),
            ram: ram,
            swap: swap,
            vertical_layout: vertical_layout,
            components: components,
        };
        tmp.update_ram_display(&sys1.borrow());
        tmp
    }

    pub fn update_ram_display(&mut self, sys: &sysinfo::System) {
        let total = sys.get_total_memory();
        let used = sys.get_used_memory();
        let disp = if total < 100000 {
            format!("{} / {}KB", used, total)
        } else if total < 10000000 {
            format!("{} / {}MB", used / 1000, total / 1000)
        } else if total < 10000000000 {
            format!("{} / {}GB", used / 1000000, total / 1000000)
        } else {
            format!("{} / {}TB", used / 1000000000, total / 1000000000)
        };

        self.ram.set_text(Some(&disp));
        self.ram.set_fraction(used as f64 / total as f64);

        let total = sys.get_total_swap();
        let used = total - sys.get_used_swap();
        let disp = if total < 100000 {
            format!("{} / {}KB", used, total)
        } else if total < 10000000 {
            format!("{} / {}MB", used / 1000, total / 1000)
        } else if total < 10000000000 {
            format!("{} / {}GB", used / 1000000, total / 1000000)
        } else {
            format!("{} / {}TB", used / 1000000000, total / 1000000000)
        };

        self.swap.set_text(Some(&disp));
        self.swap.set_fraction(used as f64 / total as f64);

        for (component, label) in sys.get_components_list().iter().zip(self.components.iter()) {
            label.set_text(&format!("{:.1} °C", component.temperature));
        }
    }

    pub fn update_process_display(&mut self, sys: &sysinfo::System) {
        let v = &*self.procs.borrow_mut();
        let mut i = 0;

        for pro in sys.get_processor_list() {
            v[i].set_text(Some(&format!("{:.1} %", pro.get_cpu_usage() * 100.)));
            v[i].set_show_text(true);
            v[i].set_fraction(pro.get_cpu_usage() as f64);
            i += 1;
        }
    }
}

fn main() {
    gtk::init().expect("GTK couldn't start normally");

    let window = gtk::Window::new(gtk::WindowType::Toplevel);
    let sys = Rc::new(RefCell::new(sysinfo::System::new()));
    let mut note = NoteBook::new();
    let procs = Procs::new(sys.borrow().get_process_list(), &mut note);
    let current_pid = procs.current_pid.clone();
    let sys1 = sys.clone();

    window.set_title("Process viewer");
    window.set_position(gtk::WindowPosition::Center);

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(false)
    });

    sys.borrow_mut().refresh_all();
    procs.kill_button.connect_clicked(move |_| {
        let sys = sys1.borrow();
        if let Some(process) = current_pid.get().and_then(|pid| sys.get_process(pid)) {
            process.kill(Signal::Kill);
        }
    });

    let mut display_tab = DisplaySysInfo::new(sys.clone(), &mut note);

    gtk::timeout_add(1500, move || {
        // first part, deactivate sorting
        let sorted = procs.list_store.get_sort_column_id();
        procs.list_store.set_unsorted();

        // we update the tree view
        update_window(&procs.list_store, &sys, &mut display_tab);

        // we re-enable the sorting
        if let Some((col, order)) = sorted {
            procs.list_store.set_sort_column_id(col, order);
        }
        glib::Continue(true)
    });

    window.add(&note.notebook);
    window.show_all();
    gtk::main();
}
<|endoftext|>