<commit_before>//! The `print-cfg` sub-command.
//!
//! Read a series of Cretonne IL files and print their control flow graphs
//! in graphviz format.
use std::fs::File;
use std::io::{Read, Write, stdout};

use CommandResult;
use cretonne::ir::Function;
use cretonne::cfg::ControlFlowGraph;
use cretonne::ir::instructions::InstructionData;
use cton_reader::parser::Parser;

pub fn run(files: Vec<String>) -> CommandResult {
    for (i, f) in files.into_iter().enumerate() {
        if i != 0 {
            println!("");
        }
        try!(print_cfg(f))
    }
    Ok(())
}

struct CFGPrinter<T: Write> {
    level: usize,
    writer: T,
    buffer: String,
}

impl<T: Write> CFGPrinter<T> {
    pub fn new(writer: T) -> CFGPrinter<T> {
        CFGPrinter {
            level: 0,
            writer: writer,
            buffer: String::new(),
        }
    }

    pub fn print(&mut self, func: &Function) -> Result<(), String> {
        self.level = 0;
        self.header(func);
        self.push_indent();
        self.ebb_subgraphs(func);
        let cfg = ControlFlowGraph::new(&func);
        self.cfg_connections(&cfg);
        self.pop_indent();
        self.footer();
        self.write()
    }

    fn write(&mut self) -> Result<(), String> {
        match self.writer.write(self.buffer.as_bytes()) {
            Err(_) => return Err("Write failed!".to_string()),
            _ => (),
        };
        match self.writer.flush() {
            Err(_) => return Err("Flush failed!".to_string()),
            _ => (),
        };
        Ok(())
    }

    fn append(&mut self, s: &str) {
        let mut indent = String::new();
        for _ in 0..self.level {
            indent = indent + "    ";
        }
        self.buffer.push_str(&(indent + s));
    }

    fn push_indent(&mut self) {
        self.level += 1;
    }

    fn pop_indent(&mut self) {
        if self.level > 0 {
            self.level -= 1;
        }
    }

    fn open_paren(&mut self) {
        self.append("{");
    }

    fn close_paren(&mut self) {
        self.append("}");
    }

    fn newline(&mut self) {
        self.append("\n");
    }

    fn header(&mut self, func: &Function) {
        self.append(&format!("digraph {} ", func.name));
        self.open_paren();
        self.newline();
        self.push_indent();
        self.append("{rank=min; ebb0}");
        self.pop_indent();
        self.newline();
    }

    fn footer(&mut self) {
        self.close_paren();
        self.newline();
    }

    fn ebb_subgraphs(&mut self, func: &Function) {
        for ebb in &func.layout {
            let inst_data = func.layout
                .ebb_insts(ebb)
                .filter(|inst| {
                    match func.dfg[*inst] {
                        InstructionData::Branch { ty: _, opcode: _, data: _ } => true,
                        InstructionData::Jump { ty: _, opcode: _, data: _ } => true,
                        _ => false,
                    }
                })
                .map(|inst| {
                    let op = match func.dfg[inst] {
                        InstructionData::Branch { ty: _, opcode, ref data } => {
                            Some((opcode, data.destination))
                        }
                        InstructionData::Jump { ty: _, opcode, ref data } => {
                            Some((opcode, data.destination))
                        }
                        _ => None,
                    };
                    (inst, op)
                })
                .collect::<Vec<_>>();

            let mut insts = vec![format!("{}", ebb)];
            for (inst, data) in inst_data {
                let (op, dest) = data.unwrap();
                insts.push(format!("<{}>{} {}", inst, op, dest));
            }

            self.append(&format!("{} [shape=record, label=\"{}{}{}\"]",
                                 ebb,
                                 "{",
                                 insts.join(" | "),
                                 "}"));
            self.newline();
        }
    }

    fn cfg_connections(&mut self, cfg: &ControlFlowGraph) {
        for (ref ebb, ref predecessors) in cfg.predecessors_iter() {
            for &(parent, inst) in *predecessors {
                self.append(&format!("{}:{} -> {}", parent, inst, ebb));
                self.newline();
            }
        }
    }
}

fn print_cfg(filename: String) -> CommandResult {
    let mut file = try!(File::open(&filename).map_err(|e| format!("{}: {}", filename, e)));
    let mut buffer = String::new();
    try!(file.read_to_string(&mut buffer)
        .map_err(|e| format!("Couldn't read {}: {}", filename, e)));
    let items = try!(Parser::parse(&buffer).map_err(|e| format!("{}: {}", filename, e)));

    let mut cfg_printer = CFGPrinter::new(stdout());
    for (idx, func) in items.into_iter().enumerate() {
        if idx != 0 {
            println!("");
        }

        try!(cfg_printer.print(&func));
    }

    Ok(())
}
<commit_msg>Print CFG edges from func.layout instead of cfg.predecessors_iter.<commit_after>//! The `print-cfg` sub-command.
//!
//! Read a series of Cretonne IL files and print their control flow graphs
//! in graphviz format.
use std::fs::File;
use std::io::{Read, Write, stdout};

use CommandResult;
use cretonne::ir::Function;
use cretonne::cfg::ControlFlowGraph;
use cretonne::ir::instructions::InstructionData;
use cton_reader::parser::Parser;

pub fn run(files: Vec<String>) -> CommandResult {
    for (i, f) in files.into_iter().enumerate() {
        if i != 0 {
            println!("");
        }
        try!(print_cfg(f))
    }
    Ok(())
}

struct CFGPrinter<T: Write> {
    level: usize,
    writer: T,
    buffer: String,
}

impl<T: Write> CFGPrinter<T> {
    pub fn new(writer: T) -> CFGPrinter<T> {
        CFGPrinter {
            level: 0,
            writer: writer,
            buffer: String::new(),
        }
    }

    pub fn print(&mut self, func: &Function) -> Result<(), String> {
        self.level = 0;
        self.header(func);
        self.push_indent();
        self.ebb_subgraphs(func);
        let cfg = ControlFlowGraph::new(func);
        self.cfg_connections(func, &cfg);
        self.pop_indent();
        self.footer();
        self.write()
    }

    fn write(&mut self) -> Result<(), String> {
        match self.writer.write(self.buffer.as_bytes()) {
            Err(_) => return Err("Write failed!".to_string()),
            _ => (),
        };
        match self.writer.flush() {
            Err(_) => return Err("Flush failed!".to_string()),
            _ => (),
        };
        Ok(())
    }

    fn append(&mut self, s: &str) {
        let mut indent = String::new();
        for _ in 0..self.level {
            indent = indent + "    ";
        }
        self.buffer.push_str(&(indent + s));
    }

    fn push_indent(&mut self) {
        self.level += 1;
    }

    fn pop_indent(&mut self) {
        if self.level > 0 {
            self.level -= 1;
        }
    }

    fn open_paren(&mut self) {
        self.append("{");
    }

    fn close_paren(&mut self) {
        self.append("}");
    }

    fn newline(&mut self) {
        self.append("\n");
    }

    fn header(&mut self, func: &Function) {
        self.append(&format!("digraph {} ", func.name));
        self.open_paren();
        self.newline();
        self.push_indent();
        self.append("{rank=min; ebb0}");
        self.pop_indent();
        self.newline();
    }

    fn footer(&mut self) {
        self.close_paren();
        self.newline();
    }

    fn ebb_subgraphs(&mut self, func: &Function) {
        for ebb in &func.layout {
            let inst_data = func.layout
                .ebb_insts(ebb)
                .filter(|inst| {
                    match func.dfg[*inst] {
                        InstructionData::Branch { ty: _, opcode: _, data: _ } => true,
                        InstructionData::Jump { ty: _, opcode: _, data: _ } => true,
                        _ => false,
                    }
                })
                .map(|inst| {
                    let op = match func.dfg[inst] {
                        InstructionData::Branch { ty: _, opcode, ref data } => {
                            Some((opcode, data.destination))
                        }
                        InstructionData::Jump { ty: _, opcode, ref data } => {
                            Some((opcode, data.destination))
                        }
                        _ => None,
                    };
                    (inst, op)
                })
                .collect::<Vec<_>>();

            let mut insts = vec![format!("{}", ebb)];
            for (inst, data) in inst_data {
                let (op, dest) = data.unwrap();
                insts.push(format!("<{}>{} {}", inst, op, dest));
            }

            self.append(&format!("{} [shape=record, label=\"{}{}{}\"]",
                                 ebb,
                                 "{",
                                 insts.join(" | "),
                                 "}"));
            self.newline();
        }
    }

    fn cfg_connections(&mut self, func: &Function, cfg: &ControlFlowGraph) {
        for ebb in &func.layout {
            for &(parent, inst) in cfg.get_predecessors(ebb) {
                self.append(&format!("{}:{} -> {}", parent, inst, ebb));
                self.newline();
            }
        }
    }
}

fn print_cfg(filename: String) -> CommandResult {
    let mut file = try!(File::open(&filename).map_err(|e| format!("{}: {}", filename, e)));
    let mut buffer = String::new();
    try!(file.read_to_string(&mut buffer)
        .map_err(|e| format!("Couldn't read {}: {}", filename, e)));
    let items = try!(Parser::parse(&buffer).map_err(|e| format!("{}: {}", filename, e)));

    let mut cfg_printer = CFGPrinter::new(stdout());
    for (idx, func) in items.into_iter().enumerate() {
        if idx != 0 {
            println!("");
        }

        try!(cfg_printer.print(&func));
    }

    Ok(())
}
<|endoftext|>


<commit_before>use std::ptr::null;
use libc::{c_char, c_int, c_double};
use std::ffi::CString;
use std::cell::RefCell;
use utils::_string;
use vector::ogr;
use geo;

/// OGR Geometry
pub struct Geometry {
    c_geometry_ref: RefCell<Option<*const ()>>,
    owned: bool,
}

impl Geometry {
    pub unsafe fn lazy_feature_geometry() -> Geometry {
        // Geometry objects created with this method map to a Feature's
        // geometry whose memory is managed by the GDAL feature.
        // This object has a tricky lifecycle:
        //
        // * Initially it's created with a null c_geometry
        // * The first time `Feature::geometry` is called, it gets
        //   c_geometry from GDAL and calls `set_c_geometry` with it.
        // * When the Feature is destroyed, this object is also destroyed,
        //   which is good, because that's when c_geometry (which is managed
        //   by the GDAL feature) becomes invalid. Because `self.owned` is
        //   `true`, we don't call `OGR_G_DestroyGeometry`.
        return Geometry{c_geometry_ref: RefCell::new(None), owned: false};
    }

    pub fn has_gdal_ptr(&self) -> bool {
        return self.c_geometry_ref.borrow().is_some();
    }

    pub unsafe fn set_c_geometry(&self, c_geometry: *const ()) {
        assert!(! self.has_gdal_ptr());
        assert_eq!(self.owned, false);
        *(self.c_geometry_ref.borrow_mut()) = Some(c_geometry);
    }

    unsafe fn with_c_geometry(c_geom: *const()) -> Geometry {
        return Geometry{
            c_geometry_ref: RefCell::new(Some(c_geom)),
            owned: true,
        };
    }

    pub fn empty(wkb_type: c_int) -> Geometry {
        let c_geom = unsafe { ogr::OGR_G_CreateGeometry(wkb_type) };
        assert!(c_geom != null());
        return unsafe { Geometry::with_c_geometry(c_geom) };
    }

    /// Create a geometry by parsing a
    /// [WKT](https://en.wikipedia.org/wiki/Well-known_text) string.
    pub fn from_wkt(wkt: &str) -> Geometry {
        let c_wkt = CString::new(wkt.as_bytes()).unwrap();
        let mut c_wkt_ptr: *const c_char = c_wkt.as_ptr();
        let mut c_geom: *const () = null();
        let rv = unsafe { ogr::OGR_G_CreateFromWkt(&mut c_wkt_ptr, null(), &mut c_geom) };
        assert_eq!(rv, ogr::OGRERR_NONE);
        return unsafe { Geometry::with_c_geometry(c_geom) };
    }

    /// Create a rectangular geometry from West, South, East and North values.
    pub fn bbox(w: f64, s: f64, e: f64, n: f64) -> Geometry {
        Geometry::from_wkt(&format!(
            "POLYGON (({} {}, {} {}, {} {}, {} {}, {} {}))",
            w, n,
            e, n,
            e, s,
            w, s,
            w, n,
        ))
    }

    /// Serialize the geometry as JSON.
    pub fn json(&self) -> String {
        let c_json = unsafe { ogr::OGR_G_ExportToJson(self.c_geometry()) };
        let rv = _string(c_json);
        unsafe { ogr::VSIFree(c_json as *mut ()) };
        return rv;
    }

    /// Serialize the geometry as WKT.
    pub fn wkt(&self) -> String {
        let mut c_wkt: *const c_char = null();
        let _err = unsafe { ogr::OGR_G_ExportToWkt(self.c_geometry(), &mut c_wkt) };
        assert_eq!(_err, ogr::OGRERR_NONE);
        let wkt = _string(c_wkt);
        unsafe { ogr::OGRFree(c_wkt as *mut ()) };
        return wkt;
    }

    pub unsafe fn c_geometry(&self) -> *const () {
        return self.c_geometry_ref.borrow().unwrap();
    }

    pub fn set_point_2d(&mut self, i: i32, p: (f64, f64)) {
        let (x, y) = p;
        unsafe { ogr::OGR_G_SetPoint_2D(
            self.c_geometry(),
            i as c_int,
            x as c_double,
            y as c_double,
        ) };
    }

    pub fn get_point(&self, i: i32) -> (f64, f64, f64) {
        let mut x: c_double = 0.;
        let mut y: c_double = 0.;
        let mut z: c_double = 0.;
        unsafe { ogr::OGR_G_GetPoint(self.c_geometry(), i, &mut x, &mut y, &mut z) };
        return (x as f64, y as f64, z as f64);
    }

    /// Compute the convex hull of this geometry.
    pub fn convex_hull(&self) -> Geometry {
        let c_geom = unsafe { ogr::OGR_G_ConvexHull(self.c_geometry()) };
        return unsafe { Geometry::with_c_geometry(c_geom) };
    }
}

impl geo::ToGeo for Geometry {
    fn to_geo(&self) -> geo::Geometry {
        let geometry_type = unsafe { ogr::OGR_G_GetGeometryType(self.c_geometry()) };
        match geometry_type {
            1 => {
                let (x, y, _) = self.get_point(0);
                geo::Geometry::Point(geo::Point(geo::Coordinate{x: x, y: y}))
            },
            _ => panic!("Unknown geometry type")
        }
    }
}

impl Drop for Geometry {
    fn drop(&mut self) {
        if self.owned {
            let c_geometry = self.c_geometry_ref.borrow();
            unsafe { ogr::OGR_G_DestroyGeometry(c_geometry.unwrap() as *mut ()) };
        }
    }
}

pub trait ToGdal {
    fn to_gdal(&self) -> Geometry;
}

impl ToGdal for geo::Point {
    fn to_gdal(&self) -> Geometry {
        let mut geom = Geometry::empty(ogr::WKB_POINT);
        let &geo::Point(coordinate) = self;
        geom.set_point_2d(0, (coordinate.x, coordinate.y));
        return geom;
    }
}

#[cfg(test)]
mod tests {
    use vector::{Geometry, ToGdal};
    use geo;
    use geo::ToGeo;

    #[test]
    fn test_import_export_point() {
        let wkt = "POINT (1 2)";
        let coord = geo::Coordinate{x: 1., y: 2.};
        let geo_point = geo::Point(coord);
        let geo = geo::Geometry::Point(geo_point);

        assert_eq!(Geometry::from_wkt(wkt).to_geo(), geo);
        assert_eq!(geo_point.to_gdal().wkt(), wkt);
    }
}
<commit_msg>implement `ToGdal` for `geo::Geometry`<commit_after>use std::ptr::null;
use libc::{c_char, c_int, c_double};
use std::ffi::CString;
use std::cell::RefCell;
use utils::_string;
use vector::ogr;
use geo;

/// OGR Geometry
pub struct Geometry {
    c_geometry_ref: RefCell<Option<*const ()>>,
    owned: bool,
}

impl Geometry {
    pub unsafe fn lazy_feature_geometry() -> Geometry {
        // Geometry objects created with this method map to a Feature's
        // geometry whose memory is managed by the GDAL feature.
        // This object has a tricky lifecycle:
        //
        // * Initially it's created with a null c_geometry
        // * The first time `Feature::geometry` is called, it gets
        //   c_geometry from GDAL and calls `set_c_geometry` with it.
        // * When the Feature is destroyed, this object is also destroyed,
        //   which is good, because that's when c_geometry (which is managed
        //   by the GDAL feature) becomes invalid. Because `self.owned` is
        //   `true`, we don't call `OGR_G_DestroyGeometry`.
        return Geometry{c_geometry_ref: RefCell::new(None), owned: false};
    }

    pub fn has_gdal_ptr(&self) -> bool {
        return self.c_geometry_ref.borrow().is_some();
    }

    pub unsafe fn set_c_geometry(&self, c_geometry: *const ()) {
        assert!(! self.has_gdal_ptr());
        assert_eq!(self.owned, false);
        *(self.c_geometry_ref.borrow_mut()) = Some(c_geometry);
    }

    unsafe fn with_c_geometry(c_geom: *const()) -> Geometry {
        return Geometry{
            c_geometry_ref: RefCell::new(Some(c_geom)),
            owned: true,
        };
    }

    pub fn empty(wkb_type: c_int) -> Geometry {
        let c_geom = unsafe { ogr::OGR_G_CreateGeometry(wkb_type) };
        assert!(c_geom != null());
        return unsafe { Geometry::with_c_geometry(c_geom) };
    }

    /// Create a geometry by parsing a
    /// [WKT](https://en.wikipedia.org/wiki/Well-known_text) string.
    pub fn from_wkt(wkt: &str) -> Geometry {
        let c_wkt = CString::new(wkt.as_bytes()).unwrap();
        let mut c_wkt_ptr: *const c_char = c_wkt.as_ptr();
        let mut c_geom: *const () = null();
        let rv = unsafe { ogr::OGR_G_CreateFromWkt(&mut c_wkt_ptr, null(), &mut c_geom) };
        assert_eq!(rv, ogr::OGRERR_NONE);
        return unsafe { Geometry::with_c_geometry(c_geom) };
    }

    /// Create a rectangular geometry from West, South, East and North values.
    pub fn bbox(w: f64, s: f64, e: f64, n: f64) -> Geometry {
        Geometry::from_wkt(&format!(
            "POLYGON (({} {}, {} {}, {} {}, {} {}, {} {}))",
            w, n,
            e, n,
            e, s,
            w, s,
            w, n,
        ))
    }

    /// Serialize the geometry as JSON.
    pub fn json(&self) -> String {
        let c_json = unsafe { ogr::OGR_G_ExportToJson(self.c_geometry()) };
        let rv = _string(c_json);
        unsafe { ogr::VSIFree(c_json as *mut ()) };
        return rv;
    }

    /// Serialize the geometry as WKT.
    pub fn wkt(&self) -> String {
        let mut c_wkt: *const c_char = null();
        let _err = unsafe { ogr::OGR_G_ExportToWkt(self.c_geometry(), &mut c_wkt) };
        assert_eq!(_err, ogr::OGRERR_NONE);
        let wkt = _string(c_wkt);
        unsafe { ogr::OGRFree(c_wkt as *mut ()) };
        return wkt;
    }

    pub unsafe fn c_geometry(&self) -> *const () {
        return self.c_geometry_ref.borrow().unwrap();
    }

    pub fn set_point_2d(&mut self, i: i32, p: (f64, f64)) {
        let (x, y) = p;
        unsafe { ogr::OGR_G_SetPoint_2D(
            self.c_geometry(),
            i as c_int,
            x as c_double,
            y as c_double,
        ) };
    }

    pub fn get_point(&self, i: i32) -> (f64, f64, f64) {
        let mut x: c_double = 0.;
        let mut y: c_double = 0.;
        let mut z: c_double = 0.;
        unsafe { ogr::OGR_G_GetPoint(self.c_geometry(), i, &mut x, &mut y, &mut z) };
        return (x as f64, y as f64, z as f64);
    }

    /// Compute the convex hull of this geometry.
    pub fn convex_hull(&self) -> Geometry {
        let c_geom = unsafe { ogr::OGR_G_ConvexHull(self.c_geometry()) };
        return unsafe { Geometry::with_c_geometry(c_geom) };
    }
}

impl geo::ToGeo for Geometry {
    fn to_geo(&self) -> geo::Geometry {
        let geometry_type = unsafe { ogr::OGR_G_GetGeometryType(self.c_geometry()) };
        match geometry_type {
            1 => {
                let (x, y, _) = self.get_point(0);
                geo::Geometry::Point(geo::Point(geo::Coordinate{x: x, y: y}))
            },
            _ => panic!("Unknown geometry type")
        }
    }
}

impl Drop for Geometry {
    fn drop(&mut self) {
        if self.owned {
            let c_geometry = self.c_geometry_ref.borrow();
            unsafe { ogr::OGR_G_DestroyGeometry(c_geometry.unwrap() as *mut ()) };
        }
    }
}

pub trait ToGdal {
    fn to_gdal(&self) -> Geometry;
}

impl ToGdal for geo::Point {
    fn to_gdal(&self) -> Geometry {
        let mut geom = Geometry::empty(ogr::WKB_POINT);
        let &geo::Point(coordinate) = self;
        geom.set_point_2d(0, (coordinate.x, coordinate.y));
        return geom;
    }
}

impl ToGdal for geo::Geometry {
    fn to_gdal(&self) -> Geometry {
        return match *self {
            geo::Geometry::Point(ref c) => c.to_gdal(),
            geo::Geometry::LineString(ref c) => c.to_gdal(),
            _ => panic!("Unknown geometry type")
        }
    }
}

#[cfg(test)]
mod tests {
    use vector::{Geometry, ToGdal};
    use geo;
    use geo::ToGeo;

    #[test]
    fn test_import_export_point() {
        let wkt = "POINT (1 2)";
        let coord = geo::Coordinate{x: 1., y: 2.};
        let geo = geo::Geometry::Point(geo::Point(coord));

        assert_eq!(Geometry::from_wkt(wkt).to_geo(), geo);
        assert_eq!(geo.to_gdal().wkt(), wkt);
    }
}
<|endoftext|>


<commit_before>use super::Vector;
use super::Vector2;

pub struct Vector2f {
    pub x: f32,
    pub y: f32,
}

impl Default for Vector2f {
    fn default() -> Vector2f {
        Vector2f {
            x: 0f32,
            y: 0f32,
        }
    }
}

impl Vector<Vector2f, f32> for Vector2f {
    fn add(&mut self, v: &Vector2f) -> &mut Self {
        self.x += v.x;
        self.y += v.y;
        self
    }

    fn add_into(&self, v: &Vector2f, dest: &mut Vector2f) {
        dest.x = self.x + v.x;
        dest.y = self.y + v.y;
    }

    fn angle(&self, v: &Vector2f) -> f32 {
        unimplemented!()
    }

    fn angle_cos(&self, v: &Vector2f) -> f32 {
        unimplemented!()
    }

    fn distance(&self, v: &Vector2f) -> f32 {
        self.distance_squared(v).sqrt()
    }

    fn distance_squared(&self, v: &Vector2f) -> f32 {
        let dx = self.x - v.x;
        let dy = self.y - v.y;
        (dx * dx) + (dy * dy)
    }

    fn dot(&self, v: &Vector2f) -> f32 {
        (self.x * v.x) + (self.y * v.y)
    }

    fn fma_scalar(&mut self, a: f32, b: &Vector2f) -> &mut Self {
        unimplemented!()
    }

    fn fma_scalar_into(&self, a: f32, b: &Vector2f, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn fma_vector(&mut self, a: &Vector2f, b: &Vector2f) -> &mut Self {
        unimplemented!()
    }

    fn fma_vector_into(&self, a: &Vector2f, b: &Vector2f, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn length(&self) -> f32 {
        self.length_squared().sqrt()
    }

    fn length_squared(&self) -> f32 {
        (self.x * self.x) + (self.y * self.y)
    }

    fn lerp(&mut self, other: &Vector2f, t: f32) -> &mut Self {
        unimplemented!()
    }

    fn lerp_into(&self, other: &Vector2f, t: f32, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn mul_scalar(&mut self, s: f32) -> &mut Self {
        self.x *= s;
        self.y *= s;
        self
    }

    fn mul_scalar_into(&self, s: f32, dest: &mut Vector2f) {
        dest.x = self.x * s;
        dest.y = self.y * s;
    }

    fn mul_vector(&mut self, v: &Vector2f) -> &mut Self {
        unimplemented!()
    }

    fn mul_vector_into(&self, v: &Vector2f, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn negate(&mut self) -> &mut Self {
        unimplemented!()
    }

    fn negate_into(&self, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn normalize(&mut self) -> &mut Self {
        unimplemented!()
    }

    fn normalize_into(&self, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn set(&mut self, v: &Vector2f) -> &mut Self {
        unimplemented!()
    }

    fn sub(&mut self, v: &Vector2f) -> &mut Self {
        unimplemented!()
    }

    fn sub_into(&self, v: &Vector2f, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn zero(&mut self) -> &mut Self {
        unimplemented!()
    }
}

impl Vector2<Vector2f, f32> for Vector2f {
    fn new(x: f32, y: f32) -> Self {
        Vector2f {
            x: x,
            y: y,
        }
    }

    fn add_components(&mut self, x: f32, y: f32) -> &mut Self {
        unimplemented!()
    }

    fn add_components_into(&self, x: f32, y: f32, dest: &mut Vector2f) {
        unimplemented!()
    }
}

#[cfg(test)]
mod tests {
    use super::super::Vector;
    use super::super::Vector2;
    use super::Vector2f;

    #[test]
    fn test_new() {
        let a = Vector2f::new(1f32, 2f32);

        assert_eq!(a.x, 1f32);
        assert_eq!(a.y, 2f32);
    }

    #[test]
    fn test_add() {
        let mut a = Vector2f::default();
        let b = Vector2f::new(1f32, 2f32);

        a.add(&b);

        assert_eq!(a.x, 1f32);
        assert_eq!(a.y, 2f32);
    }

    #[test]
    fn test_add_into() {
        let a = Vector2f::new(1f32, 1f32);
        let b = Vector2f::new(1f32, 2f32);
        let mut c = Vector2f::default();

        a.add_into(&b, &mut c);

        assert_eq!(c.x, 2f32);
        assert_eq!(c.y, 3f32);
    }

    #[test]
    fn test_distance() {
        let a = Vector2f::new(2f32, 1f32);
        let b = Vector2f::new(0f32, 1f32);

        let target_distance = 2f32;
        let distance = a.distance(&b);

        assert_eq!(target_distance, distance);
    }

    #[test]
    fn test_distance_squared() {
        let a = Vector2f::new(2f32, 1f32);
        let b = Vector2f::new(0f32, 1f32);

        let target_distance_sq = 4f32; //distance is 2
        let distance_sq = a.distance_squared(&b);

        assert_eq!(target_distance_sq, distance_sq);
    }

    #[test]
    fn test_dot() {
        let a = Vector2f::new(2f32, 1f32);
        let b = Vector2f::new(1f32, 1f32);

        let target_dot = 3f32;
        let dot = a.dot(&b);

        assert_eq!(target_dot, dot);
    }

    #[test]
    fn test_length() {
        let a = Vector2f::new(3f32, 4f32);

        let target_length = 5f32; //length should be 5 because of the 3:4:5 triangle
        let length = a.length();

        assert_eq!(target_length, length);
    }

    #[test]
    fn test_length_squared() {
        let a = Vector2f::new(3f32, 4f32);

        let target_length_sq = 25f32; //length should be 5 because of the 3:4:5 triangle
        let length_sq = a.length_squared();

        assert_eq!(target_length_sq, length_sq);
    }

    #[test]
    fn test_mul_scalar() {
        let mut a = Vector2f::new(1f32, 2f32);
        let b = 2f32;

        a.mul_scalar(b);

        assert_eq!(a.x, 2f32);
        assert_eq!(a.y, 4f32);
    }

    #[test]
    fn test_mul_scalar_into() {
        let a = Vector2f::new(1f32, 2f32);
        let b = 2f32;
        let mut c = Vector2::new(0f32, 0f32);

        a.mul_scalar_into(b, &mut c);

        assert_eq!(c.x, 2f32);
        assert_eq!(c.y, 4f32);
    }
}
<commit_msg>add mul_vector impls<commit_after>use super::Vector;
use super::Vector2;

pub struct Vector2f {
    pub x: f32,
    pub y: f32,
}

impl Default for Vector2f {
    fn default() -> Vector2f {
        Vector2f {
            x: 0f32,
            y: 0f32,
        }
    }
}

impl Vector<Vector2f, f32> for Vector2f {
    fn add(&mut self, v: &Vector2f) -> &mut Self {
        self.x += v.x;
        self.y += v.y;
        self
    }

    fn add_into(&self, v: &Vector2f, dest: &mut Vector2f) {
        dest.x = self.x + v.x;
        dest.y = self.y + v.y;
    }

    fn angle(&self, v: &Vector2f) -> f32 {
        unimplemented!()
    }

    fn angle_cos(&self, v: &Vector2f) -> f32 {
        unimplemented!()
    }

    fn distance(&self, v: &Vector2f) -> f32 {
        self.distance_squared(v).sqrt()
    }

    fn distance_squared(&self, v: &Vector2f) -> f32 {
        let dx = self.x - v.x;
        let dy = self.y - v.y;
        (dx * dx) + (dy * dy)
    }

    fn dot(&self, v: &Vector2f) -> f32 {
        (self.x * v.x) + (self.y * v.y)
    }

    fn fma_scalar(&mut self, a: f32, b: &Vector2f) -> &mut Self {
        unimplemented!()
    }

    fn fma_scalar_into(&self, a: f32, b: &Vector2f, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn fma_vector(&mut self, a: &Vector2f, b: &Vector2f) -> &mut Self {
        unimplemented!()
    }

    fn fma_vector_into(&self, a: &Vector2f, b: &Vector2f, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn length(&self) -> f32 {
        self.length_squared().sqrt()
    }

    fn length_squared(&self) -> f32 {
        (self.x * self.x) + (self.y * self.y)
    }

    fn lerp(&mut self, other: &Vector2f, t: f32) -> &mut Self {
        unimplemented!()
    }

    fn lerp_into(&self, other: &Vector2f, t: f32, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn mul_scalar(&mut self, s: f32) -> &mut Self {
        self.x *= s;
        self.y *= s;
        self
    }

    fn mul_scalar_into(&self, s: f32, dest: &mut Vector2f) {
        dest.x = self.x * s;
        dest.y = self.y * s;
    }

    fn mul_vector(&mut self, v: &Vector2f) -> &mut Self {
        self.x *= v.x;
        self.y *= v.y;
        self
    }

    fn mul_vector_into(&self, v: &Vector2f, dest: &mut Vector2f) {
        dest.x = self.x * v.x;
        dest.y = self.y * v.y;
    }

    fn negate(&mut self) -> &mut Self {
        unimplemented!()
    }

    fn negate_into(&self, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn normalize(&mut self) -> &mut Self {
        unimplemented!()
    }

    fn normalize_into(&self, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn set(&mut self, v: &Vector2f) -> &mut Self {
        unimplemented!()
    }

    fn sub(&mut self, v: &Vector2f) -> &mut Self {
        unimplemented!()
    }

    fn sub_into(&self, v: &Vector2f, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn zero(&mut self) -> &mut Self {
        unimplemented!()
    }
}

impl Vector2<Vector2f, f32> for Vector2f {
    fn new(x: f32, y: f32) -> Self {
        Vector2f {
            x: x,
            y: y,
        }
    }

    fn add_components(&mut self, x: f32, y: f32) -> &mut Self {
        unimplemented!()
    }

    fn add_components_into(&self, x: f32, y: f32, dest: &mut Vector2f) {
        unimplemented!()
    }
}

#[cfg(test)]
mod tests {
    use super::super::Vector;
    use super::super::Vector2;
    use super::Vector2f;

    #[test]
    fn test_new() {
        let a = Vector2f::new(1f32, 2f32);

        assert_eq!(a.x, 1f32);
        assert_eq!(a.y, 2f32);
    }

    #[test]
    fn test_add() {
        let mut a = Vector2f::default();
        let b = Vector2f::new(1f32, 2f32);

        a.add(&b);

        assert_eq!(a.x, 1f32);
        assert_eq!(a.y, 2f32);
    }

    #[test]
    fn test_add_into() {
        let a = Vector2f::new(1f32, 1f32);
        let b = Vector2f::new(1f32, 2f32);
        let mut c = Vector2f::default();

        a.add_into(&b, &mut c);

        assert_eq!(c.x, 2f32);
        assert_eq!(c.y, 3f32);
    }

    #[test]
    fn test_distance() {
        let a = Vector2f::new(2f32, 1f32);
        let b = Vector2f::new(0f32, 1f32);

        let target_distance = 2f32;
        let distance = a.distance(&b);

        assert_eq!(target_distance, distance);
    }

    #[test]
    fn test_distance_squared() {
        let a = Vector2f::new(2f32, 1f32);
        let b = Vector2f::new(0f32, 1f32);

        let target_distance_sq = 4f32; //distance is 2
        let distance_sq = a.distance_squared(&b);

        assert_eq!(target_distance_sq, distance_sq);
    }

    #[test]
    fn test_dot() {
        let a = Vector2f::new(2f32, 1f32);
        let b = Vector2f::new(1f32, 1f32);

        let target_dot = 3f32;
        let dot = a.dot(&b);

        assert_eq!(target_dot, dot);
    }

    #[test]
    fn test_length() {
        let a = Vector2f::new(3f32, 4f32);

        let target_length = 5f32; //length should be 5 because of the 3:4:5 triangle
        let length = a.length();

        assert_eq!(target_length, length);
    }

    #[test]
    fn test_length_squared() {
        let a = Vector2f::new(3f32, 4f32);

        let target_length_sq = 25f32; //length should be 5 because of the 3:4:5 triangle
        let length_sq = a.length_squared();

        assert_eq!(target_length_sq, length_sq);
    }

    #[test]
    fn test_mul_scalar() {
        let mut a = Vector2f::new(1f32, 2f32);
        let b = 2f32;

        a.mul_scalar(b);

        assert_eq!(a.x, 2f32);
        assert_eq!(a.y, 4f32);
    }

    #[test]
    fn test_mul_scalar_into() {
        let a = Vector2f::new(1f32, 2f32);
        let b = 2f32;
        let mut c = Vector2::new(0f32, 0f32);

        a.mul_scalar_into(b, &mut c);

        assert_eq!(c.x, 2f32);
        assert_eq!(c.y, 4f32);
    }

    #[test]
    fn test_mul_vector() {
        let mut a = Vector2f::new(1f32, 2f32);
        let b = Vector2f::new(2f32, 3f32);

        a.mul_vector(&b);

        assert_eq!(a.x, 2f32);
        assert_eq!(a.y, 6f32);
    }

    #[test]
    fn test_mul_vector_into() {
        let a = Vector2f::new(1f32, 2f32);
        let b = Vector2f::new(2f32, 3f32);
        let mut c = Vector2::new(0f32, 0f32);

        a.mul_vector_into(&b, &mut c);

        assert_eq!(c.x, 2f32);
        assert_eq!(c.y, 6f32);
    }
}
<|endoftext|>


<commit_before>use unicode_segmentation::UnicodeSegmentation;
use unicode_width::UnicodeWidthStr;
use odds::vec::VecExt;

use {Printer, With, XY};
use direction::Direction;
use vec::Vec2;
use event::{Event, EventResult, Key};
use utils::{LinesIterator, Row, prefix_length};
use view::{ScrollBase, SizeCache, View};
use theme::{ColorStyle, Effect};

/// Multi-lines text editor.
///
/// A `TextArea` by itself doesn't have a well-defined size.
/// You should wrap it in a `BoxView` to control its size.
pub struct TextArea {
    // TODO: use a smarter data structure (rope?)
    content: String,
    /// Byte offsets within `content` representing text rows
    rows: Vec<Row>,

    /// When `false`, we don't take any input.
    enabled: bool,

    /// Base for scrolling features
    scrollbase: ScrollBase,

    /// Cache to avoid re-computing layout on no-op events
    last_size: Option<XY<SizeCache>>,

    /// Byte offset of the currently selected grapheme.
    cursor: usize,
}

fn make_rows(text: &str, width: usize) -> Vec<Row> {
    LinesIterator::new(text, width)
        .show_spaces()
        .collect()
}

new_default!(TextArea);

impl TextArea {
    /// Creates a new, empty TextArea.
    pub fn new() -> Self {
        TextArea {
            content: String::new(),
            rows: vec![Row {
                           start: 0,
                           end: 0,
                           width: 0,
                       }],
            enabled: true,
            scrollbase: ScrollBase::new().right_padding(0),
            last_size: None,
            cursor: 0,
        }
    }

    /// Retrieves the content of the view.
    pub fn get_content(&self) -> &str {
        &self.content
    }

    fn invalidate(&mut self) {
        self.last_size = None;
    }

    /// Sets the content of the view.
    pub fn set_content<S: Into<String>>(&mut self, content: S) {
        self.content = content.into();
        if let Some(size) = self.last_size.map(|s| s.map(|s| s.value)) {
            self.compute_rows(size);
        }
    }

    /// Sets the content of the view.
    ///
    /// Chainable variant.
    pub fn content<S: Into<String>>(self, content: S) -> Self {
        self.with(|s| s.set_content(content))
    }

    /// Finds the row containing the grapheme at the given offset
    fn row_at(&self, offset: usize) -> usize {
        // println_stderr!("Offset: {}", offset);
        self.rows
            .iter()
            .enumerate()
            .take_while(|&(_, row)| row.start <= offset)
            .map(|(i, _)| i)
            .last()
            .unwrap()
    }

    fn col_at(&self, offset: usize) -> usize {
        let row_id = self.row_at(offset);
        let row = self.rows[row_id];
        // Number of cells to the left of the cursor
        self.content[row.start..offset].width()
    }

    /// Finds the row containing the cursor
    fn selected_row(&self) -> usize {
        self.row_at(self.cursor)
    }

    fn page_up(&mut self) {
        for _ in 0..5 {
            self.move_up();
        }
    }

    fn page_down(&mut self) {
        for _ in 0..5 {
            self.move_down();
        }
    }

    fn move_up(&mut self) {
        let row_id = self.selected_row();
        if row_id == 0 {
            return;
        }

        // Number of cells to the left of the cursor
        let x = self.col_at(self.cursor);

        let prev_row = self.rows[row_id - 1];
        let prev_text = &self.content[prev_row.start..prev_row.end];
        let offset = prefix_length(prev_text.graphemes(true), x, "");
        self.cursor = prev_row.start + offset;
    }

    fn move_down(&mut self) {
        let row_id = self.selected_row();
        if row_id + 1 == self.rows.len() {
            return;
        }
        let x = self.col_at(self.cursor);

        let next_row = self.rows[row_id + 1];
        let next_text = &self.content[next_row.start..next_row.end];
        let offset = prefix_length(next_text.graphemes(true), x, "");
        self.cursor = next_row.start + offset;
    }

    /// Moves the cursor to the left.
    ///
    /// Wraps the previous line if required.
    fn move_left(&mut self) {
        let len = {
            // We don't want to utf8-parse the entire content.
            // So restrict to the last row.
            let mut row = self.selected_row();
            if self.rows[row].start == self.cursor {
                row -= 1;
            }

            let text = &self.content[self.rows[row].start..self.cursor];
            text.graphemes(true)
                .last()
                .unwrap()
                .len()
        };
        self.cursor -= len;
    }

    /// Moves the cursor to the right.
    ///
    /// Jumps to the next line is required.
    fn move_right(&mut self) {
        let len = self.content[self.cursor..]
            .graphemes(true)
            .next()
            .unwrap()
            .len();
        self.cursor += len;
    }

    fn is_cache_valid(&self, size: Vec2) -> bool {
        match self.last_size {
            None => false,
            Some(ref last) => last.x.accept(size.x) && last.y.accept(size.y),
        }
    }

    fn fix_ghost_row(&mut self) {
        if self.rows.is_empty() ||
           self.rows.last().unwrap().end != self.content.len() {
            // Add a fake, empty row at the end.
            self.rows.push(Row {
                start: self.content.len(),
                end: self.content.len(),
                width: 0,
            });
        }
    }

    fn compute_rows(&mut self, size: Vec2) {
        if self.is_cache_valid(size) {
            return;
        }
        // println_stderr!("Computing! Oh yeah!");

        let mut available = size.x;
        self.rows = make_rows(&self.content, available);
        self.fix_ghost_row();
        if self.rows.len() > size.y {
            available -= 1;
            // Doh :(
            self.rows = make_rows(&self.content, available);
            self.fix_ghost_row();
        }

        if !self.rows.is_empty() {
            self.last_size = Some(SizeCache::build(size, size));
        }
    }

    fn backspace(&mut self) {
        if self.cursor != 0 {
            self.move_left();
            self.delete();
        }
    }

    fn delete(&mut self) {
        if self.cursor == self.content.len() {
            return;
        }
        // println_stderr!("Rows: {:?}", self.rows);
        let len = self.content[self.cursor..]
            .graphemes(true)
            .next()
            .unwrap()
            .len();
        let start = self.cursor;
        let end = self.cursor + len;
        // println_stderr!("Start/end: {}/{}", start, end);
        // println_stderr!("Content: `{}`", self.content);
        for _ in self.content.drain(start..end) {}
        // println_stderr!("Content: `{}`", self.content);

        let selected_row = self.selected_row();
        // println_stderr!("Selected row: {}", selected_row);
        if self.cursor == self.rows[selected_row].end {
            // We're removing an (implicit) newline.
            // This means merging two rows.
            let new_end = self.rows[selected_row + 1].end;
            self.rows[selected_row].end = new_end;
            self.rows.remove(selected_row + 1);
        }
        self.rows[selected_row].end -= len;

        // update all the rows downstream
        for row in &mut self.rows.iter_mut().skip(1 + selected_row) {
            row.rev_shift(len);
        }
        // println_stderr!("Rows: {:?}", self.rows);

        self.fix_damages();
        // println_stderr!("Rows: {:?}", self.rows);
    }

    fn insert(&mut self, ch: char) {

        // First, we inject the data, but keep the cursor unmoved
        // (So the cursor is to the left of the injected char)
        self.content.insert(self.cursor, ch);

        // Then, we shift the indexes of every row after this one.
        let shift = ch.len_utf8();

        // The current row grows, every other is just shifted.
        let selected_row = self.selected_row();
        self.rows[selected_row].end += shift;

        for row in &mut self.rows.iter_mut().skip(1 + selected_row) {
            row.shift(shift);
        }
        self.cursor += shift;

        // Finally, rows may not have the correct width anymore, so fix them.
        self.fix_damages();
    }

    /// Fix a damage located at the cursor.
    ///
    /// The only damages are assumed to have occured around the cursor.
    fn fix_damages(&mut self) {
        if self.last_size.is_none() {
            // If we don't know our size, it means we'll get a layout command soon.
            // So no need to do that here.
            return;
        }

        let size = self.last_size.unwrap().map(|s| s.value);

        // Find affected text.
        // We know the damage started at this row, so it'll need to go.
        let mut first_row = self.selected_row();
        // Actually, if possible, also re-compute the previous row.
        // Indeed, the previous row may have been cut short, and if we now
        // break apart a big word, maybe the first half can go up one level.
        if first_row > 0 {
            first_row -= 1;
        }
        // The
        let first_byte = self.rows[first_row].start;

        // We don't need to go beyond a newline.
        // If we don't find one, end of the text it is.
        // println_stderr!("Cursor: {}", self.cursor);
        let last_byte = self.content[self.cursor..]
            .find('\n')
            .map(|i| 1 + i + self.cursor);
        let last_row = last_byte.map_or(self.rows.len(), |last_byte| self.row_at(last_byte));
        let last_byte = last_byte.unwrap_or(self.content.len());

        // println_stderr!("Content: `{}` (len={})",
        //                 self.content,
        //                 self.content.len());
        // println_stderr!("start/end: {}/{}", first_byte, last_byte);
        // println_stderr!("start/end rows: {}/{}", first_row, last_row);

        // Do we have access to the entire width?...
        let mut available = size.x;

        let scrollable = self.rows.len() > size.y;
        if scrollable {
            // ... not if a scrollbar is there
            available -= 1;
        }

        // First attempt, if scrollbase status didn't change.
        // println_stderr!("Rows: {:?}", self.rows);
        let new_rows = make_rows(&self.content[first_byte..last_byte],
                                     available);
        // How much did this add?
        // println_stderr!("New rows: {:?}", new_rows);
        // println_stderr!("{}-{}", first_row, last_row);
        let new_row_count = self.rows.len() + new_rows.len() + first_row -
                            last_row;
        if !scrollable && new_row_count > size.y {
            // We just changed scrollable status.
            // This changes everything.
            // TODO: compute_rows() currently makes a scroll-less attempt.
            // Here, we know it's just no gonna happen.
            self.invalidate();
            self.compute_rows(size);
            self.scrollbase.set_heights(size.y, self.rows.len());
            return;
        }

        // Otherwise, replace stuff.
        let affected_rows = first_row..last_row;
        let replacement_rows = new_rows.into_iter()
            .map(|row| row.shifted(first_byte));
        self.rows.splice(affected_rows, replacement_rows);
        self.fix_ghost_row();
        self.scrollbase.set_heights(size.y, self.rows.len());
    }
}

impl View for TextArea {
    fn draw(&self, printer: &Printer) {
        printer.with_color(ColorStyle::Secondary, |printer| {
            let effect = if self.enabled {
                Effect::Reverse
            } else {
                Effect::Simple
            };

            let w = if self.scrollbase.scrollable() {
                printer.size.x - 1
            } else {
                printer.size.x
            };
            printer.with_effect(effect, |printer| {
                for y in 0..printer.size.y {
                    printer.print_hline((0, y), w, " ");
                }
            });

            // println_stderr!("Content: `{}`", &self.content);
            self.scrollbase.draw(printer, |printer, i| {
                // println_stderr!("Drawing row {}", i);
                let row = &self.rows[i];
                // println_stderr!("row: {:?}", row);
                let text = &self.content[row.start..row.end];
                // println_stderr!("row text: `{}`", text);
                printer.with_effect(effect, |printer| {
                    printer.print((0, 0), text);
                });

                if printer.focused && i == self.selected_row() {
                    let cursor_offset = self.cursor - row.start;
                    let c = if cursor_offset == text.len() {
                        "_"
                    } else {
                        text[cursor_offset..]
                            .graphemes(true)
                            .next()
                            .expect("Found no char!")
                    };
                    let offset = text[..cursor_offset].width();
                    printer.print((offset, 0), c);
                }

            });
        });
    }

    fn on_event(&mut self, event: Event) -> EventResult {
        match event {
            Event::Char(ch) => self.insert(ch),
            Event::Key(Key::Enter) => self.insert('\n'),
            Event::Key(Key::Backspace) if self.cursor > 0 => self.backspace(),
            Event::Key(Key::Del) if self.cursor < self.content.len() => {
                self.delete()
            }

            Event::Key(Key::End) => {
                let row = self.selected_row();
                self.cursor = self.rows[row].end;
                if row + 1 < self.rows.len() &&
                   self.cursor == self.rows[row + 1].start {
                    self.move_left();
                }
            }
            Event::Ctrl(Key::Home) => self.cursor = 0,
            Event::Ctrl(Key::End) => self.cursor = self.content.len(),
            Event::Key(Key::Home) => {
                self.cursor = self.rows[self.selected_row()].start
            }
            Event::Key(Key::Up) if self.selected_row() > 0 => self.move_up(),
            Event::Key(Key::Down) if self.selected_row() + 1 <
                                     self.rows.len() => self.move_down(),
            Event::Key(Key::PageUp) => self.page_up(),
            Event::Key(Key::PageDown) => self.page_down(),
            Event::Key(Key::Left) if self.cursor > 0 => self.move_left(),
            Event::Key(Key::Right) if self.cursor < self.content.len() => {
                self.move_right()
            }
            _ => return EventResult::Ignored,
        }

        // println_stderr!("Rows: {:?}", self.rows);
        let focus = self.selected_row();
        self.scrollbase.scroll_to(focus);

        EventResult::Consumed(None)
    }

    fn take_focus(&mut self, _: Direction) -> bool {
        self.enabled
    }

    fn layout(&mut self, size: Vec2) {
        self.compute_rows(size);
        self.scrollbase.set_heights(size.y, self.rows.len());
    }
}
<commit_msg>TextArea: starts with no rows.<commit_after>use unicode_segmentation::UnicodeSegmentation;
use unicode_width::UnicodeWidthStr;
use odds::vec::VecExt;

use {Printer, With, XY};
use direction::Direction;
use vec::Vec2;
use event::{Event, EventResult, Key};
use utils::{LinesIterator, Row, prefix_length};
use view::{ScrollBase, SizeCache, View};
use theme::{ColorStyle, Effect};

/// Multi-lines text editor.
///
/// A `TextArea` by itself doesn't have a well-defined size.
/// You should wrap it in a `BoxView` to control its size.
pub struct TextArea {
    // TODO: use a smarter data structure (rope?)
    content: String,
    /// Byte offsets within `content` representing text rows
    rows: Vec<Row>,

    /// When `false`, we don't take any input.
    enabled: bool,

    /// Base for scrolling features
    scrollbase: ScrollBase,

    /// Cache to avoid re-computing layout on no-op events
    last_size: Option<XY<SizeCache>>,

    /// Byte offset of the currently selected grapheme.
    cursor: usize,
}

fn make_rows(text: &str, width: usize) -> Vec<Row> {
    LinesIterator::new(text, width)
        .show_spaces()
        .collect()
}

new_default!(TextArea);

impl TextArea {
    /// Creates a new, empty TextArea.
    pub fn new() -> Self {
        TextArea {
            content: String::new(),
            rows: Vec::new(),
            enabled: true,
            scrollbase: ScrollBase::new().right_padding(0),
            last_size: None,
            cursor: 0,
        }
    }

    /// Retrieves the content of the view.
    pub fn get_content(&self) -> &str {
        &self.content
    }

    fn invalidate(&mut self) {
        self.last_size = None;
    }

    /// Sets the content of the view.
    pub fn set_content<S: Into<String>>(&mut self, content: S) {
        self.content = content.into();
        if let Some(size) = self.last_size.map(|s| s.map(|s| s.value)) {
            self.compute_rows(size);
        }
    }

    /// Sets the content of the view.
    ///
    /// Chainable variant.
    pub fn content<S: Into<String>>(self, content: S) -> Self {
        self.with(|s| s.set_content(content))
    }

    /// Finds the row containing the grapheme at the given offset
    fn row_at(&self, offset: usize) -> usize {
        // println_stderr!("Offset: {}", offset);
        self.rows
            .iter()
            .enumerate()
            .take_while(|&(_, row)| row.start <= offset)
            .map(|(i, _)| i)
            .last()
            .unwrap()
    }

    fn col_at(&self, offset: usize) -> usize {
        let row_id = self.row_at(offset);
        let row = self.rows[row_id];
        // Number of cells to the left of the cursor
        self.content[row.start..offset].width()
    }

    /// Finds the row containing the cursor
    fn selected_row(&self) -> usize {
        self.row_at(self.cursor)
    }

    fn page_up(&mut self) {
        for _ in 0..5 {
            self.move_up();
        }
    }

    fn page_down(&mut self) {
        for _ in 0..5 {
            self.move_down();
        }
    }

    fn move_up(&mut self) {
        let row_id = self.selected_row();
        if row_id == 0 {
            return;
        }

        // Number of cells to the left of the cursor
        let x = self.col_at(self.cursor);

        let prev_row = self.rows[row_id - 1];
        let prev_text = &self.content[prev_row.start..prev_row.end];
        let offset = prefix_length(prev_text.graphemes(true), x, "");
        self.cursor = prev_row.start + offset;
    }

    fn move_down(&mut self) {
        let row_id = self.selected_row();
        if row_id + 1 == self.rows.len() {
            return;
        }
        let x = self.col_at(self.cursor);

        let next_row = self.rows[row_id + 1];
        let next_text = &self.content[next_row.start..next_row.end];
        let offset = prefix_length(next_text.graphemes(true), x, "");
        self.cursor = next_row.start + offset;
    }

    /// Moves the cursor to the left.
    ///
    /// Wraps the previous line if required.
    fn move_left(&mut self) {
        let len = {
            // We don't want to utf8-parse the entire content.
            // So restrict to the last row.
            let mut row = self.selected_row();
            if self.rows[row].start == self.cursor {
                row -= 1;
            }

            let text = &self.content[self.rows[row].start..self.cursor];
            text.graphemes(true)
                .last()
                .unwrap()
                .len()
        };
        self.cursor -= len;
    }

    /// Moves the cursor to the right.
    ///
    /// Jumps to the next line is required.
    fn move_right(&mut self) {
        let len = self.content[self.cursor..]
            .graphemes(true)
            .next()
            .unwrap()
            .len();
        self.cursor += len;
    }

    fn is_cache_valid(&self, size: Vec2) -> bool {
        match self.last_size {
            None => false,
            Some(ref last) => last.x.accept(size.x) && last.y.accept(size.y),
        }
    }

    fn fix_ghost_row(&mut self) {
        if self.rows.is_empty() ||
           self.rows.last().unwrap().end != self.content.len() {
            // Add a fake, empty row at the end.
            self.rows.push(Row {
                start: self.content.len(),
                end: self.content.len(),
                width: 0,
            });
        }
    }

    fn compute_rows(&mut self, size: Vec2) {
        if self.is_cache_valid(size) {
            return;
        }
        // println_stderr!("Computing! Oh yeah!");

        let mut available = size.x;
        self.rows = make_rows(&self.content, available);
        self.fix_ghost_row();
        if self.rows.len() > size.y {
            available -= 1;
            // Doh :(
            self.rows = make_rows(&self.content, available);
            self.fix_ghost_row();
        }

        if !self.rows.is_empty() {
            self.last_size = Some(SizeCache::build(size, size));
        }
    }

    fn backspace(&mut self) {
        if self.cursor != 0 {
            self.move_left();
            self.delete();
        }
    }

    fn delete(&mut self) {
        if self.cursor == self.content.len() {
            return;
        }
        // println_stderr!("Rows: {:?}", self.rows);
        let len = self.content[self.cursor..]
            .graphemes(true)
            .next()
            .unwrap()
            .len();
        let start = self.cursor;
        let end = self.cursor + len;
        // println_stderr!("Start/end: {}/{}", start, end);
        // println_stderr!("Content: `{}`", self.content);
        for _ in self.content.drain(start..end) {}
        // println_stderr!("Content: `{}`", self.content);

        let selected_row = self.selected_row();
        // println_stderr!("Selected row: {}", selected_row);
        if self.cursor == self.rows[selected_row].end {
            // We're removing an (implicit) newline.
            // This means merging two rows.
            let new_end = self.rows[selected_row + 1].end;
            self.rows[selected_row].end = new_end;
            self.rows.remove(selected_row + 1);
        }
        self.rows[selected_row].end -= len;

        // update all the rows downstream
        for row in &mut self.rows.iter_mut().skip(1 + selected_row) {
            row.rev_shift(len);
        }
        // println_stderr!("Rows: {:?}", self.rows);

        self.fix_damages();
        // println_stderr!("Rows: {:?}", self.rows);
    }

    fn insert(&mut self, ch: char) {

        // First, we inject the data, but keep the cursor unmoved
        // (So the cursor is to the left of the injected char)
        self.content.insert(self.cursor, ch);

        // Then, we shift the indexes of every row after this one.
        let shift = ch.len_utf8();

        // The current row grows, every other is just shifted.
        let selected_row = self.selected_row();
        self.rows[selected_row].end += shift;

        for row in &mut self.rows.iter_mut().skip(1 + selected_row) {
            row.shift(shift);
        }
        self.cursor += shift;

        // Finally, rows may not have the correct width anymore, so fix them.
        self.fix_damages();
    }

    /// Fix a damage located at the cursor.
    ///
    /// The only damages are assumed to have occured around the cursor.
    fn fix_damages(&mut self) {
        if self.last_size.is_none() {
            // If we don't know our size, it means we'll get a layout command soon.
            // So no need to do that here.
            return;
        }

        let size = self.last_size.unwrap().map(|s| s.value);

        // Find affected text.
        // We know the damage started at this row, so it'll need to go.
        let mut first_row = self.selected_row();
        // Actually, if possible, also re-compute the previous row.
        // Indeed, the previous row may have been cut short, and if we now
        // break apart a big word, maybe the first half can go up one level.
        if first_row > 0 {
            first_row -= 1;
        }
        // The
        let first_byte = self.rows[first_row].start;

        // We don't need to go beyond a newline.
        // If we don't find one, end of the text it is.
        // println_stderr!("Cursor: {}", self.cursor);
        let last_byte = self.content[self.cursor..]
            .find('\n')
            .map(|i| 1 + i + self.cursor);
        let last_row = last_byte.map_or(self.rows.len(), |last_byte| self.row_at(last_byte));
        let last_byte = last_byte.unwrap_or(self.content.len());

        // println_stderr!("Content: `{}` (len={})",
        //                 self.content,
        //                 self.content.len());
        // println_stderr!("start/end: {}/{}", first_byte, last_byte);
        // println_stderr!("start/end rows: {}/{}", first_row, last_row);

        // Do we have access to the entire width?...
        let mut available = size.x;

        let scrollable = self.rows.len() > size.y;
        if scrollable {
            // ... not if a scrollbar is there
            available -= 1;
        }

        // First attempt, if scrollbase status didn't change.
        // println_stderr!("Rows: {:?}", self.rows);
        let new_rows = make_rows(&self.content[first_byte..last_byte],
                                     available);
        // How much did this add?
        // println_stderr!("New rows: {:?}", new_rows);
        // println_stderr!("{}-{}", first_row, last_row);
        let new_row_count = self.rows.len() + new_rows.len() + first_row -
                            last_row;
        if !scrollable && new_row_count > size.y {
            // We just changed scrollable status.
            // This changes everything.
            // TODO: compute_rows() currently makes a scroll-less attempt.
            // Here, we know it's just no gonna happen.
            self.invalidate();
            self.compute_rows(size);
            self.scrollbase.set_heights(size.y, self.rows.len());
            return;
        }

        // Otherwise, replace stuff.
        let affected_rows = first_row..last_row;
        let replacement_rows = new_rows.into_iter()
            .map(|row| row.shifted(first_byte));
        self.rows.splice(affected_rows, replacement_rows);
        self.fix_ghost_row();
        self.scrollbase.set_heights(size.y, self.rows.len());
    }
}

impl View for TextArea {
    fn draw(&self, printer: &Printer) {
        printer.with_color(ColorStyle::Secondary, |printer| {
            let effect = if self.enabled {
                Effect::Reverse
            } else {
                Effect::Simple
            };

            let w = if self.scrollbase.scrollable() {
                printer.size.x - 1
            } else {
                printer.size.x
            };
            printer.with_effect(effect, |printer| {
                for y in 0..printer.size.y {
                    printer.print_hline((0, y), w, " ");
                }
            });

            // println_stderr!("Content: `{}`", &self.content);
            self.scrollbase.draw(printer, |printer, i| {
                // println_stderr!("Drawing row {}", i);
                let row = &self.rows[i];
                // println_stderr!("row: {:?}", row);
                let text = &self.content[row.start..row.end];
                // println_stderr!("row text: `{}`", text);
                printer.with_effect(effect, |printer| {
                    printer.print((0, 0), text);
                });

                if printer.focused && i == self.selected_row() {
                    let cursor_offset = self.cursor - row.start;
                    let c = if cursor_offset == text.len() {
                        "_"
                    } else {
                        text[cursor_offset..]
                            .graphemes(true)
                            .next()
                            .expect("Found no char!")
                    };
                    let offset = text[..cursor_offset].width();
                    printer.print((offset, 0), c);
                }

            });
        });
    }

    fn on_event(&mut self, event: Event) -> EventResult {
        match event {
            Event::Char(ch) => self.insert(ch),
            Event::Key(Key::Enter) => self.insert('\n'),
            Event::Key(Key::Backspace) if self.cursor > 0 => self.backspace(),
            Event::Key(Key::Del) if self.cursor < self.content.len() => {
                self.delete()
            }

            Event::Key(Key::End) => {
                let row = self.selected_row();
                self.cursor = self.rows[row].end;
                if row + 1 < self.rows.len() &&
                   self.cursor == self.rows[row + 1].start {
                    self.move_left();
                }
            }
            Event::Ctrl(Key::Home) => self.cursor = 0,
            Event::Ctrl(Key::End) => self.cursor = self.content.len(),
            Event::Key(Key::Home) => {
                self.cursor = self.rows[self.selected_row()].start
            }
            Event::Key(Key::Up) if self.selected_row() > 0 => self.move_up(),
            Event::Key(Key::Down) if self.selected_row() + 1 <
                                     self.rows.len() => self.move_down(),
            Event::Key(Key::PageUp) => self.page_up(),
            Event::Key(Key::PageDown) => self.page_down(),
            Event::Key(Key::Left) if self.cursor > 0 => self.move_left(),
            Event::Key(Key::Right) if self.cursor < self.content.len() => {
                self.move_right()
            }
            _ => return EventResult::Ignored,
        }

        // println_stderr!("Rows: {:?}", self.rows);
        let focus = self.selected_row();
        self.scrollbase.scroll_to(focus);

        EventResult::Consumed(None)
    }

    fn take_focus(&mut self, _: Direction) -> bool {
        self.enabled
    }

    fn layout(&mut self, size: Vec2) {
        self.compute_rows(size);
        self.scrollbase.set_heights(size.y, self.rows.len());
    }
}
<|endoftext|>


<commit_before>use opengles;   // FIXME: Should only be for tests.
import glut::{check_loop, create_window, destroy_window, init, init_display_mode, swap_buffers};
import opengles::gl2::{ARRAY_BUFFER, COLOR_BUFFER_BIT, COMPILE_STATUS};
import opengles::gl2::{FRAGMENT_SHADER, LINK_STATUS, NO_ERROR, STATIC_DRAW};
import opengles::gl2::{TRIANGLE_STRIP, VERTEX_SHADER, GLclampf, GLenum};
import opengles::gl2::{GLsizei, GLuint, attach_shader, bind_buffer};
import opengles::gl2::{buffer_data, create_program, clear, clear_color};
import opengles::gl2::{compile_shader, create_shader, draw_arrays};
import opengles::gl2::{enable_vertex_attrib_array, gen_buffers};
import opengles::gl2::{get_attrib_location, get_error, get_program_iv};
import opengles::gl2::{get_shader_info_log, get_shader_iv};
import opengles::gl2::{get_uniform_location, link_program, shader_source};
import opengles::gl2::{use_program, vertex_attrib_pointer_f32};

import comm::{Chan, peek, Port, recv, send};
import io::println;
import ptr::{addr_of, null};
import str::to_bytes;
import task::TaskBuilder;
import vec::unsafe::to_ptr;

fn fragment_shader_source() -> ~str {
    ~"
    #ifdef GLES2
        precision mediump float;
    #endif

        void main(void) {
            gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
        }
    "
}

fn vertex_shader_source() -> ~str {
    ~"
        attribute vec3 aVertexPosition;

        /*uniform mat4 uMVMatrix;
        uniform mat4 uPMatrix;*/

        void main(void) {
            gl_Position = /*uPMatrix * uMVMatrix **/
                vec4(aVertexPosition, 1.0);
        }
    "
}

fn load_shader(source_str: ~str, shader_type: GLenum) -> GLuint {
    let shader_id = create_shader(shader_type);
    shader_source(shader_id, ~[to_bytes(source_str)]);
    compile_shader(shader_id);

    if get_error() != NO_ERROR {
        println(#fmt("error: %d", get_error() as int));
        fail ~"failed to compile shader with error";
    }

    if get_shader_iv(shader_id, COMPILE_STATUS) == (0 as GLint) {
        println(get_shader_info_log(shader_id));
        fail ~"failed to compile shader";
    }
    return shader_id;
}

struct shader_program {
    let program: GLuint;
    let aVertexPosition: c_int;
    /*let uPMatrix: c_int;
    let uMVMatrix: c_int;*/

    new(program: GLuint) {
        self.program = program;
        self.aVertexPosition = get_attrib_location(program, ~"aVertexPosition");
        /*self.uPMatrix = get_uniform_location(program, "uPMatrix");
        self.uMVMatrix = get_uniform_location(program, "uMVMatrix");*/

        enable_vertex_attrib_array(self.aVertexPosition as GLuint);
    }
}

fn init_shaders() -> shader_program {
    let vertex_shader = load_shader(vertex_shader_source(), VERTEX_SHADER);
    let fragment_shader = load_shader(fragment_shader_source(),
                                      FRAGMENT_SHADER);

    let program = create_program();
    attach_shader(program, vertex_shader);
    attach_shader(program, fragment_shader);
    link_program(program);

    if get_program_iv(program, LINK_STATUS) == (0 as GLint) {
        fail ~"failed to initialize program";
    }

    use_program(program);

    return shader_program(program);
}

fn init_buffers() -> GLuint {
    let triangle_vertex_buffer = gen_buffers(1 as GLsizei)[0];
    bind_buffer(ARRAY_BUFFER, triangle_vertex_buffer);
    let vertices = ~[
        0.0f32, 1.0f32, 0.0f32,
        1.0f32, 0.0f32, 0.0f32,
        0.0f32, 0.0f32, 0.0f32
    ];
    buffer_data(ARRAY_BUFFER, vertices, STATIC_DRAW);
    return triangle_vertex_buffer;
}

fn draw_scene(shader_program: shader_program, vertex_buffer: GLuint) {
    clear_color(0.0f32, 0.0f32, 1.0f32, 1.0f32);
    clear(COLOR_BUFFER_BIT);

    bind_buffer(ARRAY_BUFFER, vertex_buffer);
    vertex_attrib_pointer_f32(shader_program.aVertexPosition as GLuint,
                              3 as GLint, false, 0 as GLsizei, 0 as GLuint);
    draw_arrays(TRIANGLE_STRIP, 0 as GLint, 3 as GLint);
}

fn display_callback() {
    let program = init_shaders();
    let vertex_buffer = init_buffers();
    draw_scene(program, vertex_buffer);

    swap_buffers();
}

#[test]
fn test_triangle_and_square() unsafe {
    let builder = task::task().sched_mode(task::PlatformThread);

    let po: Port<()> = Port();
    let ch = Chan(po);
    let _result_ch: Chan<()> = builder.spawn_listener(|_port| {
        init();
        init_display_mode(0 as c_uint);
        let window = create_window(~"Rust GLUT");
        display_func(display_callback);

        let wakeup = Port();
        let wakeup_chan = Chan(wakeup);
        timer_func(1000, || send(wakeup_chan, ()));

        loop {
            check_loop();

            if peek(wakeup) {
                recv(wakeup);
                send(ch, ());
                destroy_window(window);
                break;
            }
        }
    });

    recv(po);
}

<commit_msg>Fix build break<commit_after>use opengles;   // FIXME: Should only be for tests.
import glut::{check_loop, create_window, destroy_window, init, init_display_mode, swap_buffers};
import opengles::gl2::{ARRAY_BUFFER, COLOR_BUFFER_BIT, COMPILE_STATUS};
import opengles::gl2::{FRAGMENT_SHADER, LINK_STATUS, NO_ERROR, STATIC_DRAW};
import opengles::gl2::{TRIANGLE_STRIP, VERTEX_SHADER, GLclampf, GLenum};
import opengles::gl2::{GLsizei, GLuint, attach_shader, bind_buffer};
import opengles::gl2::{buffer_data, create_program, clear, clear_color};
import opengles::gl2::{compile_shader, create_shader, draw_arrays};
import opengles::gl2::{enable_vertex_attrib_array, gen_buffers};
import opengles::gl2::{get_attrib_location, get_error, get_program_iv};
import opengles::gl2::{get_shader_info_log, get_shader_iv};
import opengles::gl2::{get_uniform_location, link_program, shader_source};
import opengles::gl2::{use_program, vertex_attrib_pointer_f32};

import comm::{Chan, peek, Port, recv, send};
import io::println;
import ptr::{addr_of, null};
import str::to_bytes;
import task::TaskBuilder;
import vec::unsafe::to_ptr;

fn fragment_shader_source() -> ~str {
    ~"
    #ifdef GLES2
        precision mediump float;
    #endif

        void main(void) {
            gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
        }
    "
}

fn vertex_shader_source() -> ~str {
    ~"
        attribute vec3 aVertexPosition;

        /*uniform mat4 uMVMatrix;
        uniform mat4 uPMatrix;*/

        void main(void) {
            gl_Position = /*uPMatrix * uMVMatrix **/
                vec4(aVertexPosition, 1.0);
        }
    "
}

fn load_shader(source_str: ~str, shader_type: GLenum) -> GLuint {
    let shader_id = create_shader(shader_type);
    shader_source(shader_id, ~[to_bytes(source_str)]);
    compile_shader(shader_id);

    if get_error() != NO_ERROR {
        println(#fmt("error: %d", get_error() as int));
        fail ~"failed to compile shader with error";
    }

    if get_shader_iv(shader_id, COMPILE_STATUS) == (0 as GLint) {
        println(get_shader_info_log(shader_id));
        fail ~"failed to compile shader";
    }
    return shader_id;
}

struct ShaderProgram {
    program: GLuint,
    aVertexPosition: c_int,
    /*let uPMatrix: c_int;
    let uMVMatrix: c_int;*/
}

fn ShaderProgram(program: GLuint) -> ShaderProgram {
    let p = ShaderProgram {
        program : program,
        aVertexPosition : get_attrib_location(program, ~"aVertexPosition"),
        /*self.uPMatrix : get_uniform_location(program, "uPMatrix"),
        self.uMVMatrix : get_uniform_location(program, "uMVMatrix")*/
    };
    enable_vertex_attrib_array(p.aVertexPosition as GLuint);
}

fn init_shaders() -> ShaderProgram {
    let vertex_shader = load_shader(vertex_shader_source(), VERTEX_SHADER);
    let fragment_shader = load_shader(fragment_shader_source(),
                                      FRAGMENT_SHADER);

    let program = create_program();
    attach_shader(program, vertex_shader);
    attach_shader(program, fragment_shader);
    link_program(program);

    if get_program_iv(program, LINK_STATUS) == (0 as GLint) {
        fail ~"failed to initialize program";
    }

    use_program(program);

    return ShaderProgram(program);
}

fn init_buffers() -> GLuint {
    let triangle_vertex_buffer = gen_buffers(1 as GLsizei)[0];
    bind_buffer(ARRAY_BUFFER, triangle_vertex_buffer);
    let vertices = ~[
        0.0f32, 1.0f32, 0.0f32,
        1.0f32, 0.0f32, 0.0f32,
        0.0f32, 0.0f32, 0.0f32
    ];
    buffer_data(ARRAY_BUFFER, vertices, STATIC_DRAW);
    return triangle_vertex_buffer;
}

fn draw_scene(shader_program: ShaderProgram, vertex_buffer: GLuint) {
    clear_color(0.0f32, 0.0f32, 1.0f32, 1.0f32);
    clear(COLOR_BUFFER_BIT);

    bind_buffer(ARRAY_BUFFER, vertex_buffer);
    vertex_attrib_pointer_f32(ShaderProgram.aVertexPosition as GLuint,
                              3 as GLint, false, 0 as GLsizei, 0 as GLuint);
    draw_arrays(TRIANGLE_STRIP, 0 as GLint, 3 as GLint);
}

fn display_callback() {
    let program = init_shaders();
    let vertex_buffer = init_buffers();
    draw_scene(program, vertex_buffer);

    swap_buffers();
}

#[test]
fn test_triangle_and_square() unsafe {
    let builder = task::task().sched_mode(task::PlatformThread);

    let po: Port<()> = Port();
    let ch = Chan(po);
    let _result_ch: Chan<()> = builder.spawn_listener(|_port| {
        init();
        init_display_mode(0 as c_uint);
        let window = create_window(~"Rust GLUT");
        display_func(display_callback);

        let wakeup = Port();
        let wakeup_chan = Chan(wakeup);
        timer_func(1000, || send(wakeup_chan, ()));

        loop {
            check_loop();

            if peek(wakeup) {
                recv(wakeup);
                send(ch, ());
                destroy_window(window);
                break;
            }
        }
    });

    recv(po);
}

<|endoftext|>


<commit_before>use std::cell::UnsafeCell;

use {Id, ShareId, ToMessage};
use runtime::{Message, Object};

#[allow(improper_ctypes)]
#[link(name = "Foundation", kind = "framework")]
extern {
	fn objc_storeWeak(location: *mut *mut Object, obj: *mut Object) -> *mut Object;
	fn objc_loadWeakRetained(location: *mut *mut Object) -> *mut Object;
	fn objc_destroyWeak(addr: *mut *mut Object);
}

pub struct WeakId<T> {
	// Our pointer must have the same address even if we are moved, so Box it.
	// Although loading the WeakId may modify the pointer, it is thread safe,
	// so we must use an UnsafeCell to get a *mut without self being mutable.
	ptr: Box<UnsafeCell<*const T>>,
}

impl<T: Message> WeakId<T> {
	pub fn new(obj: &ShareId<T>) -> WeakId<T> {
		let ptr = box UnsafeCell::new(RawPtr::null());
		unsafe {
			let loc = ptr.get() as *mut *mut Object;
			objc_storeWeak(loc, obj.as_ptr());
		}
		WeakId { ptr: ptr }
	}

	pub fn load(&self) -> Option<ShareId<T>> {
		unsafe {
			let loc = self.ptr.get() as *mut *mut Object;
			let obj = objc_loadWeakRetained(loc);
			Id::maybe_from_retained_ptr(obj as *mut T)
		}
	}
}

#[unsafe_destructor]
impl<T> Drop for WeakId<T> {
	fn drop(&mut self) {
		unsafe {
			let loc = self.ptr.get() as *mut *mut Object;
			objc_destroyWeak(loc);
		}
	}
}

#[cfg(test)]
mod tests {
	use {Id};
	use foundation::{INSObject, NSObject};
	use super::WeakId;

	#[test]
	fn test_weak() {
		let obj: Id<NSObject> = INSObject::new();
		let obj = obj.share();

		let weak = WeakId::new(&obj);
		let strong = weak.load().unwrap();
		assert!(strong == obj);
		drop(strong);

		drop(obj);
		assert!(weak.load().is_none());
	}
}
<commit_msg>Don't use foundation in weak tests.<commit_after>use std::cell::UnsafeCell;

use {Id, ShareId, ToMessage};
use runtime::{Message, Object};

#[allow(improper_ctypes)]
#[link(name = "Foundation", kind = "framework")]
extern {
	fn objc_storeWeak(location: *mut *mut Object, obj: *mut Object) -> *mut Object;
	fn objc_loadWeakRetained(location: *mut *mut Object) -> *mut Object;
	fn objc_destroyWeak(addr: *mut *mut Object);
}

pub struct WeakId<T> {
	// Our pointer must have the same address even if we are moved, so Box it.
	// Although loading the WeakId may modify the pointer, it is thread safe,
	// so we must use an UnsafeCell to get a *mut without self being mutable.
	ptr: Box<UnsafeCell<*const T>>,
}

impl<T: Message> WeakId<T> {
	pub fn new(obj: &ShareId<T>) -> WeakId<T> {
		let ptr = box UnsafeCell::new(RawPtr::null());
		unsafe {
			let loc = ptr.get() as *mut *mut Object;
			objc_storeWeak(loc, obj.as_ptr());
		}
		WeakId { ptr: ptr }
	}

	pub fn load(&self) -> Option<ShareId<T>> {
		unsafe {
			let loc = self.ptr.get() as *mut *mut Object;
			let obj = objc_loadWeakRetained(loc);
			Id::maybe_from_retained_ptr(obj as *mut T)
		}
	}
}

#[unsafe_destructor]
impl<T> Drop for WeakId<T> {
	fn drop(&mut self) {
		unsafe {
			let loc = self.ptr.get() as *mut *mut Object;
			objc_destroyWeak(loc);
		}
	}
}

#[cfg(test)]
mod tests {
	use {Id};
	use runtime::{Class, Object};
	use super::WeakId;

	#[test]
	fn test_weak() {
		let cls = Class::get("NSObject").unwrap();
		let obj = unsafe {
			let obj = msg_send![cls alloc];
			let obj = msg_send![obj init];
			Id::from_retained_ptr(obj)
		};
		let obj = obj.share();

		let weak = WeakId::new(&obj);
		let strong = weak.load().unwrap();
		assert!(&*strong as *const Object == &*obj as *const Object);
		drop(strong);

		drop(obj);
		assert!(weak.load().is_none());
	}
}
<|endoftext|>


<commit_before><commit_msg>Do not try to rebuild the assembly files if not needed<commit_after><|endoftext|>


<commit_before><commit_msg>[build] Set proper build flags<commit_after><|endoftext|>


<commit_before>//! The reference loader implementation for the `gltf` crate.
//!
//! # Examples
//!
//! ### Importing some `glTF` 2.0
//!
//! ```rust
//! use gltf_importer::import;
//! # #[allow(unused_variables)]
//! let path = "path/to/asset.gltf";
//! # let path = "../examples/Box.gltf";
//! match import(path) {
//!     Ok((gltf, _)) => println!("{:#?}", gltf.as_json()),
//!     Err(err) => println!("error: {:?}", err),
//! }
//! ```

extern crate base64;
extern crate gltf;
extern crate gltf_utils;

use gltf::json::{self, validation};
use std::{fmt, fs, io, path};

use gltf::Gltf;
use gltf_utils::Source;
use std::error::Error as StdError;
use std::path::Path;

/// Contains parameters for import configuration.
pub mod config;

pub use self::config::Config;
pub use self::config::ValidationStrategy;

/// Error encountered when importing a glTF 2.0 asset.
#[derive(Debug)]
pub enum Error {
    /// A loaded glTF buffer is not of the required length.
    BufferLength(json::Path),

    /// Base 64 decoding error.
    Base64Decoding(base64::DecodeError),

    /// A glTF extension required by the asset has not been enabled by the user.
    ExtensionDisabled(String),

    /// A glTF extension required by the asset is not supported by the library.
    ExtensionUnsupported(String),

    /// File not found.
    FileNotFound(path::PathBuf),

    /// The glTF version of the asset is incompatible with the importer.
    IncompatibleVersion(String),

    /// Standard I/O error.
    Io(io::Error),

    /// `gltf` crate error.
    Gltf(gltf::Error),

    /// Failure when deserializing .gltf or .glb JSON.
    MalformedJson(json::Error),

    /// The .gltf data is invalid.
    Validation(Vec<(json::Path, validation::Error)>),
}

/// Buffer data returned from `import`.
#[derive(Clone, Debug)]
pub struct Buffers(Vec<Vec<u8>>);

impl Source for Buffers {
    fn source_buffer(&self, buffer: &gltf::Buffer) -> &[u8] {
        &self.0[buffer.index()]
    }
}

impl Buffers {
    /// Obtain the contents of a loaded buffer.
    pub fn buffer(&self, buffer: &gltf::Buffer) -> Option<&[u8]> {
        self.0.get(buffer.index()).map(Vec::as_slice)
    }

    /// Obtain the contents of a loaded buffer view.
    pub fn view(&self, view: &gltf::buffer::View) -> Option<&[u8]> {
        self.buffer(&view.buffer())
            .map(|data| {
                let begin = view.offset();
                let end = begin + view.length();
                &data[begin..end]
            })
    }

    /// Take the loaded buffer data.
    pub fn take(self) -> Vec<Vec<u8>> {
        self.0
    }
}

fn import_impl(path: &Path, config: &Config) -> Result<(Gltf, Buffers), Error> {
    let data = read_to_end(path)?;
    import_data_slice(&data, path, config)
}

/// Imports glTF 2.0 from a slice with custom configuration.
pub fn import_data_slice<'a, P>(data: &'a [u8], path: P, config: &Config) -> Result<(Gltf, Buffers), Error>
    where P: AsRef<Path>
{
    if data.starts_with(b"glTF") {
        import_binary(&data, config, path.as_ref())
    } else {
        import_standard(&data, config, path.as_ref())
    }
}

/// Imports glTF 2.0 with custom configuration.
pub fn import_with_config<P>(path: P, config: &Config) -> Result<(Gltf, Buffers), Error>
    where P: AsRef<Path>
{
    import_impl(path.as_ref(), config)
}

/// Imports glTF 2.0 with default configuration.
pub fn import<P>(path: P) -> Result<(Gltf, Buffers), Error>
    where P: AsRef<Path>
{
    import_impl(path.as_ref(), &Default::default())
}

fn read_to_end_impl(path: &Path) -> Result<Vec<u8>, Error> {
    use io::Read;
    if path.exists() {
        let file = fs::File::open(path)?;
        let mut reader = io::BufReader::new(file);
        let mut buffer = vec![];
        let _ = reader.read_to_end(&mut buffer)?;
        Ok(buffer)
    } else {
        Err(Error::FileNotFound(path.to_path_buf()))
    }
}

fn read_to_end<P: AsRef<Path>>(path: P) -> Result<Vec<u8>, Error> {
    read_to_end_impl(path.as_ref())
}

fn parse_data_uri(uri: &str) -> Result<Vec<u8>, Error> {
    let encoded = uri.split(',').nth(1).unwrap();
    let decoded = base64::decode(&encoded)?;
    Ok(decoded)
}

fn load_external_buffers(
    base_path: &Path,
    gltf: &Gltf,
    mut bin: Option<Vec<u8>>,
) -> Result<Vec<Vec<u8>>, Error> {
    let mut buffers = vec![];
    for (index, buffer) in gltf.buffers().enumerate() {
        let uri = buffer.uri();
        let data = if uri == "#bin" {
            Ok(bin.take().unwrap())
        } else if uri.starts_with("data:") {
            Ok(parse_data_uri(uri)?)
        } else {
            let path = base_path.parent().unwrap_or_else(|| Path::new("./")).join(uri);
            read_to_end(&path)
        }?;
        if data.len() < buffer.length() {
            let path = json::Path::new().field("buffers").index(index);
            return Err(Error::BufferLength(path));
        }
        buffers.push(data);
    }
    Ok(buffers)
}

fn validate_standard(
    unvalidated: gltf::Unvalidated,
    config: &Config,
) -> Result<Gltf, Error> {
    use config::ValidationStrategy;
    Ok(match config.validation_strategy {
        ValidationStrategy::Skip => unvalidated.skip_validation(),
        ValidationStrategy::Minimal => unvalidated.validate_minimally()?,
        ValidationStrategy::Complete => unvalidated.validate_completely()?,
    })
}

fn validate_binary(
    unvalidated: gltf::Unvalidated,
    config: &Config,
    has_bin: bool,
) -> Result<Gltf, Error> {
    use config::ValidationStrategy;
    use json::validation::Error as Reason;

    if config.validation_strategy == ValidationStrategy::Skip {
        return Ok(unvalidated.skip_validation());
    }

    let mut errs = vec![];
    {
        let json = unvalidated.as_json();
        for (index, buffer) in json.buffers.iter().enumerate() {
            let path = || {
                json::Path::new()
                    .field("buffers")
                    .index(index)
                    .field("uri")
            };
            match index {
                0 if has_bin => if buffer.uri.is_some() {
                    errs.push((path(), Reason::Missing));
                },
                _ if buffer.uri.is_none() => {
                    errs.push((path(), Reason::Missing));
                },
                _ => {},
            }
        }
    }

    if errs.is_empty() {
        Ok(match config.validation_strategy {
            ValidationStrategy::Minimal => unvalidated.validate_minimally()?,
            ValidationStrategy::Complete => unvalidated.validate_completely()?,
            ValidationStrategy::Skip => unreachable!(),
        })
    } else {
        Err(Error::Validation(errs))
    }
}

fn import_standard<'a>(
    data: &'a [u8],
    config: &Config,
    base_path: &Path,
) -> Result<(Gltf, Buffers), Error> {
    let unvalidated = Gltf::from_slice(data)?;
    let gltf = validate_standard(unvalidated, config)?;
    let bin = None;
    let mut buffers = Buffers(vec![]);
    for buffer in load_external_buffers(base_path, &gltf, bin)? {
        buffers.0.push(buffer);
    }
    Ok((gltf, buffers))
}

fn import_binary<'a>(
    data: &'a [u8],
    config: &Config,
    base_path: &Path,
) -> Result<(Gltf, Buffers), Error> {
    let gltf::Glb { json, bin, .. } = gltf::Glb::from_slice(data)?;
    let unvalidated = Gltf::from_slice(json)?;
    let bin = bin.map(|x| x.to_vec());
    let gltf = validate_binary(unvalidated, config, bin.is_some())?;
    let mut buffers = Buffers(vec![]);
    for buffer in load_external_buffers(base_path, &gltf, bin)? {
        buffers.0.push(buffer);
    }
    Ok((gltf, buffers))
}

impl From<json::Error> for Error {
    fn from(err: json::Error) -> Error {
        Error::MalformedJson(err)
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

impl From<Vec<(json::Path, validation::Error)>> for Error {
    fn from(errs: Vec<(json::Path, validation::Error)>) -> Error {
        Error::Validation(errs)
    }
}

impl From<gltf::Error> for Error {
    fn from(err: gltf::Error) -> Error {
        match err {
            gltf::Error::Validation(errs) => Error::Validation(errs),
            _ => Error::Gltf(err),
        }
    }
}

impl From<base64::DecodeError> for Error {
    fn from(err: base64::DecodeError) -> Error {
        Error::Base64Decoding(err)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use std::error::Error;
        write!(f, "{}", self.description())
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        use self::Error::*;
        match *self {
            Base64Decoding(_) => "base 64 decoding failed",
            BufferLength(_) => "buffer does not match required length",
            ExtensionDisabled(_) => "asset requires a disabled extension",
            ExtensionUnsupported(_) => "asset requires an unsupported extension",
            FileNotFound(_) => "file not found",
            IncompatibleVersion(_) => "asset is not glTF version 2.0",
            Io(_) => "io error",
            Gltf(_) => "error from gltf crate",
            MalformedJson(_) => "malformed .gltf / .glb JSON",
            Validation(_) => "asset failed validation tests",
        }
    }

    fn cause(&self) -> Option<&StdError> {
        use self::Error::*;
        match *self {
            MalformedJson(ref err) => Some(err),
            Io(ref err) => Some(err),
            _ => None,
        }
    }
}
<commit_msg>Fix gltf-importer<commit_after>//! The reference loader implementation for the `gltf` crate.
//!
//! # Examples
//!
//! ### Importing some `glTF` 2.0
//!
//! ```rust
//! use gltf_importer::import;
//! # #[allow(unused_variables)]
//! let path = "path/to/asset.gltf";
//! # let path = "../examples/Box.gltf";
//! match import(path) {
//!     Ok((gltf, _)) => println!("{:#?}", gltf.as_json()),
//!     Err(err) => println!("error: {:?}", err),
//! }
//! ```

extern crate base64;
extern crate gltf;
extern crate gltf_utils;

use gltf::json::{self, validation};
use std::{fmt, fs, io, path};

use gltf::Gltf;
use gltf_utils::Source;
use std::error::Error as StdError;
use std::path::Path;

/// Contains parameters for import configuration.
pub mod config;

pub use self::config::Config;
pub use self::config::ValidationStrategy;

/// Error encountered when importing a glTF 2.0 asset.
#[derive(Debug)]
pub enum Error {
    /// A loaded glTF buffer is not of the required length.
    BufferLength(json::Path),

    /// Base 64 decoding error.
    Base64Decoding(base64::DecodeError),

    /// A glTF extension required by the asset has not been enabled by the user.
    ExtensionDisabled(String),

    /// A glTF extension required by the asset is not supported by the library.
    ExtensionUnsupported(String),

    /// File not found.
    FileNotFound(path::PathBuf),

    /// The glTF version of the asset is incompatible with the importer.
    IncompatibleVersion(String),

    /// Standard I/O error.
    Io(io::Error),

    /// `gltf` crate error.
    Gltf(gltf::Error),

    /// Failure when deserializing .gltf or .glb JSON.
    MalformedJson(json::Error),

    /// The .gltf data is invalid.
    Validation(Vec<(json::Path, validation::Error)>),
}

/// Buffer data returned from `import`.
#[derive(Clone, Debug)]
pub struct Buffers(Vec<Vec<u8>>);

impl Source for Buffers {
    fn source_buffer(&self, buffer: &gltf::Buffer) -> &[u8] {
        &self.0[buffer.index()]
    }
}

impl Buffers {
    /// Obtain the contents of a loaded buffer.
    pub fn buffer(&self, buffer: &gltf::Buffer) -> Option<&[u8]> {
        self.0.get(buffer.index()).map(Vec::as_slice)
    }

    /// Obtain the contents of a loaded buffer view.
    pub fn view(&self, view: &gltf::buffer::View) -> Option<&[u8]> {
        self.buffer(&view.buffer())
            .map(|data| {
                let begin = view.offset();
                let end = begin + view.length();
                &data[begin..end]
            })
    }

    /// Take the loaded buffer data.
    pub fn take(self) -> Vec<Vec<u8>> {
        self.0
    }
}

fn import_impl(path: &Path, config: &Config) -> Result<(Gltf, Buffers), Error> {
    let data = read_to_end(path)?;
    import_data_slice(&data, path, config)
}

/// Imports glTF 2.0 from a slice with custom configuration.
pub fn import_data_slice<'a, P>(data: &'a [u8], path: P, config: &Config) -> Result<(Gltf, Buffers), Error>
    where P: AsRef<Path>
{
    if data.starts_with(b"glTF") {
        import_binary(&data, config, path.as_ref())
    } else {
        import_standard(&data, config, path.as_ref())
    }
}

/// Imports glTF 2.0 with custom configuration.
pub fn import_with_config<P>(path: P, config: &Config) -> Result<(Gltf, Buffers), Error>
    where P: AsRef<Path>
{
    import_impl(path.as_ref(), config)
}

/// Imports glTF 2.0 with default configuration.
pub fn import<P>(path: P) -> Result<(Gltf, Buffers), Error>
    where P: AsRef<Path>
{
    import_impl(path.as_ref(), &Default::default())
}

fn read_to_end_impl(path: &Path) -> Result<Vec<u8>, Error> {
    use io::Read;
    if path.exists() {
        let file = fs::File::open(path)?;
        let mut reader = io::BufReader::new(file);
        let mut buffer = vec![];
        let _ = reader.read_to_end(&mut buffer)?;
        Ok(buffer)
    } else {
        Err(Error::FileNotFound(path.to_path_buf()))
    }
}

fn read_to_end<P: AsRef<Path>>(path: P) -> Result<Vec<u8>, Error> {
    read_to_end_impl(path.as_ref())
}

fn parse_data_uri(uri: &str) -> Result<Vec<u8>, Error> {
    let encoded = uri.split(',').nth(1).unwrap();
    let decoded = base64::decode(&encoded)?;
    Ok(decoded)
}

fn load_external_buffers(
    base_path: &Path,
    gltf: &Gltf,
    mut bin: Option<Vec<u8>>,
) -> Result<Vec<Vec<u8>>, Error> {
    let mut buffers = vec![];
    for (index, buffer) in gltf.buffers().enumerate() {
        let uri = buffer.uri();
        let data = if uri == "#bin" {
            Ok(bin.take().unwrap())
        } else if uri.starts_with("data:") {
            Ok(parse_data_uri(uri)?)
        } else {
            let path = base_path.parent().unwrap_or_else(|| Path::new("./")).join(uri);
            read_to_end(&path)
        }?;
        if data.len() < buffer.length() {
            let path = json::Path::new().field("buffers").index(index);
            return Err(Error::BufferLength(path));
        }
        buffers.push(data);
    }
    Ok(buffers)
}

fn validate_standard(
    unvalidated: gltf::Unvalidated,
    config: &Config,
) -> Result<Gltf, Error> {
    use config::ValidationStrategy;
    Ok(match config.validation_strategy {
        ValidationStrategy::Skip => unvalidated.skip_validation(),
        ValidationStrategy::Minimal => unvalidated.validate_minimally()?,
        ValidationStrategy::Complete => unvalidated.validate_completely()?,
    })
}

fn validate_binary(
    unvalidated: gltf::Unvalidated,
    config: &Config,
    has_bin: bool,
) -> Result<Gltf, Error> {
    use config::ValidationStrategy;
    use json::validation::Error as Reason;

    if config.validation_strategy == ValidationStrategy::Skip {
        return Ok(unvalidated.skip_validation());
    }

    let mut errs = vec![];
    {
        let json = unvalidated.as_json();
        for (index, buffer) in json.buffers.iter().enumerate() {
            let path = || {
                json::Path::new()
                    .field("buffers")
                    .index(index)
                    .field("uri")
            };
            match index {
                0 if has_bin => if buffer.uri.is_some() {
                    errs.push((path(), Reason::Missing));
                },
                _ if buffer.uri.is_none() => {
                    errs.push((path(), Reason::Missing));
                },
                _ => {},
            }
        }
    }

    if errs.is_empty() {
        Ok(match config.validation_strategy {
            ValidationStrategy::Minimal => unvalidated.validate_minimally()?,
            ValidationStrategy::Complete => unvalidated.validate_completely()?,
            ValidationStrategy::Skip => unreachable!(),
        })
    } else {
        Err(Error::Validation(errs))
    }
}

fn import_standard<'a>(
    data: &'a [u8],
    config: &Config,
    base_path: &Path,
) -> Result<(Gltf, Buffers), Error> {
    let unvalidated = Gltf::from_slice(data)?;
    let gltf = validate_standard(unvalidated, config)?;
    let bin = None;
    let mut buffers = Buffers(vec![]);
    for buffer in load_external_buffers(base_path, &gltf, bin)? {
        buffers.0.push(buffer);
    }
    Ok((gltf, buffers))
}

fn import_binary<'a>(
    data: &'a [u8],
    config: &Config,
    base_path: &Path,
) -> Result<(Gltf, Buffers), Error> {
    let gltf::Glb { json, bin, .. } = gltf::Glb::from_slice(data)?;
    let unvalidated = Gltf::from_slice(&json)?;
    let bin = bin.map(|x| x.into_owned());
    let gltf = validate_binary(unvalidated, config, bin.is_some())?;
    let mut buffers = Buffers(vec![]);
    for buffer in load_external_buffers(base_path, &gltf, bin)? {
        buffers.0.push(buffer);
    }
    Ok((gltf, buffers))
}

impl From<json::Error> for Error {
    fn from(err: json::Error) -> Error {
        Error::MalformedJson(err)
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

impl From<Vec<(json::Path, validation::Error)>> for Error {
    fn from(errs: Vec<(json::Path, validation::Error)>) -> Error {
        Error::Validation(errs)
    }
}

impl From<gltf::Error> for Error {
    fn from(err: gltf::Error) -> Error {
        match err {
            gltf::Error::Validation(errs) => Error::Validation(errs),
            _ => Error::Gltf(err),
        }
    }
}

impl From<base64::DecodeError> for Error {
    fn from(err: base64::DecodeError) -> Error {
        Error::Base64Decoding(err)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use std::error::Error;
        write!(f, "{}", self.description())
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        use self::Error::*;
        match *self {
            Base64Decoding(_) => "base 64 decoding failed",
            BufferLength(_) => "buffer does not match required length",
            ExtensionDisabled(_) => "asset requires a disabled extension",
            ExtensionUnsupported(_) => "asset requires an unsupported extension",
            FileNotFound(_) => "file not found",
            IncompatibleVersion(_) => "asset is not glTF version 2.0",
            Io(_) => "io error",
            Gltf(_) => "error from gltf crate",
            MalformedJson(_) => "malformed .gltf / .glb JSON",
            Validation(_) => "asset failed validation tests",
        }
    }

    fn cause(&self) -> Option<&StdError> {
        use self::Error::*;
        match *self {
            MalformedJson(ref err) => Some(err),
            Io(ref err) => Some(err),
            _ => None,
        }
    }
}
<|endoftext|>