<commit_before>//! The module defines song structs and methods.

use time::{strptime, Duration, Tm};

use std::collections::BTreeMap;
use std::str::FromStr;
use std::fmt;

use error::{Error, ParseError};
use convert::FromIter;

/// Song ID
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Default, RustcEncodable)]
pub struct Id(pub u32);

impl fmt::Display for Id {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

/// Song place in the queue
#[derive(Debug, Copy, Clone, PartialEq, Default, RustcEncodable)]
pub struct QueuePlace {
    /// song ID
    pub id: Id,
    /// absolute zero-based song position
    pub pos: u32,
    /// song priority, if present, defaults to 0
    pub prio: u8
}

/// Song range
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Range(pub Duration, pub Option<Duration>);

impl Default for Range {
    fn default() -> Range {
        Range(Duration::seconds(0), None)
    }
}

impl fmt::Display for Range {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.num_seconds().fmt(f)
            .and_then(|_| f.write_str(":"))
            .and_then(|_| self.1.map(|v| v.num_seconds().fmt(f)).unwrap_or(Ok(())))
    }
}

impl FromStr for Range {
    type Err = ParseError;
    fn from_str(s: &str) -> Result<Range, ParseError> {
        let mut splits = s.split('-').flat_map(|v| v.parse().into_iter());
        match (splits.next(), splits.next()) {
            (Some(s), Some(e)) => Ok(Range(Duration::seconds(s), Some(Duration::seconds(e)))),
            (None, Some(e)) => Ok(Range(Duration::zero(), Some(Duration::seconds(e)))),
            (Some(s), None) => Ok(Range(Duration::seconds(s), None)),
            (None, None) => Ok(Range(Duration::zero(), None)),
        }
    }
}

/// Song data
#[derive(Debug, Clone, PartialEq, Default)]
pub struct Song {
    /// filename
    pub file: String,
    /// name (for streams)
    pub name: Option<String>,
    /// last modification time
    pub last_mod: Option<Tm>,
    /// duration (in seconds resolution)
    pub duration: Option<Duration>,
    /// place in the queue (if queued for playback)
    pub place: Option<QueuePlace>,
    /// range to play (if queued for playback and range was set)
    pub range: Option<Range>,
    /// arbitrary tags, like album, artist etc
    pub tags: BTreeMap<String, String>,
}

impl FromIter for Song {
    /// build song from map
    fn from_iter<I: Iterator<Item=Result<(String, String), Error>>>(iter: I) -> Result<Song, Error> {
        let mut result = Song::default();

        for res in iter {
            let line = try!(res);
            match &*line.0 {
                "file" => result.file = line.1.to_owned(),
                "Last-Modified" => result.last_mod = try!(strptime(&*line.1, "%Y-%m-%dT%H:%M:%S%Z").map_err(ParseError::BadTime).map(Some)),
                "Name" => result.name = Some(line.1.to_owned()),
                "Time" => result.duration = Some(Duration::seconds(try!(line.1.parse()))),
                "Range" => result.range = Some(try!(line.1.parse())),
                "Id" => match result.place {
                    None => result.place = Some(QueuePlace { id: Id(try!(line.1.parse())), pos: 0, prio: 0 }),
                    Some(ref mut place) => place.id = Id(try!(line.1.parse())),
                },
                "Pos" => match result.place {
                    None => result.place = Some(QueuePlace { pos: try!(line.1.parse()), id: Id(0), prio: 0 }),
                    Some(ref mut place) => place.pos = try!(line.1.parse()),
                },
                "Prio" => match result.place {
                    None => result.place = Some(QueuePlace { prio: try!(line.1.parse()), id: Id(0), pos: 0 }),
                    Some(ref mut place) => place.prio = try!(line.1.parse()),
                },
                _ => { result.tags.insert(line.0, line.1); }
            }
        }

        Ok(result)
    }
}

<commit_msg>impl encodable for song<commit_after>//! The module defines song structs and methods.

use time::{strptime, Duration, Tm};
use rustc_serialize::{Encodable, Encoder};

use std::collections::BTreeMap;
use std::str::FromStr;
use std::fmt;

use error::{Error, ParseError};
use convert::FromIter;

/// Song ID
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Default, RustcEncodable)]
pub struct Id(pub u32);

impl fmt::Display for Id {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

/// Song place in the queue
#[derive(Debug, Copy, Clone, PartialEq, Default, RustcEncodable)]
pub struct QueuePlace {
    /// song ID
    pub id: Id,
    /// absolute zero-based song position
    pub pos: u32,
    /// song priority, if present, defaults to 0
    pub prio: u8
}

/// Song range
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Range(pub Duration, pub Option<Duration>);

impl Encodable for Range {
    fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
        e.emit_tuple(2, |e|
            e.emit_tuple_arg(0, |e| e.emit_i64(self.0.num_seconds())).and_then(|_|
            e.emit_tuple_arg(1, |e| e.emit_option(|e| self.1.map(|d| e.emit_option_some(|e| d.num_seconds().encode(e))).unwrap_or_else(|| e.emit_option_none())))))
    }
}

impl Default for Range {
    fn default() -> Range {
        Range(Duration::seconds(0), None)
    }
}

impl fmt::Display for Range {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.num_seconds().fmt(f)
            .and_then(|_| f.write_str(":"))
            .and_then(|_| self.1.map(|v| v.num_seconds().fmt(f)).unwrap_or(Ok(())))
    }
}

impl FromStr for Range {
    type Err = ParseError;
    fn from_str(s: &str) -> Result<Range, ParseError> {
        let mut splits = s.split('-').flat_map(|v| v.parse().into_iter());
        match (splits.next(), splits.next()) {
            (Some(s), Some(e)) => Ok(Range(Duration::seconds(s), Some(Duration::seconds(e)))),
            (None, Some(e)) => Ok(Range(Duration::zero(), Some(Duration::seconds(e)))),
            (Some(s), None) => Ok(Range(Duration::seconds(s), None)),
            (None, None) => Ok(Range(Duration::zero(), None)),
        }
    }
}

/// Song data
#[derive(Debug, Clone, PartialEq, Default)]
pub struct Song {
    /// filename
    pub file: String,
    /// name (for streams)
    pub name: Option<String>,
    /// last modification time
    pub last_mod: Option<Tm>,
    /// duration (in seconds resolution)
    pub duration: Option<Duration>,
    /// place in the queue (if queued for playback)
    pub place: Option<QueuePlace>,
    /// range to play (if queued for playback and range was set)
    pub range: Option<Range>,
    /// arbitrary tags, like album, artist etc
    pub tags: BTreeMap<String, String>,
}

impl Encodable for Song {
    fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
        e.emit_struct("Song", 7, |e|
            e.emit_struct_field("file", 0, |e| self.file.encode(e)).and_then(|_|
            e.emit_struct_field("name", 1, |e| self.name.encode(e))).and_then(|_|
            e.emit_struct_field("last_mod", 2, |e| e.emit_option(
                    |e| self.last_mod.as_ref().map(|m| e.emit_option_some(|e| m.to_timespec().sec.encode(e))).unwrap_or_else(|| e.emit_option_none())))).and_then(|_|
            e.emit_struct_field("duration", 3, |e| e.emit_option(
                    |e| self.duration.as_ref().map(|d| e.emit_option_some(|e| d.num_seconds().encode(e))).unwrap_or_else(|| e.emit_option_none())
                    ))).and_then(|_|
            e.emit_struct_field("place", 4, |e| self.place.encode(e))).and_then(|_|
            e.emit_struct_field("range", 5, |e| self.range.encode(e))).and_then(|_|
            e.emit_struct_field("tags", 6, |e| self.tags.encode(e))))
    }
}

impl FromIter for Song {
    /// build song from map
    fn from_iter<I: Iterator<Item=Result<(String, String), Error>>>(iter: I) -> Result<Song, Error> {
        let mut result = Song::default();

        for res in iter {
            let line = try!(res);
            match &*line.0 {
                "file" => result.file = line.1.to_owned(),
                "Last-Modified" => result.last_mod = try!(strptime(&*line.1, "%Y-%m-%dT%H:%M:%S%Z").map_err(ParseError::BadTime).map(Some)),
                "Name" => result.name = Some(line.1.to_owned()),
                "Time" => result.duration = Some(Duration::seconds(try!(line.1.parse()))),
                "Range" => result.range = Some(try!(line.1.parse())),
                "Id" => match result.place {
                    None => result.place = Some(QueuePlace { id: Id(try!(line.1.parse())), pos: 0, prio: 0 }),
                    Some(ref mut place) => place.id = Id(try!(line.1.parse())),
                },
                "Pos" => match result.place {
                    None => result.place = Some(QueuePlace { pos: try!(line.1.parse()), id: Id(0), prio: 0 }),
                    Some(ref mut place) => place.pos = try!(line.1.parse()),
                },
                "Prio" => match result.place {
                    None => result.place = Some(QueuePlace { prio: try!(line.1.parse()), id: Id(0), pos: 0 }),
                    Some(ref mut place) => place.prio = try!(line.1.parse()),
                },
                _ => { result.tags.insert(line.0, line.1); }
            }
        }

        Ok(result)
    }
}

<|endoftext|>


<commit_before>extern crate orbclient;
extern crate sinulation;

use super::start;

#[cfg(target_os = "redox")]
use sinulation::Trig;

#[derive(Debug, Clone, Copy)]
pub struct Color {
    pub r: u8,
    pub g: u8,
    pub b: u8,
}

impl Color {
    pub fn new(r: u8, g: u8, b: u8) -> Color {
        Color {
            r: r,
            g: g,
            b: b,
        }
    }

    pub fn orb_color(&self) -> orbclient::color::Color {
        orbclient::color::Color::rgb(self.r, self.g, self.b)
    }
}

#[derive(Clone, Copy, Debug)]
pub struct FlatPoint {
    pub x: i32,
    pub y: i32,
}

/*impl FlatPoint {
    pub fn make_sdl(&self) -> sdl2::rect::Point {
        sdl2::rect::Point::new(self.x, self.y)
    }
}*/

#[derive(Clone, Copy, Debug)]
pub struct DepthPoint {
    pub x: f32,
    pub y: f32,
    pub z: f32,

    pub x_y: f32,
    pub x_z: f32,
    pub y_z: f32,

    last_x_y: f32,
    last_x_z: f32,
    last_y_z: f32,
}

impl DepthPoint {
    pub fn new(x: f32, y: f32, z: f32) -> DepthPoint {
        DepthPoint {
            x: x,
            y: y,
            z: z,

            x_y: 0.0,
            x_z: 0.0,
            y_z: 0.0,

            last_x_y: 0.0,
            last_x_z: 0.0,
            last_y_z: 0.0,
        }
    }

    pub fn flat_point(&mut self, engine_scr_x: u32, engine_scr_y: u32, offset_x: f32, offset_y: f32, offset_z: f32) -> FlatPoint {
        if self.z > -0.01 && self.z < 0.0 {
            self.z = 0.001
        }

        else if self.z < 0.1 { // Prevents division by nearly 0, that cause integer overflow/underflow
            self.z = 0.11;
        }

        FlatPoint {
            x: ((engine_scr_x as f32 * (self.x + offset_x) as f32/(self.z + offset_z)) + engine_scr_x as f32 / 2.0) as i32,
            y: ((engine_scr_x as f32 * (self.y + offset_y) as f32/(self.z + offset_z)) + engine_scr_y as f32 / 2.0) as i32,
        }
    }

    pub fn apply_camera_rotations(&mut self, engine: &start::Window) {
        use std::f32::consts::PI;

        let x_y = self.x_y;
        let x_z = self.x_z;
        let y_z = self.y_z;

        let last_x_y = self.last_x_y;
        let last_x_z = self.last_x_z;
        let last_y_z = self.last_y_z;

        self.camera_rotate_x_y(&engine, x_y - last_x_y);
        self.camera_rotate_x_z(&engine, x_z - last_x_z);
        self.camera_rotate_y_z(&engine, y_z - last_y_z);

        self.last_x_y = x_y;
        self.last_x_z = x_z;
        self.last_y_z = y_z;

        //normalize rotations
        if self.x_z > (PI * 2.0) {
            self.x_z -= (PI * 2.0);
        }

        if self.x_y > (PI * 2.0) {
            self.x_y -= (PI * 2.0);
        }

        if self.y_z > (PI * 2.0) {
            self.y_z -= (PI * 2.0);
        }
    }

    pub fn camera_rotate_x_y(&mut self, engine: &start::Window, angle: f32) {
        #[cfg(not(target_os = "redox"))]
        use std::f32;

        let s = f32::sin(angle);
        let c = f32::cos(angle);

        self.x -= engine.camera_x;
        self.y -= engine.camera_y;

        let new_x = self.x * c - self.y * s;
        let new_y = self.x * s + self.y * c;

        self.x = new_x + engine.camera_x;
        self.y = new_y + engine.camera_y;
    }

    pub fn camera_rotate_x_z(&mut self, engine: &start::Window, angle: f32) {
        #[cfg(not(target_os = "redox"))]
        use std::f32;

        let s = f32::sin(angle);
        let c = f32::cos(angle);

        self.x -= engine.camera_x;
        self.z -= engine.camera_z;

        let new_x = self.x * c - self.z * s;
        let new_z = self.x * s + self.z * c;

        self.x = new_x + engine.camera_x;
        self.z = new_z + engine.camera_z;
    }

    pub fn camera_rotate_y_z(&mut self, engine: &start::Window, angle: f32) {
        #[cfg(not(target_os = "redox"))]
        use std::f32;

        let s = f32::sin(angle);
        let c = f32::cos(angle);

        self.y -= engine.camera_y;
        self.z -= engine.camera_z;

        let new_y = self.y * c - self.z * s;
        let new_z = self.y * s + self.z * c;

        self.y = new_y + engine.camera_y;
        self.z = new_z + engine.camera_z;
    }

    pub fn coord_rotate_x_y(&mut self, x: f32, y: f32, angle: f32) {
        #[cfg(not(target_os = "redox"))]
        use std::f32;

        let s = f32::sin(angle);
        let c = f32::cos(angle);

        self.x -= x;
        self.y -= y;

        let new_x = self.x * c - self.y * s;
        let new_y = self.x * s + self.y * c;

        self.x = new_x + x;
        self.y = new_y + y;
    }

    pub fn coord_rotate_x_z(&mut self, x: f32, z: f32, angle: f32) {
        #[cfg(not(target_os = "redox"))]
        use std::f32;

        let s = f32::sin(angle);
        let c = f32::cos(angle);

        self.x -= x;
        self.z -= z;

        let new_x = self.x * c - self.z * s;
        let new_z = self.x * s + self.z * c;

        self.x = new_x + x;
        self.z = new_z + z;
    }

    pub fn coord_rotate_y_z(&mut self, y: f32, z: f32, angle: f32) {
        #[cfg(not(target_os = "redox"))]
        use std::f32;

        let s = f32::sin(angle);
        let c = f32::cos(angle);

        self.y -= y;
        self.z -= z;

        let new_y = self.y * c - self.z * s;
        let new_z = self.y * s + self.z * c;

        self.y = new_y + y;
        self.z = new_z + z;
    }
}

#[derive(Clone, Copy, Debug)]
pub struct Triangle {
    pub p1: DepthPoint,
    pub p2: DepthPoint,
    pub p3: DepthPoint,

    pub x: f32,
    pub y: f32,
    pub z: f32,

    pub x_y: f32,
    pub x_z: f32,
    pub y_z: f32,

    pub color: Color,
}

impl Triangle {
    pub fn new(p1: DepthPoint, p2: DepthPoint, p3: DepthPoint, x: f32, y: f32, z: f32, color: Color) -> Triangle {
        Triangle {
            p1: p1,
            p2: p2,
            p3: p3,

            x: x,
            y: y,
            z: z,

            x_y: 0.0,
            x_z: 0.0,
            y_z: 0.0,

            color: color,
        }
    }

    pub fn apply_camera_rotations(&mut self, engine: &start::Window) {
        self.p1.x_y += self.x_y;
        self.p1.x_z += self.x_z;
        self.p1.y_z += self.y_z;

        self.p2.x_y += self.x_y;
        self.p2.x_z += self.x_z;
        self.p2.y_z += self.y_z;

        self.p3.x_y += self.x_y;
        self.p3.x_z += self.x_z;
        self.p3.y_z += self.y_z;

        self.p1.apply_camera_rotations(&engine);
        self.p2.apply_camera_rotations(&engine);
        self.p3.apply_camera_rotations(&engine);

        self.p1.x_y -= self.x_y;
        self.p1.x_z -= self.x_z;
        self.p1.y_z -= self.y_z;

        self.p2.x_y -= self.x_y;
        self.p2.x_z -= self.x_z;
        self.p2.y_z -= self.y_z;

        self.p3.x_y -= self.x_y;
        self.p3.x_z -= self.x_z;
        self.p3.y_z -= self.y_z;
    }

    pub fn coord_rotate_x_y(&mut self, x: f32, y: f32, angle: f32) {
        self.p1.coord_rotate_x_y(x, y, angle);
        self.p2.coord_rotate_x_y(x, y, angle);
        self.p3.coord_rotate_x_y(x, y, angle);
    }

    pub fn coord_rotate_x_z(&mut self, x: f32, z: f32, angle: f32) {
        self.p1.coord_rotate_x_z(x, z, angle);
        self.p2.coord_rotate_x_z(x, z, angle);
        self.p3.coord_rotate_x_z(x, z, angle);
    }

    pub fn coord_rotate_y_z(&mut self, y: f32, z: f32, angle: f32) {
        self.p1.coord_rotate_y_z(y, z, angle);
        self.p2.coord_rotate_y_z(y, z, angle);
        self.p3.coord_rotate_y_z(y, z, angle);
    }
}

#[derive(Clone, Debug)]
pub struct TriangleGroup {
    pub triangles: Vec<Triangle>,
}

impl TriangleGroup {
    pub fn new(triangles: Vec<Triangle>) -> TriangleGroup {
        TriangleGroup {
            triangles: triangles
        }
    }
}
<commit_msg>Redox stuff again<commit_after>extern crate orbclient;
extern crate sinulation;

use super::start;

#[cfg(target_os = "redox")]
use sinulation::Trig;

#[derive(Debug, Clone, Copy)]
pub struct Color {
    pub r: u8,
    pub g: u8,
    pub b: u8,
}

impl Color {
    pub fn new(r: u8, g: u8, b: u8) -> Color {
        Color {
            r: r,
            g: g,
            b: b,
        }
    }

    pub fn orb_color(&self) -> orbclient::color::Color {
        orbclient::color::Color::rgb(self.r, self.g, self.b)
    }
}

#[derive(Clone, Copy, Debug)]
pub struct FlatPoint {
    pub x: i32,
    pub y: i32,
}

/*impl FlatPoint {
    pub fn make_sdl(&self) -> sdl2::rect::Point {
        sdl2::rect::Point::new(self.x, self.y)
    }
}*/

#[derive(Clone, Copy, Debug)]
pub struct DepthPoint {
    pub x: f32,
    pub y: f32,
    pub z: f32,

    pub x_y: f32,
    pub x_z: f32,
    pub y_z: f32,

    last_x_y: f32,
    last_x_z: f32,
    last_y_z: f32,
}

impl DepthPoint {
    pub fn new(x: f32, y: f32, z: f32) -> DepthPoint {
        DepthPoint {
            x: x,
            y: y,
            z: z,

            x_y: 0.0,
            x_z: 0.0,
            y_z: 0.0,

            last_x_y: 0.0,
            last_x_z: 0.0,
            last_y_z: 0.0,
        }
    }

    pub fn flat_point(&mut self, engine_scr_x: u32, engine_scr_y: u32, offset_x: f32, offset_y: f32, offset_z: f32) -> FlatPoint {
        if self.z > -0.01 && self.z < 0.0 {
            self.z = 0.001
        }

        else if self.z < 0.1 { // Prevents division by nearly 0, that cause integer overflow/underflow
            self.z = 0.11;
        }

        FlatPoint {
            x: ((engine_scr_x as f32 * (self.x + offset_x) as f32/(self.z + offset_z)) + engine_scr_x as f32 / 2.0) as i32,
            y: ((engine_scr_x as f32 * (self.y + offset_y) as f32/(self.z + offset_z)) + engine_scr_y as f32 / 2.0) as i32,
        }
    }

    pub fn apply_camera_rotations(&mut self, engine: &start::Window) {
        #[cfg(not(target_os = "redox"))]
        use std::f32::consts::PI;

        #[cfg(target_os = "redox")]
        const PI: f32 = 3.141592653589793;

        let x_y = self.x_y;
        let x_z = self.x_z;
        let y_z = self.y_z;

        let last_x_y = self.last_x_y;
        let last_x_z = self.last_x_z;
        let last_y_z = self.last_y_z;

        self.camera_rotate_x_y(&engine, x_y - last_x_y);
        self.camera_rotate_x_z(&engine, x_z - last_x_z);
        self.camera_rotate_y_z(&engine, y_z - last_y_z);

        self.last_x_y = x_y;
        self.last_x_z = x_z;
        self.last_y_z = y_z;

        //normalize rotations
        if self.x_z > (PI * 2.0) {
            self.x_z -= (PI * 2.0);
        }

        if self.x_y > (PI * 2.0) {
            self.x_y -= (PI * 2.0);
        }

        if self.y_z > (PI * 2.0) {
            self.y_z -= (PI * 2.0);
        }
    }

    pub fn camera_rotate_x_y(&mut self, engine: &start::Window, angle: f32) {
        #[cfg(not(target_os = "redox"))]
        use std::f32;

        let s = f32::sin(angle);
        let c = f32::cos(angle);

        self.x -= engine.camera_x;
        self.y -= engine.camera_y;

        let new_x = self.x * c - self.y * s;
        let new_y = self.x * s + self.y * c;

        self.x = new_x + engine.camera_x;
        self.y = new_y + engine.camera_y;
    }

    pub fn camera_rotate_x_z(&mut self, engine: &start::Window, angle: f32) {
        #[cfg(not(target_os = "redox"))]
        use std::f32;

        let s = f32::sin(angle);
        let c = f32::cos(angle);

        self.x -= engine.camera_x;
        self.z -= engine.camera_z;

        let new_x = self.x * c - self.z * s;
        let new_z = self.x * s + self.z * c;

        self.x = new_x + engine.camera_x;
        self.z = new_z + engine.camera_z;
    }

    pub fn camera_rotate_y_z(&mut self, engine: &start::Window, angle: f32) {
        #[cfg(not(target_os = "redox"))]
        use std::f32;

        let s = f32::sin(angle);
        let c = f32::cos(angle);

        self.y -= engine.camera_y;
        self.z -= engine.camera_z;

        let new_y = self.y * c - self.z * s;
        let new_z = self.y * s + self.z * c;

        self.y = new_y + engine.camera_y;
        self.z = new_z + engine.camera_z;
    }

    pub fn coord_rotate_x_y(&mut self, x: f32, y: f32, angle: f32) {
        #[cfg(not(target_os = "redox"))]
        use std::f32;

        let s = f32::sin(angle);
        let c = f32::cos(angle);

        self.x -= x;
        self.y -= y;

        let new_x = self.x * c - self.y * s;
        let new_y = self.x * s + self.y * c;

        self.x = new_x + x;
        self.y = new_y + y;
    }

    pub fn coord_rotate_x_z(&mut self, x: f32, z: f32, angle: f32) {
        #[cfg(not(target_os = "redox"))]
        use std::f32;

        let s = f32::sin(angle);
        let c = f32::cos(angle);

        self.x -= x;
        self.z -= z;

        let new_x = self.x * c - self.z * s;
        let new_z = self.x * s + self.z * c;

        self.x = new_x + x;
        self.z = new_z + z;
    }

    pub fn coord_rotate_y_z(&mut self, y: f32, z: f32, angle: f32) {
        #[cfg(not(target_os = "redox"))]
        use std::f32;

        let s = f32::sin(angle);
        let c = f32::cos(angle);

        self.y -= y;
        self.z -= z;

        let new_y = self.y * c - self.z * s;
        let new_z = self.y * s + self.z * c;

        self.y = new_y + y;
        self.z = new_z + z;
    }
}

#[derive(Clone, Copy, Debug)]
pub struct Triangle {
    pub p1: DepthPoint,
    pub p2: DepthPoint,
    pub p3: DepthPoint,

    pub x: f32,
    pub y: f32,
    pub z: f32,

    pub x_y: f32,
    pub x_z: f32,
    pub y_z: f32,

    pub color: Color,
}

impl Triangle {
    pub fn new(p1: DepthPoint, p2: DepthPoint, p3: DepthPoint, x: f32, y: f32, z: f32, color: Color) -> Triangle {
        Triangle {
            p1: p1,
            p2: p2,
            p3: p3,

            x: x,
            y: y,
            z: z,

            x_y: 0.0,
            x_z: 0.0,
            y_z: 0.0,

            color: color,
        }
    }

    pub fn apply_camera_rotations(&mut self, engine: &start::Window) {
        self.p1.x_y += self.x_y;
        self.p1.x_z += self.x_z;
        self.p1.y_z += self.y_z;

        self.p2.x_y += self.x_y;
        self.p2.x_z += self.x_z;
        self.p2.y_z += self.y_z;

        self.p3.x_y += self.x_y;
        self.p3.x_z += self.x_z;
        self.p3.y_z += self.y_z;

        self.p1.apply_camera_rotations(&engine);
        self.p2.apply_camera_rotations(&engine);
        self.p3.apply_camera_rotations(&engine);

        self.p1.x_y -= self.x_y;
        self.p1.x_z -= self.x_z;
        self.p1.y_z -= self.y_z;

        self.p2.x_y -= self.x_y;
        self.p2.x_z -= self.x_z;
        self.p2.y_z -= self.y_z;

        self.p3.x_y -= self.x_y;
        self.p3.x_z -= self.x_z;
        self.p3.y_z -= self.y_z;
    }

    pub fn coord_rotate_x_y(&mut self, x: f32, y: f32, angle: f32) {
        self.p1.coord_rotate_x_y(x, y, angle);
        self.p2.coord_rotate_x_y(x, y, angle);
        self.p3.coord_rotate_x_y(x, y, angle);
    }

    pub fn coord_rotate_x_z(&mut self, x: f32, z: f32, angle: f32) {
        self.p1.coord_rotate_x_z(x, z, angle);
        self.p2.coord_rotate_x_z(x, z, angle);
        self.p3.coord_rotate_x_z(x, z, angle);
    }

    pub fn coord_rotate_y_z(&mut self, y: f32, z: f32, angle: f32) {
        self.p1.coord_rotate_y_z(y, z, angle);
        self.p2.coord_rotate_y_z(y, z, angle);
        self.p3.coord_rotate_y_z(y, z, angle);
    }
}

#[derive(Clone, Debug)]
pub struct TriangleGroup {
    pub triangles: Vec<Triangle>,
}

impl TriangleGroup {
    pub fn new(triangles: Vec<Triangle>) -> TriangleGroup {
        TriangleGroup {
            triangles: triangles
        }
    }
}
<|endoftext|>


<commit_before>use anyhow::{anyhow, Context as _};
use cookie_store::CookieStore;
use fs2::FileExt as _;
use std::{
    fs::{self, File},
    io::BufReader,
    io::{Seek as _, SeekFrom},
    path::{Path, PathBuf},
    sync::Mutex,
    time::Duration,
};

pub(crate) const SESSION_TIMEOUT: Duration = Duration::from_secs(30);

#[derive(Debug)]
pub(crate) struct LazyLockedFile {
    path: PathBuf,
    file: Mutex<Option<File>>,
}

impl LazyLockedFile {
    pub(crate) fn new(path: &Path) -> Self {
        Self {
            path: path.to_owned(),
            file: Mutex::new(None),
        }
    }

    pub(crate) fn path(&self) -> &Path {
        &self.path
    }

    fn overwrite(&self, f: impl FnOnce(&mut File) -> anyhow::Result<()>) -> anyhow::Result<()> {
        let Self { path, file } = self;

        let mut file = file.lock().unwrap();

        let new_file = if file.is_none() {
            if let Some(parent) = path.parent() {
                if !parent.exists() {
                    fs::create_dir_all(parent)
                        .with_context(|| format!("Could not create `{}`", parent.display()))?;
                }
            }

            let new_file = File::create(&path)
                .with_context(|| format!("Could not open `{}`", path.display()))?;

            new_file
                .try_lock_exclusive()
                .with_context(|| format!("Could not lock `{}`", path.display()))?;

            Some(new_file)
        } else {
            None
        };

        let file = file.get_or_insert_with(|| new_file.unwrap());

        file.seek(SeekFrom::Start(0))
            .and_then(|_| file.set_len(0))
            .with_context(|| format!("Could not clear the content of `{}`", path.display()))?;

        f(file)
    }
}

pub(crate) fn cookies_path() -> anyhow::Result<PathBuf> {
    let data_local_dir =
        dirs::data_local_dir().with_context(|| "Could not find the local date directory")?;
    Ok(data_local_dir.join("snowchains").join("cookies.jsonl"))
}

pub(crate) fn load_cookie_store(path: &Path) -> anyhow::Result<CookieStore> {
    if path.exists() {
        File::open(path)
            .map_err(anyhow::Error::from)
            .and_then(|h| CookieStore::load_json(BufReader::new(h)).map_err(|e| anyhow!("{}", e)))
            .with_context(|| format!("Could not load cookies from `{}`", path.display()))
    } else {
        Ok(CookieStore::default())
    }
}

pub(crate) fn save_cookie_store(
    cookie_store: &CookieStore,
    file: &LazyLockedFile,
) -> anyhow::Result<()> {
    file.overwrite(|file| {
        cookie_store.save_json(file).map_err(|e| anyhow!("{}", e))?;
        Ok(())
    })
}
<commit_msg>`sync_data` of `cookies.jsonl`<commit_after>use anyhow::{anyhow, Context as _};
use cookie_store::CookieStore;
use fs2::FileExt as _;
use std::{
    fs::{self, File},
    io::BufReader,
    io::{Seek as _, SeekFrom},
    path::{Path, PathBuf},
    sync::Mutex,
    time::Duration,
};

pub(crate) const SESSION_TIMEOUT: Duration = Duration::from_secs(30);

#[derive(Debug)]
pub(crate) struct LazyLockedFile {
    path: PathBuf,
    file: Mutex<Option<File>>,
}

impl LazyLockedFile {
    pub(crate) fn new(path: &Path) -> Self {
        Self {
            path: path.to_owned(),
            file: Mutex::new(None),
        }
    }

    pub(crate) fn path(&self) -> &Path {
        &self.path
    }

    fn overwrite(&self, f: impl FnOnce(&mut File) -> anyhow::Result<()>) -> anyhow::Result<()> {
        let Self { path, file } = self;

        let mut file = file.lock().unwrap();

        let new_file = if file.is_none() {
            if let Some(parent) = path.parent() {
                if !parent.exists() {
                    fs::create_dir_all(parent)
                        .with_context(|| format!("Could not create `{}`", parent.display()))?;
                }
            }

            let new_file = File::create(&path)
                .with_context(|| format!("Could not open `{}`", path.display()))?;

            new_file
                .try_lock_exclusive()
                .with_context(|| format!("Could not lock `{}`", path.display()))?;

            Some(new_file)
        } else {
            None
        };

        let file = file.get_or_insert_with(|| new_file.unwrap());

        file.seek(SeekFrom::Start(0))
            .and_then(|_| file.set_len(0))
            .map_err(Into::into)
            .and_then(|()| f(file))
            .and_then(|()| file.sync_data().map_err(Into::into))
            .with_context(|| format!("Could not write `{}`", path.display()))
    }
}

pub(crate) fn cookies_path() -> anyhow::Result<PathBuf> {
    let data_local_dir =
        dirs::data_local_dir().with_context(|| "Could not find the local date directory")?;
    Ok(data_local_dir.join("snowchains").join("cookies.jsonl"))
}

pub(crate) fn load_cookie_store(path: &Path) -> anyhow::Result<CookieStore> {
    if path.exists() {
        File::open(path)
            .map_err(anyhow::Error::from)
            .and_then(|h| CookieStore::load_json(BufReader::new(h)).map_err(|e| anyhow!("{}", e)))
            .with_context(|| format!("Could not load cookies from `{}`", path.display()))
    } else {
        Ok(CookieStore::default())
    }
}

pub(crate) fn save_cookie_store(
    cookie_store: &CookieStore,
    file: &LazyLockedFile,
) -> anyhow::Result<()> {
    file.overwrite(|file| {
        cookie_store.save_json(file).map_err(|e| anyhow!("{}", e))?;
        Ok(())
    })
}
<|endoftext|>


<commit_before>use serde_json;

use transport::query_server::QueryServer;

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct Tick {
    pub bid: f64,
    pub ask: f64,
    pub timestamp: i64
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SymbolTick {
    pub bid: f64,
    pub ask: f64,
    pub timestamp: i64,
    pub symbol: String
}

impl Tick {
    // returns a dummy placeholder tick
    pub fn null() -> Tick {
        Tick {bid: 0f64, ask: 0f64, timestamp: 0i64}
    }

    // converts a JSON-encoded String into a Tick
    pub fn from_json_string(s: String) -> Tick {
        serde_json::from_str(s.as_str()).expect("Unable to parse tick from string")
    }

    // generates a JSON string containing the data of the tick
    pub fn to_json_string(&self, symbol :String) -> String {
        serde_json::to_string(&SymbolTick::from_tick(*self, symbol))
            .expect("Couldn't convert tick to json string")
    }

    // returns the difference between the bid and the ask
    pub fn spread(&self) -> f64 {
        self.bid - self.ask
    }

    // returns the average of the bid and ask price
    pub fn mid(&self) -> f64 {
        (self.bid + self.ask) / 2f64
    }

    // saves the tick in the database
    // the table "ticks_SYMBOL" must exist.
    pub fn store(&self, symbol: &str, qs: &mut QueryServer) {
        let query = format!(
            "INSERT INTO ticks_{} (tick_time, bid, ask) VALUES ({}, {}, {});",
            symbol,
            self.timestamp,
            self.bid,
            self.ask
        );

        // Asynchronously store the tick in the database
        qs.execute(query);
    }
}

impl SymbolTick {
    // creates a SymbolTick given a Tick and a SymbolTick
    pub fn from_tick(tick: Tick, symbol: String) -> SymbolTick {
        SymbolTick {bid: tick.bid, ask: tick.ask, timestamp: tick.timestamp, symbol: symbol}
    }
}
<commit_msg>Derived PartialEq for Tick<commit_after>use serde_json;

use transport::query_server::QueryServer;

#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
pub struct Tick {
    pub bid: f64,
    pub ask: f64,
    pub timestamp: i64
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct SymbolTick {
    pub bid: f64,
    pub ask: f64,
    pub timestamp: i64,
    pub symbol: String
}

impl Tick {
    // returns a dummy placeholder tick
    pub fn null() -> Tick {
        Tick {bid: 0f64, ask: 0f64, timestamp: 0i64}
    }

    // converts a JSON-encoded String into a Tick
    pub fn from_json_string(s: String) -> Tick {
        serde_json::from_str(s.as_str()).expect("Unable to parse tick from string")
    }

    // generates a JSON string containing the data of the tick
    pub fn to_json_string(&self, symbol :String) -> String {
        serde_json::to_string(&SymbolTick::from_tick(*self, symbol))
            .expect("Couldn't convert tick to json string")
    }

    // returns the difference between the bid and the ask
    pub fn spread(&self) -> f64 {
        self.bid - self.ask
    }

    // returns the average of the bid and ask price
    pub fn mid(&self) -> f64 {
        (self.bid + self.ask) / 2f64
    }

    // saves the tick in the database
    // the table "ticks_SYMBOL" must exist.
    pub fn store(&self, symbol: &str, qs: &mut QueryServer) {
        let query = format!(
            "INSERT INTO ticks_{} (tick_time, bid, ask) VALUES ({}, {}, {});",
            symbol,
            self.timestamp,
            self.bid,
            self.ask
        );

        // Asynchronously store the tick in the database
        qs.execute(query);
    }
}

impl SymbolTick {
    // creates a SymbolTick given a Tick and a SymbolTick
    pub fn from_tick(tick: Tick, symbol: String) -> SymbolTick {
        SymbolTick {bid: tick.bid, ask: tick.ask, timestamp: tick.timestamp, symbol: symbol}
    }
}
<|endoftext|>


<commit_before>use super::snowflake::ProcessUniqueId;
use super::Node;
use super::NodeId;
use super::MutableNode;

//todo: remove panic!()s and replace with custom errors and return Result values instead
//todo: clean this up a bit more if possible.

pub struct TreeBuilder<T> {
    root: Option<Node<T>>,
    node_capacity: usize,
}

impl<T> TreeBuilder<T> {
    pub fn new() -> TreeBuilder<T> {
        TreeBuilder {
            root: None,
            node_capacity: 0,
        }
    }

    pub fn with_root(&mut self, root: Node<T>) -> TreeBuilder<T> {
        TreeBuilder {
            root: Some(root),
            node_capacity: self.node_capacity,
        }
    }

    pub fn with_node_capacity(&mut self, node_capacity: usize) -> TreeBuilder<T> {
        TreeBuilder {
            root: self.root.take(),
            node_capacity: node_capacity,
        }
    }

    pub fn build(&mut self) -> Tree<T> {

        let tree_id = ProcessUniqueId::new();

        let mut tree = Tree {
            id: tree_id,
            root: None,
            nodes: Vec::with_capacity(self.node_capacity),
            free_ids: Vec::new(), //todo: should this start with capacity too?
        };

        if self.root.is_some() {

            let node_id = NodeId {
                tree_id: tree_id,
                index: 0,
            };

            tree.nodes.push(self.root.take());
            tree.root = Some(node_id);
        }

        tree
    }
}

pub struct Tree<T> {
    id: ProcessUniqueId,
    root: Option<NodeId>,
    nodes: Vec<Option<Node<T>>>,
    free_ids: Vec<NodeId>,
}

impl<T> Tree<T> {
    pub fn set_root(&mut self, new_root: Node<T>) -> NodeId {
        let new_root_id = self.insert_new_node(new_root);

        match self.root {
            Some(current_root_node_id) => {
                self.set_as_parent_and_child(new_root_id, current_root_node_id);
            },
            None => ()
        };

        self.root = Some(new_root_id);
        new_root_id
    }

    pub fn add_child(&mut self, parent_id: NodeId, child: Node<T>) -> NodeId {
        if !self.is_valid_node_id(parent_id) {
            //todo: is panic the right tool here?
            // maybe having this return Result would be better.
            panic!("Invalid NodeId given for parent_id.");
        }

        let new_child_id = self.insert_new_node(child);
        self.set_as_parent_and_child(parent_id, new_child_id);

        new_child_id
    }

    pub fn remove_node_drop_children(&mut self, node_id: NodeId) -> Node<T> {
        if !self.is_valid_node_id(node_id) {
            //todo: is panic the right tool here?
            // maybe having this return Result would be better.
            panic!("Invalid NodeId given for node_id.");
        }

        if self.is_root_node(node_id) {
            self.root = None;
        }

        self.drop_children_recursive(node_id);

        let mut node = self.remove_node(node_id);
        //clear children because they're no longer valid
        node.children_mut().clear();

        node
    }

    pub fn remove_node_orphan_children(&mut self, node_id: NodeId) -> Node<T> {
        if !self.is_valid_node_id(node_id) {
            //todo: is panic the right tool here?
            // maybe having this return Result would be better.
            panic!("Invalid NodeId given for node_id.");
        }

        self.remove_node(node_id)
    }

    pub fn get(&self, node_id: NodeId) -> Option<&Node<T>> {
        if self.is_valid_node_id(node_id) {
            return (*self.nodes.get(node_id.index).unwrap()).as_ref();
        }
        None
    }

    pub fn get_mut(&mut self, node_id: NodeId) -> Option<&mut Node<T>> {
        if self.is_valid_node_id(node_id) {
            return (*self.nodes.get_mut(node_id.index).unwrap()).as_mut();
        }
        None
    }

    pub fn root_node_id(&self) -> Option<NodeId> {
        self.root
    }

    fn set_as_parent_and_child(&mut self, parent_id: NodeId, child_id: NodeId) {
        self.get_mut(parent_id)
            .expect("parent_id refers to a None value.")
            .add_child(child_id);

        self.get_mut(child_id)
            .expect("child_id refers to a None value.")
            .set_parent(Some(parent_id));
    }

    fn insert_new_node(&mut self, new_node: Node<T>) -> NodeId {

        if self.free_ids.len() > 0 {
            let new_node_id: NodeId = self.free_ids.pop()
                .expect("Couldn't pop from Vec with len() > 0 while inserting a new node.");

            self.nodes.push(Some(new_node));
            self.nodes.swap_remove(new_node_id.index);
            return new_node_id;

        } else {
            let new_node_index = self.nodes.len();
            self.nodes.push(Some(new_node));

            return self.new_node_id(new_node_index);
        }
    }

    fn remove_node(&mut self, node_id: NodeId) -> Node<T> {

        let node = self.remove_node_dirty(node_id);

        //todo: it seems like I might be missing an edge case here, but I'm not sure what it is
        if let Some(parent_id) = node.parent() {
            if let Some(parent_node) = self.get_mut(parent_id) {
                parent_node.children_mut().retain(|&child_id| child_id != node_id);
            } else {
                panic!("Invalid parent_id for node_id: {:?}", node_id);
            }
        }

        node
    }

    fn remove_node_dirty(&mut self, node_id: NodeId) -> Node<T> {
        debug_assert!(self.is_valid_node_id(node_id), "Invalid node_id found in what should be a 'protected' function.");

        self.nodes.push(None);
        let node = self.nodes.swap_remove(node_id.index).expect("node_id refers to a None value even though it is should be valid.");
        self.free_ids.push(node_id);

        node
    }

    fn drop_children_recursive(&mut self, node_id: NodeId) {

        //todo: is there a way to avoid this clone?
        let children = self.get(node_id).unwrap().children().clone();

        for child_id in children {
            self.drop_children_recursive(child_id);
            self.remove_node_dirty(child_id);
        }
    }

    fn new_node_id(&self, node_index: usize) -> NodeId {
        NodeId {
            tree_id: self.id,
            index: node_index,
        }
    }

    fn is_valid_node_id(&self, node_id: NodeId) -> bool {
        if node_id.tree_id != self.id {
            //the node_id belongs to a different tree.
            return false;
        }

        if self.nodes.get(node_id.index).is_none() {
            //the index is out of bounds
            return false;
        }

        if self.nodes.get(node_id.index).unwrap().is_none() {
            //the node at that index was removed.
            return false;
        }

        true
    }

    fn is_root_node(&self, node_id: NodeId) -> bool {
        match self.root {
            Some(root_id) => {
                root_id == node_id
            },
            None => false
        }
    }
}

#[cfg(test)]
mod tree_builder_tests {
    use super::TreeBuilder;
    use super::super::Node;

    #[test]
    fn test_new() {
        let tb: TreeBuilder<i32> = TreeBuilder::new();
        assert!(tb.root.is_none());
        assert_eq!(tb.node_capacity, 0);
    }

    #[test]
    fn test_with_root() {
        let tb: TreeBuilder<i32> = TreeBuilder::new()
            .with_root(Node::new(5));

        assert_eq!(tb.root.unwrap().data(), &5);
        assert_eq!(tb.node_capacity, 0);
    }

    #[test]
    fn test_with_capacity() {
        let tb: TreeBuilder<i32> = TreeBuilder::new()
            .with_node_capacity(10);

        assert!(tb.root.is_none());
        assert_eq!(tb.node_capacity, 10);
    }

    #[test]
    fn test_with_root_with_capacity() {
        let tb: TreeBuilder<i32> = TreeBuilder::new()
            .with_root(Node::new(5))
            .with_node_capacity(10);

        assert_eq!(tb.root.unwrap().data(), &5);
        assert_eq!(tb.node_capacity, 10);
    }
}

#[cfg(test)]
mod tree_tests {
    use super::TreeBuilder;
    use super::super::NodeId;
    use super::super::Node;

    #[test]
    fn test_get() {
        let root_node = Node::new(5);
        let mut tree = TreeBuilder::new().build();

        let root_id = tree.set_root(root_node);

        let root_node_ref = tree.get(root_id).unwrap();
        assert_eq!(root_node_ref.data(), &5);
    }

    #[test]
    fn test_get_mut() {
        let root_node = Node::new(5);
        let mut tree = TreeBuilder::new().build();

        let root_id = tree.set_root(root_node);

        {
            let root_node_ref: &mut Node<i32> = tree.get_mut(root_id).unwrap();
            assert_eq!(root_node_ref.data(), &5);
        }

        {
            let root_node_ref: &mut Node<i32> = tree.get_mut(root_id).unwrap();
            *root_node_ref.data_mut() = 6;
        }

        let root_node_ref = tree.get_mut(root_id).unwrap();
        assert_eq!(root_node_ref.data(), &6);
    }

    #[test]
    fn test_set_root() {
        let node_a = Node::new(5);
        let node_b = Node::new(6);
        let mut tree = TreeBuilder::new().build();

        let node_a_id = tree.set_root(node_a);
        let root_id = tree.root_node_id().unwrap();
        assert_eq!(node_a_id, root_id);
        {
            let node_a_ref = tree.get(node_a_id).unwrap();
            let root_ref = tree.get(root_id).unwrap();
            assert_eq!(node_a_ref.data(), &5);
            assert_eq!(root_ref.data(), &5);
        }

        let node_b_id = tree.set_root(node_b);
        let root_id = tree.root_node_id().unwrap();
        assert_eq!(node_b_id, root_id);
        {
            let node_b_ref = tree.get(node_b_id).unwrap();
            let root_ref = tree.get(root_id).unwrap();
            assert_eq!(node_b_ref.data(), &6);
            assert_eq!(root_ref.data(), &6);

            let node_b_child_id = node_b_ref.children().get(0).unwrap();
            let node_b_child_ref = tree.get(*node_b_child_id).unwrap();
            assert_eq!(node_b_child_ref.data(), &5);
        }
    }

    #[test]
    fn test_root_node_id() {
        let root_node = Node::new(5);
        let mut tree = TreeBuilder::new().build();

        let root_id = tree.set_root(root_node);
        let root_node_id = tree.root_node_id().unwrap();

        assert_eq!(root_id, root_node_id);
    }

    #[test]
    fn test_add_child() {
        let mut tree = TreeBuilder::new()
            .with_root(Node::new(5))
            .build();

        let node_1 = Node::new(1);
        let node_2 = Node::new(2);

        let root_id = tree.root_node_id().unwrap();
        let node_1_id = tree.add_child(root_id, node_1);
        let node_2_id = tree.add_child(root_id, node_2);

        let node_1_ref = tree.get(node_1_id).unwrap();
        let node_2_ref = tree.get(node_2_id).unwrap();
        assert_eq!(node_1_ref.data(), &1);
        assert_eq!(node_2_ref.data(), &2);

        assert_eq!(node_1_ref.parent().unwrap(), root_id);
        assert_eq!(node_2_ref.parent().unwrap(), root_id);

        let root_node_ref = tree.get(root_id).unwrap();
        let root_children: &Vec<NodeId> = root_node_ref.children();

        let child_1_id = root_children.get(0).unwrap();
        let child_2_id = root_children.get(1).unwrap();

        let child_1_ref = tree.get(*child_1_id).unwrap();
        let child_2_ref = tree.get(*child_2_id).unwrap();

        assert_eq!(child_1_ref.data(), &1);
        assert_eq!(child_2_ref.data(), &2);
    }

    #[test]
    fn test_remove_node_drop_children() {

        let mut tree = TreeBuilder::new()
            .with_root(Node::new(5))
            .build();

        let root_node_id = tree.root_node_id().unwrap();

        let node_1_id = tree.add_child(root_node_id, Node::new(1));
        let node_2_id = tree.add_child(node_1_id, Node::new(2));
        let node_3_id = tree.add_child(node_1_id, Node::new(3));

        let node_1 = tree.remove_node_drop_children(node_1_id);

        assert_eq!(node_1.data(), &1);
        assert_eq!(node_1.children().len(), 0);
        assert_eq!(node_1.parent().unwrap(), root_node_id);
        assert!(tree.get(node_1_id).is_none());
        assert!(tree.get(node_2_id).is_none());
        assert!(tree.get(node_3_id).is_none());
    }

    #[test]
    fn test_remove_node_orphan_children() {

        let mut tree = TreeBuilder::new()
            .with_root(Node::new(5))
            .build();

        let root_node_id = tree.root_node_id().unwrap();

        let node_1_id = tree.add_child(root_node_id, Node::new(1));
        let node_2_id = tree.add_child(node_1_id, Node::new(2));
        let node_3_id = tree.add_child(node_1_id, Node::new(3));

        let node_1 = tree.remove_node_orphan_children(node_1_id);

        assert_eq!(node_1.data(), &1);
        assert_eq!(node_1.children().len(), 2);
        assert_eq!(node_1.parent().unwrap(), root_node_id);
        assert!(tree.get(node_1_id).is_none());
        assert_eq!(tree.get(node_2_id).unwrap().data(), &2);
        assert_eq!(tree.get(node_3_id).unwrap().data(), &3);
    }
}
<commit_msg>add swap_capacity to TreeBuilder<commit_after>use super::snowflake::ProcessUniqueId;
use super::Node;
use super::NodeId;
use super::MutableNode;

//todo: remove panic!()s and replace with custom errors and return Result values instead
//todo: clean this up a bit more if possible.

pub struct TreeBuilder<T> {
    root: Option<Node<T>>,
    node_capacity: usize,
    swap_capacity: usize,
}

impl<T> TreeBuilder<T> {
    pub fn new() -> TreeBuilder<T> {
        TreeBuilder {
            root: None,
            node_capacity: 0,
            swap_capacity: 0,
        }
    }

    pub fn with_root(mut self, root: Node<T>) -> TreeBuilder<T> {
        self.root = Some(root);
        self
    }

    pub fn with_node_capacity(mut self, node_capacity: usize) -> TreeBuilder<T> {
        self.node_capacity = node_capacity;
        self
    }

    pub fn with_swap_capacity(mut self, swap_capacity: usize) -> TreeBuilder<T> {
        self.swap_capacity = swap_capacity;
        self
    }

    pub fn build(mut self) -> Tree<T> {

        let tree_id = ProcessUniqueId::new();

        let mut tree = Tree {
            id: tree_id,
            root: None,
            nodes: Vec::with_capacity(self.node_capacity),
            free_ids: Vec::with_capacity(self.swap_capacity),//todo: write tests for this.
        };

        if self.root.is_some() {

            let node_id = NodeId {
                tree_id: tree_id,
                index: 0,
            };

            tree.nodes.push(self.root.take());
            tree.root = Some(node_id);
        }

        tree
    }
}

pub struct Tree<T> {
    id: ProcessUniqueId,
    root: Option<NodeId>,
    nodes: Vec<Option<Node<T>>>,
    free_ids: Vec<NodeId>,
}

impl<T> Tree<T> {
    pub fn new() -> Tree<T> {
        TreeBuilder::new().build() //todo: add test for this.
    }

    pub fn set_root(&mut self, new_root: Node<T>) -> NodeId {
        let new_root_id = self.insert_new_node(new_root);

        match self.root {
            Some(current_root_node_id) => {
                self.set_as_parent_and_child(new_root_id, current_root_node_id);
            },
            None => ()
        };

        self.root = Some(new_root_id);
        new_root_id
    }

    pub fn add_child(&mut self, parent_id: NodeId, child: Node<T>) -> NodeId {
        if !self.is_valid_node_id(parent_id) {
            //todo: is panic the right tool here?
            // maybe having this return Result would be better.
            panic!("Invalid NodeId given for parent_id.");
        }

        let new_child_id = self.insert_new_node(child);
        self.set_as_parent_and_child(parent_id, new_child_id);

        new_child_id
    }

    pub fn remove_node_drop_children(&mut self, node_id: NodeId) -> Node<T> {
        if !self.is_valid_node_id(node_id) {
            //todo: is panic the right tool here?
            // maybe having this return Result would be better.
            panic!("Invalid NodeId given for node_id.");
        }

        if self.is_root_node(node_id) {
            self.root = None;
        }

        self.drop_children_recursive(node_id);

        let mut node = self.remove_node(node_id);
        //clear children because they're no longer valid
        node.children_mut().clear();

        node
    }

    pub fn remove_node_orphan_children(&mut self, node_id: NodeId) -> Node<T> {
        if !self.is_valid_node_id(node_id) {
            //todo: is panic the right tool here?
            // maybe having this return Result would be better.
            panic!("Invalid NodeId given for node_id.");
        }

        self.remove_node(node_id)
    }

    pub fn get(&self, node_id: NodeId) -> Option<&Node<T>> {
        if self.is_valid_node_id(node_id) {
            return (*self.nodes.get(node_id.index).unwrap()).as_ref();
        }
        None
    }

    pub fn get_mut(&mut self, node_id: NodeId) -> Option<&mut Node<T>> {
        if self.is_valid_node_id(node_id) {
            return (*self.nodes.get_mut(node_id.index).unwrap()).as_mut();
        }
        None
    }

    pub fn root_node_id(&self) -> Option<NodeId> {
        self.root
    }

    fn set_as_parent_and_child(&mut self, parent_id: NodeId, child_id: NodeId) {
        self.get_mut(parent_id)
            .expect("parent_id refers to a None value.")
            .add_child(child_id);

        self.get_mut(child_id)
            .expect("child_id refers to a None value.")
            .set_parent(Some(parent_id));
    }

    fn insert_new_node(&mut self, new_node: Node<T>) -> NodeId {

        if self.free_ids.len() > 0 {
            let new_node_id: NodeId = self.free_ids.pop()
                .expect("Couldn't pop from Vec with len() > 0 while inserting a new node.");

            self.nodes.push(Some(new_node));
            self.nodes.swap_remove(new_node_id.index);
            return new_node_id;

        } else {
            let new_node_index = self.nodes.len();
            self.nodes.push(Some(new_node));

            return self.new_node_id(new_node_index);
        }
    }

    fn remove_node(&mut self, node_id: NodeId) -> Node<T> {

        let node = self.remove_node_dirty(node_id);

        //todo: it seems like I might be missing an edge case here, but I'm not sure what it is
        if let Some(parent_id) = node.parent() {
            if let Some(parent_node) = self.get_mut(parent_id) {
                parent_node.children_mut().retain(|&child_id| child_id != node_id);
            } else {
                panic!("Invalid parent_id for node_id: {:?}", node_id);
            }
        }

        node
    }

    fn remove_node_dirty(&mut self, node_id: NodeId) -> Node<T> {
        debug_assert!(self.is_valid_node_id(node_id), "Invalid node_id found in what should be a 'protected' function.");

        self.nodes.push(None);
        let node = self.nodes.swap_remove(node_id.index).expect("node_id refers to a None value even though it is should be valid.");
        self.free_ids.push(node_id);

        node
    }

    fn drop_children_recursive(&mut self, node_id: NodeId) {

        //todo: is there a way to avoid this clone?
        let children = self.get(node_id).unwrap().children().clone();

        for child_id in children {
            self.drop_children_recursive(child_id);
            self.remove_node_dirty(child_id);
        }
    }

    fn new_node_id(&self, node_index: usize) -> NodeId {
        NodeId {
            tree_id: self.id,
            index: node_index,
        }
    }

    fn is_valid_node_id(&self, node_id: NodeId) -> bool {
        if node_id.tree_id != self.id {
            //the node_id belongs to a different tree.
            return false;
        }

        if self.nodes.get(node_id.index).is_none() {
            //the index is out of bounds
            return false;
        }

        if self.nodes.get(node_id.index).unwrap().is_none() {
            //the node at that index was removed.
            return false;
        }

        true
    }

    fn is_root_node(&self, node_id: NodeId) -> bool {
        match self.root {
            Some(root_id) => {
                root_id == node_id
            },
            None => false
        }
    }
}

#[cfg(test)]
mod tree_builder_tests {
    use super::TreeBuilder;
    use super::super::Node;

    #[test]
    fn test_new() {
        let tb: TreeBuilder<i32> = TreeBuilder::new();
        assert!(tb.root.is_none());
        assert_eq!(tb.node_capacity, 0);
    }

    #[test]
    fn test_with_root() {
        let tb: TreeBuilder<i32> = TreeBuilder::new()
            .with_root(Node::new(5));

        assert_eq!(tb.root.unwrap().data(), &5);
        assert_eq!(tb.node_capacity, 0);
    }

    #[test]
    fn test_with_capacity() {
        let tb: TreeBuilder<i32> = TreeBuilder::new()
            .with_node_capacity(10);

        assert!(tb.root.is_none());
        assert_eq!(tb.node_capacity, 10);
    }

    #[test]
    fn test_with_root_with_capacity() {
        let tb: TreeBuilder<i32> = TreeBuilder::new()
            .with_root(Node::new(5))
            .with_node_capacity(10);

        assert_eq!(tb.root.unwrap().data(), &5);
        assert_eq!(tb.node_capacity, 10);
    }
}

#[cfg(test)]
mod tree_tests {
    use super::TreeBuilder;
    use super::super::NodeId;
    use super::super::Node;

    #[test]
    fn test_get() {
        let root_node = Node::new(5);
        let mut tree = TreeBuilder::new().build();

        let root_id = tree.set_root(root_node);

        let root_node_ref = tree.get(root_id).unwrap();
        assert_eq!(root_node_ref.data(), &5);
    }

    #[test]
    fn test_get_mut() {
        let root_node = Node::new(5);
        let mut tree = TreeBuilder::new().build();

        let root_id = tree.set_root(root_node);

        {
            let root_node_ref: &mut Node<i32> = tree.get_mut(root_id).unwrap();
            assert_eq!(root_node_ref.data(), &5);
        }

        {
            let root_node_ref: &mut Node<i32> = tree.get_mut(root_id).unwrap();
            *root_node_ref.data_mut() = 6;
        }

        let root_node_ref = tree.get_mut(root_id).unwrap();
        assert_eq!(root_node_ref.data(), &6);
    }

    #[test]
    fn test_set_root() {
        let node_a = Node::new(5);
        let node_b = Node::new(6);
        let mut tree = TreeBuilder::new().build();

        let node_a_id = tree.set_root(node_a);
        let root_id = tree.root_node_id().unwrap();
        assert_eq!(node_a_id, root_id);
        {
            let node_a_ref = tree.get(node_a_id).unwrap();
            let root_ref = tree.get(root_id).unwrap();
            assert_eq!(node_a_ref.data(), &5);
            assert_eq!(root_ref.data(), &5);
        }

        let node_b_id = tree.set_root(node_b);
        let root_id = tree.root_node_id().unwrap();
        assert_eq!(node_b_id, root_id);
        {
            let node_b_ref = tree.get(node_b_id).unwrap();
            let root_ref = tree.get(root_id).unwrap();
            assert_eq!(node_b_ref.data(), &6);
            assert_eq!(root_ref.data(), &6);

            let node_b_child_id = node_b_ref.children().get(0).unwrap();
            let node_b_child_ref = tree.get(*node_b_child_id).unwrap();
            assert_eq!(node_b_child_ref.data(), &5);
        }
    }

    #[test]
    fn test_root_node_id() {
        let root_node = Node::new(5);
        let mut tree = TreeBuilder::new().build();

        let root_id = tree.set_root(root_node);
        let root_node_id = tree.root_node_id().unwrap();

        assert_eq!(root_id, root_node_id);
    }

    #[test]
    fn test_add_child() {
        let mut tree = TreeBuilder::new()
            .with_root(Node::new(5))
            .build();

        let node_1 = Node::new(1);
        let node_2 = Node::new(2);

        let root_id = tree.root_node_id().unwrap();
        let node_1_id = tree.add_child(root_id, node_1);
        let node_2_id = tree.add_child(root_id, node_2);

        let node_1_ref = tree.get(node_1_id).unwrap();
        let node_2_ref = tree.get(node_2_id).unwrap();
        assert_eq!(node_1_ref.data(), &1);
        assert_eq!(node_2_ref.data(), &2);

        assert_eq!(node_1_ref.parent().unwrap(), root_id);
        assert_eq!(node_2_ref.parent().unwrap(), root_id);

        let root_node_ref = tree.get(root_id).unwrap();
        let root_children: &Vec<NodeId> = root_node_ref.children();

        let child_1_id = root_children.get(0).unwrap();
        let child_2_id = root_children.get(1).unwrap();

        let child_1_ref = tree.get(*child_1_id).unwrap();
        let child_2_ref = tree.get(*child_2_id).unwrap();

        assert_eq!(child_1_ref.data(), &1);
        assert_eq!(child_2_ref.data(), &2);
    }

    #[test]
    fn test_remove_node_drop_children() {

        let mut tree = TreeBuilder::new()
            .with_root(Node::new(5))
            .build();

        let root_node_id = tree.root_node_id().unwrap();

        let node_1_id = tree.add_child(root_node_id, Node::new(1));
        let node_2_id = tree.add_child(node_1_id, Node::new(2));
        let node_3_id = tree.add_child(node_1_id, Node::new(3));

        let node_1 = tree.remove_node_drop_children(node_1_id);

        assert_eq!(node_1.data(), &1);
        assert_eq!(node_1.children().len(), 0);
        assert_eq!(node_1.parent().unwrap(), root_node_id);
        assert!(tree.get(node_1_id).is_none());
        assert!(tree.get(node_2_id).is_none());
        assert!(tree.get(node_3_id).is_none());
    }

    #[test]
    fn test_remove_node_orphan_children() {

        let mut tree = TreeBuilder::new()
            .with_root(Node::new(5))
            .build();

        let root_node_id = tree.root_node_id().unwrap();

        let node_1_id = tree.add_child(root_node_id, Node::new(1));
        let node_2_id = tree.add_child(node_1_id, Node::new(2));
        let node_3_id = tree.add_child(node_1_id, Node::new(3));

        let node_1 = tree.remove_node_orphan_children(node_1_id);

        assert_eq!(node_1.data(), &1);
        assert_eq!(node_1.children().len(), 2);
        assert_eq!(node_1.parent().unwrap(), root_node_id);
        assert!(tree.get(node_1_id).is_none());
        assert_eq!(tree.get(node_2_id).unwrap().data(), &2);
        assert_eq!(tree.get(node_3_id).unwrap().data(), &3);
    }
}
<|endoftext|>


<commit_before>//! Unix-only extensions, for sending signals

extern crate libc;

use std::io;

use super::{Handle, HandleInner, PipeHandle, ThenHandle};
use shared_child::unix::SharedChildExt;

pub trait HandleExt {
    /// Send a signal to all child processes running under this expression.
    ///
    /// # Caveat
    ///
    /// In the case of a `then` expression where the left expression is unchecked and dies from the
    /// signal, then the right expression will start anyway. If the intention is to stop the entire
    /// expression then the `kill` method should be used instead.
    fn send_signal(&self, signal: libc::c_int) -> io::Result<()>;

    /// Send SIGTERM to all child processes running under this expression. Gives the processes
    /// a chance to exit more gracefully than they can with the `kill` method.
    ///
    /// There is no guarantee a process will terminate from a SIGTERM signal. So it is
    /// recommended to have some timeout after this call and then call `kill` if it is still alive.
    ///
    /// For `then` expressions still running the left expression, calling this method will make
    /// sure the right expression never starts.
    fn terminate(&self) -> io::Result<()>;
}

impl HandleExt for Handle {
    fn send_signal(&self, signal: libc::c_int) -> io::Result<()> {
        self.inner.send_signal(signal)
    }

    fn terminate(&self) -> io::Result<()> {
        self.inner.terminate()
    }
}

impl HandleExt for HandleInner {
    fn send_signal(&self, signal: libc::c_int) -> io::Result<()> {
        match *self {
            HandleInner::Child(ref child_handle) => child_handle.child.send_signal(signal),
            HandleInner::Pipe(ref pipe_handle) => pipe_handle.send_signal(signal),
            HandleInner::Then(ref then_handle) => then_handle.send_signal(signal),
            HandleInner::Input(ref input_handle) => input_handle.inner_handle.send_signal(signal),
            HandleInner::Unchecked(ref inner_handle) => inner_handle.send_signal(signal),
        }
    }

    fn terminate(&self) -> io::Result<()> {
        match *self {
            HandleInner::Child(ref child_handle) => child_handle.child.send_signal(libc::SIGTERM),
            HandleInner::Pipe(ref pipe_handle) => pipe_handle.terminate(),
            HandleInner::Then(ref then_handle) => then_handle.terminate(),
            HandleInner::Input(ref input_handle) => input_handle.inner_handle.terminate(),
            HandleInner::Unchecked(ref inner_handle) => inner_handle.terminate(),
        }
    }
}

impl HandleExt for PipeHandle {
    /// Signals both parts of this `pipe` expression. Returns an error if signalling one of the
    /// expressions returned an error.
    fn send_signal(&self, signal: libc::c_int) -> io::Result<()> {
        let left_result = self.left_handle.send_signal(signal);
        let right_result = self.right_start_result
            .as_ref()
            .map(|right_handle| right_handle.send_signal(signal))
            .unwrap_or(Ok(()));
        left_result.and(right_result)
    }

    fn terminate(&self) -> io::Result<()> {
        let left_result = self.left_handle.terminate();
        let right_result = self.right_start_result
            .as_ref()
            .map(|right_handle| right_handle.terminate())
            .unwrap_or(Ok(()));
        left_result.and(right_result)
    }
}

impl HandleExt for ThenHandle {
    /// Signals the running part of this `then` expression.
    fn send_signal(&self, signal: libc::c_int) -> io::Result<()> {
        match self.shared_state.right_cell.borrow() {
            Some(&Ok(ref right_handle)) => right_handle.send_signal(signal),
            Some(&Err(_)) => Ok(()),
            None => self.shared_state.left_handle.send_signal(signal)
        }
    }

    fn terminate(&self) -> io::Result<()> {
        // Lock and clear the right context first, so that it can't be started
        // if it hasn't been already. This is important because if the left side
        // is unchecked, a waiting thread will ignore its terminated exit status and
        // try to start the right side anyway.
        let mut right_lock_guard = self.shared_state.right_lock.lock().unwrap();
        *right_lock_guard = None;

        match self.shared_state.right_cell.borrow() {
            Some(&Ok(ref right_handle)) => right_handle.terminate(),
            Some(&Err(_)) => Ok(()),
            None => self.shared_state.left_handle.terminate()
        }
    }
}

#[cfg(test)]
mod tests {
    use test::*;
    use cmd;
    use super::{libc, HandleExt};

    use std::os::unix::process::ExitStatusExt;
    use std::sync::Arc;
    use std::thread;

    #[test]
    fn test_send_signal_from_other_thread() {
        let sleep_cmd = cmd(path_to_exe("sleep"), &["1000000"]);
        let handle = Arc::new(sleep_cmd.unchecked().start().unwrap());
        let handle_clone = handle.clone();

        thread::spawn(move || handle_clone.send_signal(libc::SIGABRT).unwrap());
        let status = handle.wait().unwrap();

        assert_eq!(Some(libc::SIGABRT), status.status.signal());
    }

    #[test]
    fn test_send_signal_to_pipe() {
        let sleep_cmd = cmd(path_to_exe("sleep"), &["1000000"]);
        let handle = sleep_cmd.pipe(sleep_cmd.clone()).unchecked().start().unwrap();
        handle.send_signal(libc::SIGABRT).unwrap();
        let status = handle.output().unwrap();
        assert_eq!(Some(libc::SIGABRT), status.status.signal());
    }

    /// Tests the caveat explained in the documentation for `send_signal`
    #[test]
    fn test_signal_then_expression() {
        let sleep_cmd = cmd(path_to_exe("sleep"), &["1000000"]);
        let handle = sleep_cmd
            .unchecked()
            .then(true_cmd())
            .unchecked()
            .start()
            .unwrap();
        handle.send_signal(libc::SIGTERM).unwrap();
        let status = handle.wait().unwrap();
        // Since the sleep is unchecked the `then` expression will happily start the second
        // expression and return the status of it upon completion.
        assert_eq!(None, status.status.signal());
        assert!(status.status.success());
    }

    #[test]
    fn test_terminate() {
        let sleep_cmd = cmd(path_to_exe("sleep"), &["1000000"]);
        let handle = sleep_cmd.unchecked().start().unwrap();
        handle.terminate().unwrap();
        let status = handle.wait().unwrap();
        assert_eq!(Some(libc::SIGTERM), status.status.signal());
    }

    #[test]
    fn test_terminate_then_expression() {
        let sleep_cmd = cmd(path_to_exe("sleep"), &["1000000"]);
        let handle = sleep_cmd
            .unchecked()
            .then(true_cmd())
            .unchecked()
            .start()
            .unwrap();
        handle.terminate().unwrap();
        let status = handle.wait().unwrap();
        assert_eq!(Some(libc::SIGTERM), status.status.signal());
    }
}
<commit_msg>Revert "Add terminate method to HandleExt"<commit_after>//! Unix-only extensions, for sending signals

extern crate libc;

use std::io;

use super::{Handle, HandleInner, PipeHandle, ThenHandle};
use shared_child::unix::SharedChildExt;

pub trait HandleExt {
    /// Send a signal to all child processes running under this expression.
    ///
    /// # Caveat
    ///
    /// In the case of a `then` expression where the left expression is unchecked and dies from the
    /// signal, then the right expression will start anyway. If the intention is to stop the entire
    /// expression then the `kill` method should be used instead.
    fn send_signal(&self, signal: libc::c_int) -> io::Result<()>;
}

impl HandleExt for Handle {
    fn send_signal(&self, signal: libc::c_int) -> io::Result<()> {
        self.inner.send_signal(signal)
    }
}

impl HandleExt for HandleInner {
    fn send_signal(&self, signal: libc::c_int) -> io::Result<()> {
        match *self {
            HandleInner::Child(ref child_handle) => child_handle.child.send_signal(signal),
            HandleInner::Pipe(ref pipe_handle) => pipe_handle.send_signal(signal),
            HandleInner::Then(ref then_handle) => then_handle.send_signal(signal),
            HandleInner::Input(ref input_handle) => input_handle.inner_handle.send_signal(signal),
            HandleInner::Unchecked(ref inner_handle) => inner_handle.send_signal(signal),
        }
    }
}

impl HandleExt for PipeHandle {
    /// Signals both parts of this `pipe` expression. Returns an error if signalling one of the
    /// expressions returned an error.
    fn send_signal(&self, signal: libc::c_int) -> io::Result<()> {
        let left_result = self.left_handle.send_signal(signal);
        let right_result = self.right_start_result
            .as_ref()
            .map(|right_handle| right_handle.send_signal(signal))
            .unwrap_or(Ok(()));
        left_result.and(right_result)
    }
}

impl HandleExt for ThenHandle {
    /// Signals the running part of this `then` expression.
    fn send_signal(&self, signal: libc::c_int) -> io::Result<()> {
        match self.shared_state.right_cell.borrow() {
            Some(&Ok(ref right_handle)) => right_handle.send_signal(signal),
            Some(&Err(_)) => Ok(()),
            None => self.shared_state.left_handle.send_signal(signal)
        }
    }
}

#[cfg(test)]
mod tests {
    use test::*;
    use cmd;
    use super::{libc, HandleExt};

    use std::os::unix::process::ExitStatusExt;
    use std::sync::Arc;
    use std::thread;

    #[test]
    fn test_send_signal_from_other_thread() {
        let sleep_cmd = cmd(path_to_exe("sleep"), &["1000000"]);
        let handle = Arc::new(sleep_cmd.unchecked().start().unwrap());
        let handle_clone = handle.clone();

        thread::spawn(move || handle_clone.send_signal(libc::SIGABRT).unwrap());
        let status = handle.wait().unwrap();

        assert_eq!(Some(libc::SIGABRT), status.status.signal());
    }

    #[test]
    fn test_send_signal_to_pipe() {
        let sleep_cmd = cmd(path_to_exe("sleep"), &["1000000"]);
        let handle = sleep_cmd.pipe(sleep_cmd.clone()).unchecked().start().unwrap();
        handle.send_signal(libc::SIGABRT).unwrap();
        let status = handle.output().unwrap();
        assert_eq!(Some(libc::SIGABRT), status.status.signal());
    }

    /// Tests the caveat explained in the documentation for `send_signal`
    #[test]
    fn test_signal_then_expression() {
        let sleep_cmd = cmd(path_to_exe("sleep"), &["1000000"]);
        let handle = sleep_cmd
            .unchecked()
            .then(true_cmd())
            .unchecked()
            .start()
            .unwrap();
        handle.send_signal(libc::SIGTERM).unwrap();
        let status = handle.wait().unwrap();
        // Since the sleep is unchecked the `then` expression will happily start the second
        // expression and return the status of it upon completion.
        assert_eq!(None, status.status.signal());
        assert!(status.status.success());
    }
}
<|endoftext|>


<commit_before>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2013, 2014  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use ffi;
use types::{gchar,gsize};
use types::{gpointer};

use alloc::libc_heap::malloc_raw;
use libc;
use libc::c_char;
use std::c_str::{CString,ToCStr};
use std::mem::transmute;
use std::ptr::copy_nonoverlapping_memory;
use std::slice;
use std::str;
use std::string;

pub struct UTF8Buf {
    data: *mut gchar,
}

impl UTF8Buf {

    pub unsafe fn wrap(data: *mut gchar) -> UTF8Buf {
        UTF8Buf { data: data }
    }

    pub fn into_collection(self) -> UTF8Str {
        unsafe {
            let len = libc::strlen(self.data as *const c_char);
            UTF8Str { buf: transmute(self), len: len as uint }
        }
    }

    pub fn to_string(&self) -> String {
        unsafe {
            string::raw::from_buf(self.data as *const gchar as *const u8)
        }
    }

    #[inline]
    pub fn to_owned(&self) -> String { self.to_string() }

    #[inline]
    pub fn into_string(self) -> String { self.to_string() }

    #[inline]
    pub fn into_owned(self) -> String { self.to_string() }

    #[inline]
    pub fn is_empty(&self) -> bool { unsafe { *self.data == 0 } }
}

impl Drop for UTF8Buf {
    fn drop(&mut self) {
        unsafe { ffi::g_free(self.data as gpointer) }
    }
}

impl Clone for UTF8Buf {
    fn clone(&self) -> UTF8Buf {
        unsafe {
            UTF8Buf::wrap(ffi::g_strdup(self.data as *const gchar))
        }
    }
}

unsafe fn dup_to_c_str(source: *const c_char, len: uint) -> CString {
    let copy = malloc_raw(len + 1) as *mut c_char;
    copy_nonoverlapping_memory(copy, source, len + 1);
    CString::new(copy as *const c_char, true)
}

impl ToCStr for UTF8Buf {

    fn to_c_str(&self) -> CString {
        unsafe { self.to_c_str_unchecked() }
    }

    unsafe fn to_c_str_unchecked(&self) -> CString {
        let src = self.data as *const c_char;
        let len = libc::strlen(src) as uint;
        dup_to_c_str(src, len)
    }

    fn with_c_str<T>(&self, f: |*const i8| -> T) -> T {
        f(self.data as *const i8)
    }

    unsafe fn with_c_str_unchecked<T>(&self, f: |*const i8| -> T) -> T {
        f(self.data as *const i8)
    }
}

pub struct UTF8Str {
    buf: UTF8Buf,
    len: uint
}

static NUL: gchar = 0;

impl UTF8Str {

    pub unsafe fn wrap(data: *mut gchar, len: uint) -> UTF8Str {
        UTF8Str { buf: UTF8Buf::wrap(data), len: len }
    }

    pub fn to_string(&self) -> String {
        unsafe {
            string::raw::from_buf_len(self.buf.data as *const u8, self.len)
        }
    }
}

impl Clone for UTF8Str {
    fn clone(&self) -> UTF8Str {
        unsafe {
            let copy = ffi::g_malloc((self.len + 1) as gsize) as *mut gchar;
            copy_nonoverlapping_memory(copy,
                    self.buf.data as *const gchar, self.len);
            *copy.offset(self.len as int) = NUL;
            UTF8Str::wrap(copy, self.len)
        }
    }
}

impl Str for UTF8Str {
    fn as_slice<'a>(&'a self) -> &'a str {
        unsafe {
            slice::raw::buf_as_slice(
                self.buf.data as *const u8,
                self.len,
                |bytes| {
                    let s = str::raw::from_utf8(bytes);
                    transmute(s)
                })
        }
    }
}

impl StrAllocating for UTF8Str {
    fn into_string(self) -> String { self.to_string() }
}

impl Collection for UTF8Str {

    // Common sense says we should return the UTF-8 length,
    // but &str returns length in bytes, so...
    fn len(&self) -> uint { return self.len }

    fn is_empty(&self) -> bool { return self.len == 0 }
}

impl ToCStr for UTF8Str {

    fn to_c_str(&self) -> CString { self.buf.to_c_str() }

    unsafe fn to_c_str_unchecked(&self) -> CString {
        dup_to_c_str(self.buf.data as *const c_char, self.len)
    }

    fn with_c_str<T>(&self, f: |*const i8| -> T) -> T {
        self.buf.with_c_str(f)
    }

    unsafe fn with_c_str_unchecked<T>(&self, f: |*const i8| -> T) -> T {
        self.buf.with_c_str_unchecked(f)
    }
}

impl PartialEq for UTF8Str {
    fn eq(&self, other: &UTF8Str) -> bool {
        self.as_slice() == other.as_slice()
    }
}

impl Eq for UTF8Str { }

impl<S: Str> Equiv<S> for UTF8Str {
    fn equiv(&self, other: &S) -> bool {
        self.as_slice() == other.as_slice()
    }
}

pub trait WithUTF8 {
    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T;
}

impl WithUTF8 for UTF8Buf {

    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        f(self.data as *const gchar)
    }
}

impl WithUTF8 for UTF8Str {

    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        self.buf.with_utf8_c_str(f)
    }
}

impl<'a> WithUTF8 for &'a str {

    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        self.with_c_str(f)
    }
}

impl WithUTF8 for String {

    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        self.with_c_str(f)
    }
}
<commit_msg>Optimized to_c_str for UTF8Str<commit_after>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2013, 2014  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use ffi;
use types::{gchar,gsize};
use types::{gpointer};

use alloc::libc_heap::malloc_raw;
use libc;
use libc::c_char;
use std::c_str::{CString,ToCStr};
use std::mem::transmute;
use std::ptr::copy_nonoverlapping_memory;
use std::slice;
use std::str;
use std::string;

pub struct UTF8Buf {
    data: *mut gchar,
}

impl UTF8Buf {

    pub unsafe fn wrap(data: *mut gchar) -> UTF8Buf {
        UTF8Buf { data: data }
    }

    pub fn into_collection(self) -> UTF8Str {
        unsafe {
            let len = libc::strlen(self.data as *const c_char);
            UTF8Str { buf: transmute(self), len: len as uint }
        }
    }

    pub fn to_string(&self) -> String {
        unsafe {
            string::raw::from_buf(self.data as *const gchar as *const u8)
        }
    }

    #[inline]
    pub fn to_owned(&self) -> String { self.to_string() }

    #[inline]
    pub fn into_string(self) -> String { self.to_string() }

    #[inline]
    pub fn into_owned(self) -> String { self.to_string() }

    #[inline]
    pub fn is_empty(&self) -> bool { unsafe { *self.data == 0 } }
}

impl Drop for UTF8Buf {
    fn drop(&mut self) {
        unsafe { ffi::g_free(self.data as gpointer) }
    }
}

impl Clone for UTF8Buf {
    fn clone(&self) -> UTF8Buf {
        unsafe {
            UTF8Buf::wrap(ffi::g_strdup(self.data as *const gchar))
        }
    }
}

unsafe fn dup_to_c_str(source: *const c_char, len: uint) -> CString {
    let copy = malloc_raw(len + 1) as *mut c_char;
    copy_nonoverlapping_memory(copy, source, len + 1);
    CString::new(copy as *const c_char, true)
}

impl ToCStr for UTF8Buf {

    fn to_c_str(&self) -> CString {
        unsafe { self.to_c_str_unchecked() }
    }

    unsafe fn to_c_str_unchecked(&self) -> CString {
        let src = self.data as *const c_char;
        let len = libc::strlen(src) as uint;
        dup_to_c_str(src, len)
    }

    fn with_c_str<T>(&self, f: |*const i8| -> T) -> T {
        f(self.data as *const i8)
    }

    unsafe fn with_c_str_unchecked<T>(&self, f: |*const i8| -> T) -> T {
        f(self.data as *const i8)
    }
}

pub struct UTF8Str {
    buf: UTF8Buf,
    len: uint
}

static NUL: gchar = 0;

impl UTF8Str {

    pub unsafe fn wrap(data: *mut gchar, len: uint) -> UTF8Str {
        UTF8Str { buf: UTF8Buf::wrap(data), len: len }
    }

    pub fn to_string(&self) -> String {
        unsafe {
            string::raw::from_buf_len(self.buf.data as *const u8, self.len)
        }
    }
}

impl Clone for UTF8Str {
    fn clone(&self) -> UTF8Str {
        unsafe {
            let copy = ffi::g_malloc((self.len + 1) as gsize) as *mut gchar;
            copy_nonoverlapping_memory(copy,
                    self.buf.data as *const gchar, self.len);
            *copy.offset(self.len as int) = NUL;
            UTF8Str::wrap(copy, self.len)
        }
    }
}

impl Str for UTF8Str {
    fn as_slice<'a>(&'a self) -> &'a str {
        unsafe {
            slice::raw::buf_as_slice(
                self.buf.data as *const u8,
                self.len,
                |bytes| {
                    let s = str::raw::from_utf8(bytes);
                    transmute(s)
                })
        }
    }
}

impl StrAllocating for UTF8Str {
    fn into_string(self) -> String { self.to_string() }
}

impl Collection for UTF8Str {

    // Common sense says we should return the UTF-8 length,
    // but &str returns length in bytes, so...
    fn len(&self) -> uint { return self.len }

    fn is_empty(&self) -> bool { return self.len == 0 }
}

impl ToCStr for UTF8Str {

    fn to_c_str(&self) -> CString {
        unsafe { self.to_c_str_unchecked() }
    }

    unsafe fn to_c_str_unchecked(&self) -> CString {
        dup_to_c_str(self.buf.data as *const c_char, self.len)
    }

    fn with_c_str<T>(&self, f: |*const i8| -> T) -> T {
        self.buf.with_c_str(f)
    }

    unsafe fn with_c_str_unchecked<T>(&self, f: |*const i8| -> T) -> T {
        self.buf.with_c_str_unchecked(f)
    }
}

impl PartialEq for UTF8Str {
    fn eq(&self, other: &UTF8Str) -> bool {
        self.as_slice() == other.as_slice()
    }
}

impl Eq for UTF8Str { }

impl<S: Str> Equiv<S> for UTF8Str {
    fn equiv(&self, other: &S) -> bool {
        self.as_slice() == other.as_slice()
    }
}

pub trait WithUTF8 {
    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T;
}

impl WithUTF8 for UTF8Buf {

    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        f(self.data as *const gchar)
    }
}

impl WithUTF8 for UTF8Str {

    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        self.buf.with_utf8_c_str(f)
    }
}

impl<'a> WithUTF8 for &'a str {

    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        self.with_c_str(f)
    }
}

impl WithUTF8 for String {

    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        self.with_c_str(f)
    }
}
<|endoftext|>


<commit_before>import libc::types::common::c99::*;

export jsapi;

// These are just macros in jsapi.h
import JS_NewRuntime = jsapi::bindgen::JS_Init;
export JS_NewRuntime;
import JS_DestroyRuntime = jsapi::bindgen::JS_Finish;
export JS_DestroyRuntime;
/*
FIXME: Not sure where JS_Lock is
import JS_LockRuntime = jsapi::bindgen::JS_Lock;
export JS_LockRuntime;
import JS_UnlockRuntime = jsapi::bindgen::JS_Unlock;
export JS_UnlockRuntime;
*/

#[link_args = "-L."]
native mod m { }

// FIXME: Add the remaining options
const JSOPTION_STRICT: uint32_t =    0b00000000000001u32;
const JSOPTION_WERROR: uint32_t =    0b00000000000010u32;
const JSOPTION_VAROBJFIX: uint32_t = 0b00000000000100u32;
const JSOPTION_METHODJIT: uint32_t = 0b10000000000000u32;

const JSCLASS_GLOBAL_FLAGS: uint32_t = 0x47d00du32;

mod crust {
    import jsapi::*;

    crust fn JS_PropertyStub(++arg0: *JSContext, ++arg1: *JSObject, ++arg2: jsid, ++arg3: *jsval) -> JSBool {
        bindgen::JS_PropertyStub(arg0, arg1, arg2, arg3)
    }

    crust fn JS_StrictPropertyStub(++arg0: *JSContext, ++arg1: *JSObject, ++arg2: jsid, ++arg3: JSBool, ++arg4: *jsval) -> JSBool {
        bindgen::JS_StrictPropertyStub(arg0, arg1, arg2, arg3, arg4)
    }

    crust fn JS_EnumerateStub(++arg0: *JSContext, ++arg1: *JSObject) -> JSBool {
        bindgen::JS_EnumerateStub(arg0, arg1)
    }

    crust fn JS_ResolveStub(++arg0: *JSContext, ++arg1: *JSObject, ++arg2: jsid) -> JSBool {
        bindgen::JS_ResolveStub(arg0, arg1, arg2)
    }

    crust fn JS_ConvertStub(++arg0: *JSContext, ++arg1: *JSObject, ++arg2: JSType, ++arg3: *jsval) -> JSBool {
        bindgen::JS_ConvertStub(arg0, arg1, arg2, arg3)
    }

    crust fn JS_FinalizeStub(++arg0: *JSContext, ++arg2: *JSObject) {
        // FIXME: Can't find the native implementation of this
    }
}
<commit_msg>Found the implementation of JS_FinalizeStub<commit_after>import libc::types::common::c99::*;

export jsapi;

// These are just macros in jsapi.h
import JS_NewRuntime = jsapi::bindgen::JS_Init;
export JS_NewRuntime;
import JS_DestroyRuntime = jsapi::bindgen::JS_Finish;
export JS_DestroyRuntime;
/*
FIXME: Not sure where JS_Lock is
import JS_LockRuntime = jsapi::bindgen::JS_Lock;
export JS_LockRuntime;
import JS_UnlockRuntime = jsapi::bindgen::JS_Unlock;
export JS_UnlockRuntime;
*/

#[link_args = "-L."]
native mod m { }

// FIXME: Add the remaining options
const JSOPTION_STRICT: uint32_t =    0b00000000000001u32;
const JSOPTION_WERROR: uint32_t =    0b00000000000010u32;
const JSOPTION_VAROBJFIX: uint32_t = 0b00000000000100u32;
const JSOPTION_METHODJIT: uint32_t = 0b10000000000000u32;

const JSCLASS_GLOBAL_FLAGS: uint32_t = 0x47d00du32;

mod crust {
    import jsapi::*;

    crust fn JS_PropertyStub(++arg0: *JSContext, ++arg1: *JSObject, ++arg2: jsid, ++arg3: *jsval) -> JSBool {
        bindgen::JS_PropertyStub(arg0, arg1, arg2, arg3)
    }

    crust fn JS_StrictPropertyStub(++arg0: *JSContext, ++arg1: *JSObject, ++arg2: jsid, ++arg3: JSBool, ++arg4: *jsval) -> JSBool {
        bindgen::JS_StrictPropertyStub(arg0, arg1, arg2, arg3, arg4)
    }

    crust fn JS_EnumerateStub(++arg0: *JSContext, ++arg1: *JSObject) -> JSBool {
        bindgen::JS_EnumerateStub(arg0, arg1)
    }

    crust fn JS_ResolveStub(++arg0: *JSContext, ++arg1: *JSObject, ++arg2: jsid) -> JSBool {
        bindgen::JS_ResolveStub(arg0, arg1, arg2)
    }

    crust fn JS_ConvertStub(++arg0: *JSContext, ++arg1: *JSObject, ++arg2: JSType, ++arg3: *jsval) -> JSBool {
        bindgen::JS_ConvertStub(arg0, arg1, arg2, arg3)
    }

    crust fn JS_FinalizeStub(++arg0: *JSContext, ++arg2: *JSObject) {
        bindgen::JS_FinalizeStub(arg0, arg2);
    }
}
<|endoftext|>