<commit_before>//! View bits in memory with turtles
//!
//! This example uses [@myrrlyn]’s [`bitvec`] crate to turn data into strings of
//! bits, and then draws them on the screen.
//!
//! [@myrrlyn]: //github.com/myrrlyn
//! [`bitvec`]: //crates.io/crates/bitvec

use bitvec::prelude::*;
use turtle::Turtle;

const BIT_WIDTH: f64 = 20.0;
const BIT_HEIGHT: f64 = 10.0;
const BIT_MARGIN: f64 = BIT_WIDTH / 2.0;
const BIT_BOX: f64 = BIT_WIDTH + BIT_MARGIN;

fn main() {
    // Replace this text with a message of your own to see how it changes on the
    // screen.
    let text = "Hello, world!";

    // This block sets up the turtle to draw bits more or less centered in the
    // screen. The turtle works by walking horizontally for each bit in a byte,
    // then backtracking and walking vertically to the next byte.
    let mut turtle = Turtle::new();
    turtle.pen_up();
    let right_edge = BIT_BOX * 4.0;
    let top_edge = BIT_HEIGHT * (text.len() as f64 / 2.0);
    // The turtle starts from the top right of the region, and moves left
    turtle.go_to((right_edge, top_edge));
    turtle.set_heading(180.0);

    // Now let’s draw some data on the screen, as individual bits

    // Rust strings can iterate over the bytes used to represent them.
    for byte in text.bytes() {
        // For each byte (`u8`), we use `bitvec` to make a view into its bits.
        //
        // The `LittleEndian` means that the view moves from right to left
        // across the byte, which fits how our turtle moves from right to left
        // across the screen.
        let bits = byte.bits::<LittleEndian>();
        // Then we draw the byte’s bits as a row
        draw_row(&mut turtle, bits);
        // And reset the turtle to the right edge.
        turtle.set_x(right_edge);
    }

    // `bitvec` can look at more than just `u8`. Let’s try looking at the bits
    // that represent a number!

    // First we need to pick a number. Rust provides some interesting numbers
    // for us.
    let tau = std::f64::consts::PI * 2.0;
    // But `bitvec` doesn’t know how to view all numbers. The standard library
    // provides a function `to_bits(f64) -> u64`, which turns it into a number
    // `bitvec` does know how to view.
    let raw_number = tau.to_bits();
    // `bitvec` can also view bits from left to right, with `BigEndian`.
    let bits = raw_number.bits::<BigEndian>();

    // Since we are reading bits from left to right, the turtle should move from
    // left to right also.
    let left_edge = -right_edge;
    turtle.set_x(left_edge * 2.0);
    turtle.set_heading(0.0);

    // The `&BitSlice` type acts just like `&[bool]`, so it comes with a
    // `.chunks` method which divides it into smaller pieces. `bitvec` can take
    // any number, not just multiples of 8, but 16 is a convenient number to
    // look at.
    for row in bits.chunks(16) {
        // Each chunk produced is a smaller `&BitSlice`, just like
        // `&[bool].chunks` produces smaller `&[bool]`s, so we can draw it.
        draw_row(&mut turtle, row);
        // After each row, the turtle has to go back to the left edge.
        turtle.set_x(left_edge * 2.0);
    }
}

/// Draw a row of bits on the screen.
///
/// This takes a reference to a turtle, which draws, and a reference to a slice
/// of bits, which provides the data to draw.
fn draw_row<C, T>(t: &mut Turtle, row: &BitSlice<C, T>)
where C: Cursor, T: BitStore {
    // `&BitSlice` can iterate over bits. It is just like `&[bool]`, and so it
    // produces `&bool` for each loop.
    for bit in row {
        // This checks if the bit produced by the row is `1` or `0`, and sets
        // the pen color to black (`1`) or light grey (`0`)
        if *bit {
            t.set_pen_color("black");
        }
        else {
            t.set_pen_color("light grey");
        }

        // For each bit, the loop puts down the pen to draw a line of the bit
        // color, then picks up the pen to add some spacing between them
        t.pen_down();
        t.forward(BIT_WIDTH);
        t.pen_up();
        t.forward(BIT_MARGIN);
    }

    // After the row is complete, the turtle picks up its pen,
    t.pen_up();
    // rememebers which direction it was going,
    let old_heading = t.heading();
    // turns to face down the screen,
    t.set_heading(270.0);
    // moves down by a row,
    t.forward(BIT_HEIGHT);
    // then goes back to its old direction.
    t.set_heading(old_heading);
    // This way each row gets spacing between them.
}
<commit_msg>Add some more comments<commit_after>//! View bits in memory with turtles
//!
//! This example uses [@myrrlyn]’s [`bitvec`] crate to turn data into strings of
//! bits, and then draws them on the screen.
//!
//! You are encouraged to change both the data used to seed the turtle, and the
//! `bitvec` calls that control how the turtle acts, to see what changes.
//!
//! [@myrrlyn]: //github.com/myrrlyn
//! [`bitvec`]: //crates.io/crates/bitvec

// The `bitvec` crate provides a bunch of types for us to use with one import
use bitvec::prelude::*;
use turtle::Turtle;

/// Set the line length for each displayed bit
const BIT_WIDTH: f64 = 20.0;
/// Set the vertical spacing between successive rows of bits
const BIT_HEIGHT: f64 = 10.0;
/// Set the horizontal spacing between successive bits in a row
const BIT_MARGIN: f64 = BIT_WIDTH / 2.0;
/// Compute the total width of a bit plus its spacing
const BIT_BOX: f64 = BIT_WIDTH + BIT_MARGIN;

fn main() {
    // Replace this text with a message of your own to see how it changes on the
    // screen.
    let text = "Hello, world!";

    // This block sets up the turtle to draw bits more or less centered in the
    // screen. The turtle works by walking horizontally for each bit in a byte,
    // then backtracking and walking vertically to the next byte.
    let mut turtle = Turtle::new();
    turtle.pen_up();
    // Compute the boundaries of the part of the screen where the turtle will
    // draw
    let right_edge = BIT_BOX * 4.0;
    let top_edge = BIT_HEIGHT * (text.len() as f64 / 2.0);
    // The turtle starts from the top right of the region,
    turtle.go_to((right_edge, top_edge));
    // and walks left
    turtle.set_heading(180.0);

    // Now let’s draw some data on the screen, as individual bits

    // Rust strings can iterate over the bytes used to represent them.
    for byte in text.bytes() {
        // For each byte (`u8`), we use `bitvec` to make a view into its bits.
        //
        // The `LittleEndian` means that the view moves from right to left
        // across the byte, which fits how our turtle moves from right to left
        // across the screen.
        let bits = byte.bits::<LittleEndian>();
        // Then we draw the byte’s bits as a row
        draw_row(&mut turtle, bits);
        // And reset the turtle to the right edge.
        turtle.set_x(right_edge);
    }

    // `bitvec` can look at more than just `u8`. Let’s try looking at the bits
    // that represent a number!

    // First we need to pick a number. Rust provides some interesting numbers
    // for us.
    let tau = std::f64::consts::PI * 2.0;
    // But `bitvec` doesn’t know how to view all numbers. The standard library
    // provides a function `to_bits(f64) -> u64`, which turns it into a number
    // `bitvec` does know how to view.
    let raw_number = tau.to_bits();
    // `bitvec` can also view bits from left to right, with `BigEndian`.
    let bits = raw_number.bits::<BigEndian>();

    // Since we are reading bits from left to right, the turtle should move from
    // left to right also. Change the `* 2.0` to move the section horizontally.
    let left_edge = -right_edge * 2.0;
    turtle.set_x(left_edge);
    // Walk from left to right
    turtle.set_heading(0.0);

    // The `&BitSlice` type acts just like `&[bool]`, so it comes with a
    // `.chunks` method which divides it into smaller pieces. `bitvec` can take
    // any number, not just multiples of 8, but 16 is a convenient number to
    // look at. Try changing it to a different number, like 10, to see what
    // happens!
    for row in bits.chunks(16) {
        // Each chunk produced is a smaller `&BitSlice`, just like
        // `&[bool].chunks` produces smaller `&[bool]`s, so we can draw it.
        draw_row(&mut turtle, row);
        // After each row, the turtle has to go back to the left edge.
        turtle.set_x(left_edge);
    }
}

/// Draw a row of bits on the screen.
///
/// This takes a reference to a turtle, which draws, and a reference to a slice
/// of bits, which provides the data to draw.
fn draw_row<C, T>(t: &mut Turtle, row: &BitSlice<C, T>)
where C: Cursor, T: BitStore {
    // `&BitSlice` can iterate over bits. It is just like `&[bool]`, and so it
    // produces `&bool` for each loop.
    for bit in row {
        // This checks if the bit produced by the row is `1` or `0`, and sets
        // the pen color to black (`1`) or light grey (`0`)
        if *bit {
            t.set_pen_color("black");
        }
        else {
            t.set_pen_color("light grey");
        }

        // For each bit, the loop puts down the pen to draw a line of the bit’s
        // color, then picks up the pen to add some horizontal spacing between
        // them.
        t.pen_down();
        t.forward(BIT_WIDTH);
        t.pen_up();
        t.forward(BIT_MARGIN);
    }

    // After the row is complete, the turtle picks up its pen,
    t.pen_up();
    // rememebers which direction it was going,
    let old_heading = t.heading();
    // turns to face down the screen,
    t.set_heading(270.0);
    // moves down by a row,
    t.forward(BIT_HEIGHT);
    // then goes back to its old direction.
    t.set_heading(old_heading);
    // This way each row gets vertical spacing between them.
}
<|endoftext|>


<commit_before>// Hound -- A WAV encoding and decoding library in Rust
// Copyright (C) 2015 Ruud van Asseldonk
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 3 of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

// This example shows how to play a wav file using the cpal crate.

extern crate hound;
extern crate cpal;

use std::env;
use std::thread;

fn main() {
    // Make a WavReader that reads the file provided as program argument.
    let fname = env::args().nth(1).expect("no file given");
    let mut reader = hound::WavReader::open(fname).unwrap();
    let spec = reader.spec().clone(); // TODO: by value might be better in this case.

    // A voice in cpal is used for playback.
    let mut voice = cpal::Voice::new();

    let mut append_data = |voice: &mut cpal::Voice| {
        let mut samples = reader.samples::<i16>();
        let samples_left = samples.size_hint().0; // TODO: add method to reader?

        if samples_left == 0 { return false; }

        println!("still going, {} samples left", samples_left);

        let mut buffer: cpal::Buffer<u16> =
            voice.append_data(spec.channels,
                              cpal::SamplesRate(spec.sample_rate),
                              samples_left);
        // Fill the cpal buffer with data from the wav file.
        for (dest, src) in buffer.iter_mut().zip(&mut samples) {
            // TODO: There is a bug in cpal that handles signed samples in the
            // wrong manner, so we cast it to `u16` for now.
            *dest = src.unwrap() as u16;
        }

        // Probably not done, loop again.
        true
    };

    // The voice must have some data before playing for the first time.
    append_data(&mut voice);
    voice.play();

    // Then we keep providing new data until the end of the audio.
    while append_data(&mut voice) { }

    // TODO: Cpal has no function (yet) to wait for playback to complete, so
    // sleep manually.
    thread::sleep_ms(1000);
}
<commit_msg>remove debug print from cpal example<commit_after>// Hound -- A WAV encoding and decoding library in Rust
// Copyright (C) 2015 Ruud van Asseldonk
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 3 of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

// This example shows how to play a wav file using the cpal crate.

extern crate hound;
extern crate cpal;

use std::env;
use std::thread;

fn main() {
    // Make a WavReader that reads the file provided as program argument.
    let fname = env::args().nth(1).expect("no file given");
    let mut reader = hound::WavReader::open(fname).unwrap();
    let spec = reader.spec().clone(); // TODO: by value might be better in this case.

    // A voice in cpal is used for playback.
    let mut voice = cpal::Voice::new();

    let mut append_data = |voice: &mut cpal::Voice| {
        let mut samples = reader.samples::<i16>();
        let samples_left = samples.size_hint().0; // TODO: add method to reader?

        if samples_left == 0 { return false; }

        let mut buffer: cpal::Buffer<u16> =
            voice.append_data(spec.channels,
                              cpal::SamplesRate(spec.sample_rate),
                              samples_left);
        // Fill the cpal buffer with data from the wav file.
        for (dest, src) in buffer.iter_mut().zip(&mut samples) {
            // TODO: There is a bug in cpal that handles signed samples in the
            // wrong manner, so we cast it to `u16` for now.
            *dest = src.unwrap() as u16;
        }

        // Probably not done, loop again.
        true
    };

    // The voice must have some data before playing for the first time.
    append_data(&mut voice);
    voice.play();

    // Then we keep providing new data until the end of the audio.
    while append_data(&mut voice) { }

    // TODO: Cpal has no function (yet) to wait for playback to complete, so
    // sleep manually.
    thread::sleep_ms(1000);
}
<|endoftext|>


<commit_before>extern crate mp4parse;

use std::env;
use std::fs::File;
use std::io::{Read, Seek, Take};
use std::io::Cursor;
use std::thread;

fn limit<'a, T: Read>(f: &'a mut T, h: &mp4parse::BoxHeader) -> Take<&'a mut T> {
    f.take(h.size - h.offset)
}

fn read_box<T: Read + Seek>(f: &mut T) {
    mp4parse::read_box_header(f).and_then(|h| {
        match &(mp4parse::fourcc_to_string(h.name))[..] {
            "ftyp" => {
                let mut content = limit(f, &h);
                let ftyp = mp4parse::read_ftyp(&mut content, &h).unwrap();
                println!("{}", ftyp);
            },
            "moov" => {
                println!("{} -- recursing", h);
                let buf: Vec<u8> = limit(f, &h)
                    .bytes()
                    .map(|u| u.unwrap())
                    .collect();
                let mut content = Cursor::new(buf);
                read_box(&mut content);
                println!("{} -- end", h);
            },
            "mvhd" => {
                let mut content = limit(f, &h);
                let mvhd = mp4parse::read_mvhd(&mut content, &h).unwrap();
                println!("  {}", mvhd);
            },
            _ => {
                // Skip the contents of unknown chunks.
                println!("{}", h);
                mp4parse::skip_box_content(f, &h).unwrap();
            },
        };
        Some(()) // and_then needs a Option.
    });
}

fn dump_file(filename: String) {
    let mut f = File::open(filename).unwrap();
    let task = thread::spawn(move || {
        loop {
            read_box(&mut f);
        }
    });
    // Catch and ignore any panics in the thread.
    task.join().ok();
}

fn main() {
    for filename in env::args().skip(1) {
        println!("-- dump of '{}' --", filename);
        dump_file(filename);
    }
}
<commit_msg>Abstract read_box() recursion and call it from 'trak' boxes.<commit_after>extern crate mp4parse;

use std::env;
use std::fs::File;
use std::io::{Read, Seek, Take};
use std::io::Cursor;
use std::thread;

fn limit<'a, T: Read>(f: &'a mut T, h: &mp4parse::BoxHeader) -> Take<&'a mut T> {
    f.take(h.size - h.offset)
}

fn recurse<T: Read>(f: &mut T, h: &mp4parse::BoxHeader) {
    println!("{} -- recursing", h);
    let buf: Vec<u8> = limit(f, &h)
        .bytes()
        .map(|u| u.unwrap())
        .collect();
    let mut content = Cursor::new(buf);
    loop {
        read_box(&mut content);
    }
    println!("{} -- end", h);
}

fn read_box<T: Read + Seek>(f: &mut T) {
    mp4parse::read_box_header(f).and_then(|h| {
        match &(mp4parse::fourcc_to_string(h.name))[..] {
            "ftyp" => {
                let mut content = limit(f, &h);
                let ftyp = mp4parse::read_ftyp(&mut content, &h).unwrap();
                println!("{}", ftyp);
            },
            "moov" => recurse(f, &h),
            "mvhd" => {
                let mut content = limit(f, &h);
                let mvhd = mp4parse::read_mvhd(&mut content, &h).unwrap();
                println!("  {}", mvhd);
            },
            "trak" => recurse(f, &h),
            _ => {
                // Skip the contents of unknown chunks.
                println!("{}", h);
                mp4parse::skip_box_content(f, &h).unwrap();
            },
        };
        Some(()) // and_then needs a Option.
    });
}

fn dump_file(filename: String) {
    let mut f = File::open(filename).unwrap();
    let task = thread::spawn(move || {
        loop {
            read_box(&mut f);
        }
    });
    // Catch and ignore any panics in the thread.
    task.join().ok();
}

fn main() {
    for filename in env::args().skip(1) {
        println!("-- dump of '{}' --", filename);
        dump_file(filename);
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "nightly-testing", plugin(clippy))]
#![cfg_attr(feature = "nightly-testing", feature(plugin))]
#![cfg_attr(feature = "nightly-testing", allow(too_many_arguments))]
#![cfg_attr(feature = "nightly-testing", allow(used_underscore_binding))]
#![cfg_attr(not(feature = "with-syntex"), feature(rustc_private, plugin))]
#![cfg_attr(not(feature = "with-syntex"), plugin(quasi_macros))]

extern crate aster;
extern crate quasi;
extern crate serde_codegen_internals as internals;

#[cfg(feature = "with-syntex")]
extern crate syntex;

#[cfg(feature = "with-syntex")]
#[macro_use]
extern crate syntex_syntax as syntax;

#[cfg(not(feature = "with-syntex"))]
#[macro_use]
extern crate syntax;

#[cfg(not(feature = "with-syntex"))]
extern crate rustc_plugin;

#[cfg(feature = "with-syntex")]
use std::path::Path;

#[cfg(not(feature = "with-syntex"))]
use syntax::feature_gate::AttributeType;

#[cfg(feature = "with-syntex")]
include!(concat!(env!("OUT_DIR"), "/lib.rs"));

#[cfg(not(feature = "with-syntex"))]
include!("lib.rs.in");

#[cfg(feature = "with-syntex")]
pub fn expand<S, D>(src: S, dst: D) -> Result<(), syntex::Error>
    where S: AsRef<Path>,
          D: AsRef<Path>,
{
    let mut registry = syntex::Registry::new();
    register(&mut registry);
    registry.expand("", src.as_ref(), dst.as_ref())
}

#[cfg(feature = "with-syntex")]
pub fn register(reg: &mut syntex::Registry) {
    use syntax::{ast, fold};

    /// Strip the serde attributes from the crate.
    #[cfg(feature = "with-syntex")]
    fn strip_attributes(krate: ast::Crate) -> ast::Crate {
        /// Helper folder that strips the serde attributes after the extensions have been expanded.
        struct StripAttributeFolder;

        impl fold::Folder for StripAttributeFolder {
            fn fold_attribute(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
                match attr.node.value.node {
                    ast::MetaItemKind::List(ref n, _) if n == &"serde" => { return None; }
                    _ => {}
                }

                Some(attr)
            }

            fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
                fold::noop_fold_mac(mac, self)
            }
        }

        fold::Folder::fold_crate(&mut StripAttributeFolder, krate)
    }

    reg.add_attr("feature(custom_derive)");
    reg.add_attr("feature(custom_attribute)");

    reg.add_decorator("derive_Serialize", ser::expand_derive_serialize);
    reg.add_decorator("derive_Deserialize", de::expand_derive_deserialize);

    reg.add_post_expansion_pass(strip_attributes);
}

#[cfg(not(feature = "with-syntex"))]
pub fn register(reg: &mut rustc_plugin::Registry) {
    reg.register_syntax_extension(
        syntax::parse::token::intern("derive_Serialize"),
        syntax::ext::base::MultiDecorator(
            Box::new(ser::expand_derive_serialize)));

    reg.register_syntax_extension(
        syntax::parse::token::intern("derive_Deserialize"),
        syntax::ext::base::MultiDecorator(
            Box::new(de::expand_derive_deserialize)));

    reg.register_attribute("serde".to_owned(), AttributeType::Normal);
}
<commit_msg>Remove public dependency on Syntex<commit_after>#![cfg_attr(feature = "nightly-testing", plugin(clippy))]
#![cfg_attr(feature = "nightly-testing", feature(plugin))]
#![cfg_attr(feature = "nightly-testing", allow(too_many_arguments))]
#![cfg_attr(feature = "nightly-testing", allow(used_underscore_binding))]
#![cfg_attr(not(feature = "with-syntex"), feature(rustc_private, plugin))]
#![cfg_attr(not(feature = "with-syntex"), plugin(quasi_macros))]

extern crate aster;
extern crate quasi;
extern crate serde_codegen_internals as internals;

#[cfg(feature = "with-syntex")]
extern crate syntex;

#[cfg(feature = "with-syntex")]
#[macro_use]
extern crate syntex_syntax as syntax;

#[cfg(not(feature = "with-syntex"))]
#[macro_use]
extern crate syntax;

#[cfg(not(feature = "with-syntex"))]
extern crate rustc_plugin;

#[cfg(feature = "with-syntex")]
use std::path::Path;

#[cfg(not(feature = "with-syntex"))]
use syntax::feature_gate::AttributeType;

#[cfg(feature = "with-syntex")]
include!(concat!(env!("OUT_DIR"), "/lib.rs"));

#[cfg(not(feature = "with-syntex"))]
include!("lib.rs.in");

#[cfg(feature = "with-syntex")]
pub fn expand<S, D>(src: S, dst: D) -> Result<(), syntex::Error>
    where S: AsRef<Path>,
          D: AsRef<Path>,
{
    use syntax::{ast, fold};

    /// Strip the serde attributes from the crate.
    #[cfg(feature = "with-syntex")]
    fn strip_attributes(krate: ast::Crate) -> ast::Crate {
        /// Helper folder that strips the serde attributes after the extensions have been expanded.
        struct StripAttributeFolder;

        impl fold::Folder for StripAttributeFolder {
            fn fold_attribute(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
                match attr.node.value.node {
                    ast::MetaItemKind::List(ref n, _) if n == &"serde" => { return None; }
                    _ => {}
                }

                Some(attr)
            }

            fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
                fold::noop_fold_mac(mac, self)
            }
        }

        fold::Folder::fold_crate(&mut StripAttributeFolder, krate)
    }

    let mut reg = syntex::Registry::new();

    reg.add_attr("feature(custom_derive)");
    reg.add_attr("feature(custom_attribute)");

    reg.add_decorator("derive_Serialize", ser::expand_derive_serialize);
    reg.add_decorator("derive_Deserialize", de::expand_derive_deserialize);

    reg.add_post_expansion_pass(strip_attributes);

    reg.expand("", src.as_ref(), dst.as_ref())
}

#[cfg(not(feature = "with-syntex"))]
pub fn register(reg: &mut rustc_plugin::Registry) {
    reg.register_syntax_extension(
        syntax::parse::token::intern("derive_Serialize"),
        syntax::ext::base::MultiDecorator(
            Box::new(ser::expand_derive_serialize)));

    reg.register_syntax_extension(
        syntax::parse::token::intern("derive_Deserialize"),
        syntax::ext::base::MultiDecorator(
            Box::new(de::expand_derive_deserialize)));

    reg.register_attribute("serde".to_owned(), AttributeType::Normal);
}
<|endoftext|>


<commit_before>use std::io;
use std::path::PathBuf;
use std::sync::Arc;

use itertools::Itertools;

use filemap::{FileMap, FileName};
use index::{ByteIndex, ByteOffset, RawIndex};

#[derive(Clone, Debug, Default)]
#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
#[cfg_attr(feature = "memory_usage", derive(HeapSizeOf))]
pub struct CodeMap {
    files: Vec<Arc<FileMap>>,
}

impl CodeMap {
    /// Creates an empty `CodeMap`.
    pub fn new() -> CodeMap {
        CodeMap::default()
    }

    /// The next start index to use for a new filemap
    fn next_start_index(&self) -> ByteIndex {
        let end_index = self.files
            .last()
            .map(|x| x.span().end())
            .unwrap_or_else(ByteIndex::none);

        // Add one byte of padding between each file
        end_index + ByteOffset(1)
    }

    /// Adds a filemap to the codemap with the given name and source string
    pub fn add_filemap(&mut self, name: FileName, src: String) -> Arc<FileMap> {
        let file = Arc::new(FileMap::with_index(name, src, self.next_start_index()));
        self.files.push(file.clone());
        file
    }

    /// Adds a filemap to the codemap with the given name and source string
    pub fn add_filemap_from_disk<P: Into<PathBuf>>(&mut self, name: P) -> io::Result<Arc<FileMap>> {
        let file = Arc::new(FileMap::from_disk(name, self.next_start_index())?);
        self.files.push(file.clone());
        Ok(file)
    }

    /// Looks up the `File` that contains the specified byte index.
    pub fn find_file(&self, index: ByteIndex) -> Option<&Arc<FileMap>> {
        self.find_index(index).map(|i| &self.files[i])
    }

    pub fn update(&mut self, index: ByteIndex, src: String) -> Option<Arc<FileMap>> {
        self.find_index(index).map(|i| {
            let min = if i == 0 {
                ByteIndex(1)
            } else {
                self.files[i - 1].span().end() + ByteOffset(1)
            };
            let max = self.files
                .get(i + 1)
                .map_or(ByteIndex(RawIndex::max_value()), |file_map| {
                    file_map.span().start()
                }) - ByteOffset(1);
            if src.len() <= (max - min).to_usize() {
                let start_index = self.files[i].span().start();
                let name = self.files[i].name().clone();
                let new_file = Arc::new(FileMap::with_index(name, src, start_index));
                self.files[i] = new_file.clone();
                new_file
            } else {
                let file = self.files.remove(i);
                match self.files
                    .first()
                    .map(|file| file.span().start().to_usize() - 1)
                    .into_iter()
                    .chain(self.files.iter().tuple_windows().map(|(x, y)| {
                        eprintln!("{} {}", x.span(), y.span());
                        (y.span().start() - x.span().end()).to_usize() - 1
                    }))
                    .position(|size| size >= src.len() + 1)
                {
                    Some(j) => {
                        let start_index = if j == 0 {
                            ByteIndex(1)
                        } else {
                            self.files[j - 1].span().end() + ByteOffset(1)
                        };
                        let new_file =
                            Arc::new(FileMap::with_index(file.name().clone(), src, start_index));
                        self.files.insert(j, new_file.clone());
                        new_file
                    },
                    None => self.add_filemap(file.name().clone(), src),
                }
            }
        })
    }

    fn find_index(&self, index: ByteIndex) -> Option<usize> {
        use std::cmp::Ordering;

        self.files
            .binary_search_by(|file| match () {
                () if file.span().start() > index => Ordering::Greater,
                () if file.span().end() < index => Ordering::Less,
                () => Ordering::Equal,
            })
            .ok()
    }
}

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

    use index::{ByteIndex, RawIndex};
    use span::Span;

    fn check_maps(code_map: &CodeMap, files: &[(RawIndex, &str, &str)]) {
        println!("{:?}", code_map);
        assert_eq!(code_map.files.len(), files.len());
        let mut prev_span = Span::new(0.into(), 0.into());
        for (i, (file, &(start, name, src))) in code_map.files.iter().zip(files).enumerate() {
            println!("{}: {:?} <=> {:?}", i, file, (start, name, src));
            match *file.name() {
                FileName::Virtual(ref virt) => assert_eq!(*virt, name, "At index {}", i),
                _ => panic!(),
            }
            assert_eq!(ByteIndex(start), file.span().start(), "At index {}", i);
            assert!(prev_span.end() < file.span().start(), "At index {}", i);
            assert_eq!(file.src(), src, "At index {}", i);

            prev_span = file.span();
        }
    }

    #[test]
    fn update() {
        let mut code_map = CodeMap::new();

        let a_span = code_map.add_filemap("a".into(), "a".into()).span();
        let b_span = code_map.add_filemap("b".into(), "b".into()).span();
        let c_span = code_map.add_filemap("c".into(), "c".into()).span();

        code_map.update(a_span.start(), "aa".into()).unwrap();
        check_maps(&code_map, &[(3, "b", "b"), (5, "c", "c"), (7, "a", "aa")]);

        code_map.update(b_span.start(), "".into()).unwrap().span();
        check_maps(&code_map, &[(3, "b", ""), (5, "c", "c"), (7, "a", "aa")]);

        code_map.update(c_span.start(), "ccc".into()).unwrap();
        check_maps(&code_map, &[(3, "b", ""), (7, "a", "aa"), (10, "c", "ccc")]);
    }
}
<commit_msg>Added an iter method to CodeMap<commit_after>use std::io;
use std::path::PathBuf;
use std::sync::Arc;

use itertools::Itertools;

use filemap::{FileMap, FileName};
use index::{ByteIndex, ByteOffset, RawIndex};

#[derive(Clone, Debug, Default)]
#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
#[cfg_attr(feature = "memory_usage", derive(HeapSizeOf))]
pub struct CodeMap {
    files: Vec<Arc<FileMap>>,
}

impl CodeMap {
    /// Creates an empty `CodeMap`.
    pub fn new() -> CodeMap {
        CodeMap::default()
    }

    /// The next start index to use for a new filemap
    fn next_start_index(&self) -> ByteIndex {
        let end_index = self.files
            .last()
            .map(|x| x.span().end())
            .unwrap_or_else(ByteIndex::none);

        // Add one byte of padding between each file
        end_index + ByteOffset(1)
    }

    /// Adds a filemap to the codemap with the given name and source string
    pub fn add_filemap(&mut self, name: FileName, src: String) -> Arc<FileMap> {
        let file = Arc::new(FileMap::with_index(name, src, self.next_start_index()));
        self.files.push(file.clone());
        file
    }

    /// Adds a filemap to the codemap with the given name and source string
    pub fn add_filemap_from_disk<P: Into<PathBuf>>(&mut self, name: P) -> io::Result<Arc<FileMap>> {
        let file = Arc::new(FileMap::from_disk(name, self.next_start_index())?);
        self.files.push(file.clone());
        Ok(file)
    }

    /// Looks up the `File` that contains the specified byte index.
    pub fn find_file(&self, index: ByteIndex) -> Option<&Arc<FileMap>> {
        self.find_index(index).map(|i| &self.files[i])
    }

    pub fn update(&mut self, index: ByteIndex, src: String) -> Option<Arc<FileMap>> {
        self.find_index(index).map(|i| {
            let min = if i == 0 {
                ByteIndex(1)
            } else {
                self.files[i - 1].span().end() + ByteOffset(1)
            };
            let max = self.files
                .get(i + 1)
                .map_or(ByteIndex(RawIndex::max_value()), |file_map| {
                    file_map.span().start()
                }) - ByteOffset(1);
            if src.len() <= (max - min).to_usize() {
                let start_index = self.files[i].span().start();
                let name = self.files[i].name().clone();
                let new_file = Arc::new(FileMap::with_index(name, src, start_index));
                self.files[i] = new_file.clone();
                new_file
            } else {
                let file = self.files.remove(i);
                match self.files
                    .first()
                    .map(|file| file.span().start().to_usize() - 1)
                    .into_iter()
                    .chain(self.files.iter().tuple_windows().map(|(x, y)| {
                        eprintln!("{} {}", x.span(), y.span());
                        (y.span().start() - x.span().end()).to_usize() - 1
                    }))
                    .position(|size| size >= src.len() + 1)
                {
                    Some(j) => {
                        let start_index = if j == 0 {
                            ByteIndex(1)
                        } else {
                            self.files[j - 1].span().end() + ByteOffset(1)
                        };
                        let new_file =
                            Arc::new(FileMap::with_index(file.name().clone(), src, start_index));
                        self.files.insert(j, new_file.clone());
                        new_file
                    },
                    None => self.add_filemap(file.name().clone(), src),
                }
            }
        })
    }

    pub fn iter(&self) -> impl Iterator<Item=&Arc<FileMap>> {
        self.files.iter()
    }

    fn find_index(&self, index: ByteIndex) -> Option<usize> {
        use std::cmp::Ordering;

        self.files
            .binary_search_by(|file| match () {
                () if file.span().start() > index => Ordering::Greater,
                () if file.span().end() < index => Ordering::Less,
                () => Ordering::Equal,
            })
            .ok()
    }
}

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

    use index::{ByteIndex, RawIndex};
    use span::Span;

    fn check_maps(code_map: &CodeMap, files: &[(RawIndex, &str, &str)]) {
        println!("{:?}", code_map);
        assert_eq!(code_map.files.len(), files.len());
        let mut prev_span = Span::new(0.into(), 0.into());
        for (i, (file, &(start, name, src))) in code_map.files.iter().zip(files).enumerate() {
            println!("{}: {:?} <=> {:?}", i, file, (start, name, src));
            match *file.name() {
                FileName::Virtual(ref virt) => assert_eq!(*virt, name, "At index {}", i),
                _ => panic!(),
            }
            assert_eq!(ByteIndex(start), file.span().start(), "At index {}", i);
            assert!(prev_span.end() < file.span().start(), "At index {}", i);
            assert_eq!(file.src(), src, "At index {}", i);

            prev_span = file.span();
        }
    }

    #[test]
    fn update() {
        let mut code_map = CodeMap::new();

        let a_span = code_map.add_filemap("a".into(), "a".into()).span();
        let b_span = code_map.add_filemap("b".into(), "b".into()).span();
        let c_span = code_map.add_filemap("c".into(), "c".into()).span();

        code_map.update(a_span.start(), "aa".into()).unwrap();
        check_maps(&code_map, &[(3, "b", "b"), (5, "c", "c"), (7, "a", "aa")]);

        code_map.update(b_span.start(), "".into()).unwrap().span();
        check_maps(&code_map, &[(3, "b", ""), (5, "c", "c"), (7, "a", "aa")]);

        code_map.update(c_span.start(), "ccc".into()).unwrap();
        check_maps(&code_map, &[(3, "b", ""), (7, "a", "aa"), (10, "c", "ccc")]);
    }
}
<|endoftext|>


<commit_before>//! Implementations of the default callbacks exposed by wlc.
//! These functions are the main entry points into Way Cooler from user action.
//! This is the default mode that Way Cooler is in at initilization
use rustwlc::*;
use rustwlc::input::{pointer, keyboard};
use rustwlc::render::{read_pixels, wlc_pixel_format};
use uuid::Uuid;

use super::{EVENT_BLOCKED, EVENT_PASS_THROUGH, LEFT_CLICK, RIGHT_CLICK};
use ::keys::{self, KeyPress, KeyEvent};
use ::layout::{lock_tree, try_lock_tree, try_lock_action, Action, ContainerType,
                    MovementError, TreeError, FocusError};
use ::layout::commands::set_performing_action;
use ::layout::MIN_SIZE;
use ::lua::{self, LuaQuery};

use ::render::screen_scrape::{read_screen_scrape_lock, scraped_pixels_lock,
                              sync_scrape};

use registry::{self};
use super::Mode;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Default;

#[allow(unused)]
impl Mode for Default {
    fn output_created(&mut self, output: WlcOutput) -> bool {
        if let Ok(mut tree) = try_lock_tree() {
            let result = tree.add_output(output).and_then(|_|{
                tree.switch_to_workspace(&"1")
                    .map(|_| tree.layout_active_of(ContainerType::Output))
            });
            match result {
                // If the output exists, we just couldn't add it to the tree because
                // it's already there. That's OK
                Ok(_) | Err(TreeError::OutputExists(_)) => true,
                _ => false
            }
        } else {
            false
        }
    }

    fn output_destroyed(&mut self, output: WlcOutput) {
         // TODO Redistribute workspaces of that output.
    }

    fn output_focused(&mut self, output: WlcOutput, focused: bool) {
         // TODO Ensure focused on right workspace
    }

    fn output_resolution(&mut self, output: WlcOutput,
                                    old_size_ptr: Size, new_size_ptr: Size) {
        // Update the resolution of the output and its children
        let scale = 1;
        output.set_resolution(new_size_ptr, scale);
        if let Ok(mut tree) = try_lock_tree() {
            tree.layout_active_of(ContainerType::Output)
                .expect("Could not layout active output");
        }
    }

    fn output_render_post(&mut self, output: WlcOutput) {
        if WlcOutput::focused() != output {
            return
        }
        let need_to_fetch = read_screen_scrape_lock();
        if *need_to_fetch {
            if let Ok(mut scraped_pixels) = scraped_pixels_lock() {
                let resolution = output.get_resolution()
                    .expect("Output had no resolution");
                let geo = Geometry {
                    origin: Point { x: 0, y: 0 },
                    size: resolution
                };
                let result = read_pixels(wlc_pixel_format::WLC_RGBA8888, geo).1;
                *scraped_pixels = result;
                sync_scrape();
            }
        }
    }

    fn view_created(&mut self, view: WlcView) -> bool {
        let lock = registry::clients_read();
        let client = lock.client(Uuid::nil()).unwrap();
        let handle = registry::ReadHandle::new(&client);
        let bar = handle.read("programs".into())
            .expect("programs category didn't exist")
            .get("x11_bar".into())
            .and_then(|data| data.as_string().map(str::to_string));
        // TODO Move this hack, probably could live somewhere else
        if let Some(bar_name) = bar {
            if view.get_title().as_str() == bar_name {
                view.set_mask(1);
                view.bring_to_front();
                if let Ok(mut tree) = try_lock_tree() {
                    for output in WlcOutput::list() {
                        tree.add_bar(view, output).unwrap_or_else(|_| {
                            warn!("Could not add bar {:#?} to output {:#?}", view, output);
                        });
                    }
                    return true;
                }
            }
        }
        // TODO Remove this hack
        if view.get_class().as_str() == "Background" {
            trace!("Setting background: {}", view.get_title());
            view.send_to_back();
            view.set_mask(1);
            let output = view.get_output();
            let resolution = output.get_resolution()
                .expect("Couldn't get output resolution");
            let fullscreen = Geometry {
                origin: Point { x: 0, y: 0 },
                size: resolution
            };
            view.set_geometry(ResizeEdge::empty(), fullscreen);
            if let Ok(mut tree) = lock_tree() {
                let output = tree.outputs()[0];
                return tree.add_background(view, output).map(|_| true)
                    .unwrap_or_else(|err| {
                        warn!("Could not add background due to {:?}", err);
                        true
                    })
            } else {
                warn!("Could not lock tree to place background");
            }
            return false
        }
        if let Ok(mut tree) = lock_tree() {
            let result = tree.add_view(view).and_then(|_| {
                view.set_state(VIEW_MAXIMIZED, true);
                match tree.set_active_view(view) {
                    // If blocked by fullscreen, we don't focus on purpose
                    Err(TreeError::Focus(FocusError::BlockedByFullscreen(_, _))) => Ok(()),
                    result => result
                }
            });
            if result.is_err() {
                warn!("Could not add {:?}. Reason: {:?}", view, result);
            }
            result.is_ok()
        } else {
            false
        }
    }

    fn view_destroyed(&mut self, view: WlcView) {
        match try_lock_tree() {
            Ok(mut tree) => {
                tree.remove_view(view).unwrap_or_else(|err| {
                    match err {
                        TreeError::ViewNotFound(_) => {},
                        _ => {
                            warn!("Error in view_destroyed: {:?}", err);
                        }
                    }});
            },
            Err(err) => warn!("Could not delete view {:?}, {:?}", view, err)
        }
    }

    fn view_focused(&mut self, current: WlcView, focused: bool) {
        current.set_state(VIEW_ACTIVATED, focused);
        if let Ok(mut tree) = try_lock_tree() {
            match tree.set_active_view(current) {
                Ok(_) => {},
                Err(err) => {
                    warn!("Could not set {:?} to be active view: {:?}", current, err);
                }
            }
        }
    }

    fn view_props_changed(&mut self, view: WlcView, prop: ViewPropertyType) {
        if prop.contains(PROPERTY_TITLE) {
            if let Ok(mut tree) = try_lock_tree() {
                match tree.update_title(view) {
                    Ok(_) => {},
                    Err(err) => {
                        warn!("Could not update title for view {:?} because {:#?}",
                            view, err);
                    }
                }
            }
        }
    }

    fn view_moved_to_output(&mut self, view: WlcView, o1: WlcOutput, o2: WlcOutput) {
        // TODO Ensure in correct workspace
    }

    fn view_request_state(&mut self, view: WlcView, state: ViewState, toggle: bool) {
        if state == VIEW_FULLSCREEN {
            if let Ok(mut tree) = try_lock_tree() {
                if let Ok(id) = tree.lookup_handle(view.into()) {
                    tree.set_fullscreen(id, toggle)
                        .expect("The ID was related to a non-view, somehow!");
                    match tree.container_in_active_workspace(id) {
                        Ok(true) => {
                            tree.layout_active_of(ContainerType::Workspace)
                                .unwrap_or_else(|err| {
                                    warn!("Could not layout active workspace \
                                           for view {:?}: {:?}",
                                            view, err)
                                });
                        },
                        Ok(false) => {},
                        Err(err) => warn!("Could not set {:?} fullscreen: {:?}",
                                           view, err)
                    }
                } else {
                    warn!("Could not find view {:?} in tree", view);
                }
            }
        }
    }

    fn view_request_move(&mut self, view: WlcView, _dest: Point) {
        if let Ok(mut tree) = try_lock_tree() {
            if let Err(err) = tree.set_active_view(view) {
                warn!("view_request_move error: {:?}", err);
            }
        }
    }

    fn view_request_resize(&mut self, view: WlcView, edge: ResizeEdge, point: Point) {
        if let Ok(mut tree) = try_lock_tree() {
            let in_action = try_lock_action()
                .map(|action| action.is_some())
                .unwrap_or(false);
            if in_action {
                if let Ok(id) = tree.lookup_handle(view.into()) {
                    if let Err(err) = tree.resize_container(id, edge, point) {
                        warn!("resize_container returned error: {:#?}",
                                err);
                    }
                }
            }
        }
    }

    fn on_keyboard_key(&mut self, _view: WlcView, _time: u32, mods: KeyboardModifiers,
                            key: u32, state: KeyState) -> bool {
        let empty_mods: KeyboardModifiers = KeyboardModifiers {
                mods: MOD_NONE,
                leds: KeyboardLed::empty()
        };
        let sym = keyboard::get_keysym_for_key(key, empty_mods);
        let press = KeyPress::new(mods.mods, sym);

        if state == KeyState::Pressed {
            if let Some(key) = keys::get(&press) {
                info!("[key] Found an action for {}, blocking event", press);
                let action = key.event;
                let passthrough = key.passthrough;
                match action {
                    KeyEvent::Command(func) => {
                        func();
                    },
                    KeyEvent::Lua => {
                        match lua::send(LuaQuery::HandleKey(press)) {
                            Ok(_) => {},
                            Err(err) => {
                                // We may want to wait for Lua's reply from
                                // keypresses; for example if the table is tampered
                                // with or Lua is restarted or Lua has an error.
                                // ATM Lua asynchronously logs this but in the future
                                // an error popup/etc is a good idea.
                                warn!("Error sending keypress: {:?}", err);
                            }
                        }
                    }
                }
                return !passthrough
            }
        }

        return EVENT_PASS_THROUGH
    }

    fn view_request_geometry(&mut self, view: WlcView, geometry: Geometry) {
        if geometry.size.w < MIN_SIZE.w || geometry.size.h < MIN_SIZE.h {
            warn!("Ignoring requested geometry {:#?}, which is below min {:#?}",
                  geometry, MIN_SIZE);
            return;
        }
        if let Ok(mut tree) = try_lock_tree() {
            match tree.update_floating_geometry(view, geometry) {
                Ok(()) | Err(TreeError::ViewNotFound(_)) => {},
                err => warn!("Could not find view {:#?} \
                              in order to update geometry w/ {:#?} \
                              because of {:#?}",
                             view, geometry, err)
            }
        }
    }

    fn on_pointer_button(&mut self, view: WlcView, _time: u32,
                            mods: KeyboardModifiers, button: u32,
                                state: ButtonState, point: Point) -> bool {
        if state == ButtonState::Pressed {
            let mouse_mod = keys::mouse_modifier();
            if button == LEFT_CLICK && !view.is_root() {
                if let Ok(mut tree) = try_lock_tree() {
                    tree.set_active_view(view).unwrap_or_else(|_| {
                        // still focus on view, even if not in tree.
                        view.focus();
                    });
                    if mods.mods.contains(mouse_mod) {
                        let action = Action {
                            view: view,
                            grab: point,
                            edges: ResizeEdge::empty()
                        };
                        set_performing_action(Some(action));
                    }
                }
            } else if button == RIGHT_CLICK && !view.is_root() {
                info!("User right clicked w/ mods \"{:?}\" on {:?}", mods, view);
                if let Ok(mut tree) = try_lock_tree() {
                    tree.set_active_view(view).ok();
                }
                if mods.mods.contains(mouse_mod) {
                    let action = Action {
                        view: view,
                        grab: point,
                        edges: ResizeEdge::empty()
                    };
                    set_performing_action(Some(action));
                    let geometry = view.get_geometry()
                        .expect("Could not get geometry of the view");
                    let halfw = geometry.origin.x + geometry.size.w as i32 / 2;
                    let halfh = geometry.origin.y + geometry.size.h as i32 / 2;

                    {
                        let mut action: Action = try_lock_action().ok().and_then(|guard| *guard)
                            .unwrap_or(Action {
                                view: view,
                                grab: point,
                                edges: ResizeEdge::empty()
                            });
                        let flag_x = if point.x < halfw {
                            RESIZE_LEFT
                        } else if point.x > halfw {
                            RESIZE_RIGHT
                        } else {
                            ResizeEdge::empty()
                        };

                        let flag_y = if point.y < halfh {
                            RESIZE_TOP
                        } else if point.y > halfh {
                            RESIZE_BOTTOM
                        } else {
                            ResizeEdge::empty()
                        };

                        action.edges = flag_x | flag_y;
                        set_performing_action(Some(action));
                    }
                    view.set_state(VIEW_RESIZING, true);
                    return EVENT_BLOCKED
                }
            }
        } else {
            if let Ok(lock) = try_lock_action() {
                match *lock {
                    Some(action) => {
                        let view = action.view;
                        if view.get_state().contains(VIEW_RESIZING) {
                            view.set_state(VIEW_RESIZING, false);
                        }
                    },
                    _ => {}
                }
            }
            set_performing_action(None);
        }
        EVENT_PASS_THROUGH
    }

    fn on_pointer_scroll(&mut self, _view: WlcView, _time: u32,
                            _mods_ptr: KeyboardModifiers, _axis: ScrollAxis,
                            _heights: [f64; 2]) -> bool {
        EVENT_PASS_THROUGH
    }

    fn on_pointer_motion(&mut self, view: WlcView, _time: u32, point: Point) -> bool {
        let mut result = EVENT_PASS_THROUGH;
        let mut maybe_action = None;
        {
            if let Ok(action_lock) = try_lock_action() {
                maybe_action = action_lock.clone();
            }
        }
        match maybe_action {
            None => result = EVENT_PASS_THROUGH,
            Some(action) => {
                if action.edges.bits() != 0 {
                    if let Ok(mut tree) = try_lock_tree() {
                        if let Ok(active_id) = tree.lookup_handle(view.into()) {
                            match tree.resize_container(active_id, action.edges, point) {
                                // Return early here to not set the pointer
                                Ok(_) => return EVENT_BLOCKED,
                                Err(err) => warn!("Could not resize: {:#?}", err)
                            }
                        }
                    }
                } else {
                    if let Ok(mut tree) = try_lock_tree() {
                        match tree.try_drag_active(point) {
                            Ok(_) => result = EVENT_BLOCKED,
                            Err(TreeError::PerformingAction(_)) |
                            Err(TreeError::Movement(MovementError::NotFloating(_))) =>
                                result = EVENT_PASS_THROUGH,
                            Err(err) => {
                                warn!("Unexpected drarg error: {:#?}", err);
                                result = EVENT_PASS_THROUGH
                            }
                        }
                    }
                }
            }
        }
        pointer::set_position(point);
        result
    }

    fn view_pre_render(&mut self, view: WlcView) {
        if let Ok(mut tree) = lock_tree() {
            tree.render_borders(view).unwrap_or_else(|err| {
                match err {
                    // TODO Only filter if background or bar
                    TreeError::ViewNotFound(_) => {},
                    err => warn!("Error while rendering borders: {:?}", err)
                }
            })
        }
    }
}
<commit_msg>Moved check inside of fetch pixel logic<commit_after>//! Implementations of the default callbacks exposed by wlc.
//! These functions are the main entry points into Way Cooler from user action.
//! This is the default mode that Way Cooler is in at initilization
use rustwlc::*;
use rustwlc::input::{pointer, keyboard};
use rustwlc::render::{read_pixels, wlc_pixel_format};
use uuid::Uuid;

use super::{EVENT_BLOCKED, EVENT_PASS_THROUGH, LEFT_CLICK, RIGHT_CLICK};
use ::keys::{self, KeyPress, KeyEvent};
use ::layout::{lock_tree, try_lock_tree, try_lock_action, Action, ContainerType,
                    MovementError, TreeError, FocusError};
use ::layout::commands::set_performing_action;
use ::layout::MIN_SIZE;
use ::lua::{self, LuaQuery};

use ::render::screen_scrape::{read_screen_scrape_lock, scraped_pixels_lock,
                              sync_scrape};

use registry::{self};
use super::Mode;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Default;

#[allow(unused)]
impl Mode for Default {
    fn output_created(&mut self, output: WlcOutput) -> bool {
        if let Ok(mut tree) = try_lock_tree() {
            let result = tree.add_output(output).and_then(|_|{
                tree.switch_to_workspace(&"1")
                    .map(|_| tree.layout_active_of(ContainerType::Output))
            });
            match result {
                // If the output exists, we just couldn't add it to the tree because
                // it's already there. That's OK
                Ok(_) | Err(TreeError::OutputExists(_)) => true,
                _ => false
            }
        } else {
            false
        }
    }

    fn output_destroyed(&mut self, output: WlcOutput) {
         // TODO Redistribute workspaces of that output.
    }

    fn output_focused(&mut self, output: WlcOutput, focused: bool) {
         // TODO Ensure focused on right workspace
    }

    fn output_resolution(&mut self, output: WlcOutput,
                                    old_size_ptr: Size, new_size_ptr: Size) {
        // Update the resolution of the output and its children
        let scale = 1;
        output.set_resolution(new_size_ptr, scale);
        if let Ok(mut tree) = try_lock_tree() {
            tree.layout_active_of(ContainerType::Output)
                .expect("Could not layout active output");
        }
    }

    fn output_render_post(&mut self, output: WlcOutput) {
        let need_to_fetch = read_screen_scrape_lock();
        if *need_to_fetch {
            if WlcOutput::focused() != output {
                return
            }
            if let Ok(mut scraped_pixels) = scraped_pixels_lock() {
                let resolution = output.get_resolution()
                    .expect("Output had no resolution");
                let geo = Geometry {
                    origin: Point { x: 0, y: 0 },
                    size: resolution
                };
                let result = read_pixels(wlc_pixel_format::WLC_RGBA8888, geo).1;
                *scraped_pixels = result;
                sync_scrape();
            }
        }
    }

    fn view_created(&mut self, view: WlcView) -> bool {
        let lock = registry::clients_read();
        let client = lock.client(Uuid::nil()).unwrap();
        let handle = registry::ReadHandle::new(&client);
        let bar = handle.read("programs".into())
            .expect("programs category didn't exist")
            .get("x11_bar".into())
            .and_then(|data| data.as_string().map(str::to_string));
        // TODO Move this hack, probably could live somewhere else
        if let Some(bar_name) = bar {
            if view.get_title().as_str() == bar_name {
                view.set_mask(1);
                view.bring_to_front();
                if let Ok(mut tree) = try_lock_tree() {
                    for output in WlcOutput::list() {
                        tree.add_bar(view, output).unwrap_or_else(|_| {
                            warn!("Could not add bar {:#?} to output {:#?}", view, output);
                        });
                    }
                    return true;
                }
            }
        }
        // TODO Remove this hack
        if view.get_class().as_str() == "Background" {
            trace!("Setting background: {}", view.get_title());
            view.send_to_back();
            view.set_mask(1);
            let output = view.get_output();
            let resolution = output.get_resolution()
                .expect("Couldn't get output resolution");
            let fullscreen = Geometry {
                origin: Point { x: 0, y: 0 },
                size: resolution
            };
            view.set_geometry(ResizeEdge::empty(), fullscreen);
            if let Ok(mut tree) = lock_tree() {
                let output = tree.outputs()[0];
                return tree.add_background(view, output).map(|_| true)
                    .unwrap_or_else(|err| {
                        warn!("Could not add background due to {:?}", err);
                        true
                    })
            } else {
                warn!("Could not lock tree to place background");
            }
            return false
        }
        if let Ok(mut tree) = lock_tree() {
            let result = tree.add_view(view).and_then(|_| {
                view.set_state(VIEW_MAXIMIZED, true);
                match tree.set_active_view(view) {
                    // If blocked by fullscreen, we don't focus on purpose
                    Err(TreeError::Focus(FocusError::BlockedByFullscreen(_, _))) => Ok(()),
                    result => result
                }
            });
            if result.is_err() {
                warn!("Could not add {:?}. Reason: {:?}", view, result);
            }
            result.is_ok()
        } else {
            false
        }
    }

    fn view_destroyed(&mut self, view: WlcView) {
        match try_lock_tree() {
            Ok(mut tree) => {
                tree.remove_view(view).unwrap_or_else(|err| {
                    match err {
                        TreeError::ViewNotFound(_) => {},
                        _ => {
                            warn!("Error in view_destroyed: {:?}", err);
                        }
                    }});
            },
            Err(err) => warn!("Could not delete view {:?}, {:?}", view, err)
        }
    }

    fn view_focused(&mut self, current: WlcView, focused: bool) {
        current.set_state(VIEW_ACTIVATED, focused);
        if let Ok(mut tree) = try_lock_tree() {
            match tree.set_active_view(current) {
                Ok(_) => {},
                Err(err) => {
                    warn!("Could not set {:?} to be active view: {:?}", current, err);
                }
            }
        }
    }

    fn view_props_changed(&mut self, view: WlcView, prop: ViewPropertyType) {
        if prop.contains(PROPERTY_TITLE) {
            if let Ok(mut tree) = try_lock_tree() {
                match tree.update_title(view) {
                    Ok(_) => {},
                    Err(err) => {
                        warn!("Could not update title for view {:?} because {:#?}",
                            view, err);
                    }
                }
            }
        }
    }

    fn view_moved_to_output(&mut self, view: WlcView, o1: WlcOutput, o2: WlcOutput) {
        // TODO Ensure in correct workspace
    }

    fn view_request_state(&mut self, view: WlcView, state: ViewState, toggle: bool) {
        if state == VIEW_FULLSCREEN {
            if let Ok(mut tree) = try_lock_tree() {
                if let Ok(id) = tree.lookup_handle(view.into()) {
                    tree.set_fullscreen(id, toggle)
                        .expect("The ID was related to a non-view, somehow!");
                    match tree.container_in_active_workspace(id) {
                        Ok(true) => {
                            tree.layout_active_of(ContainerType::Workspace)
                                .unwrap_or_else(|err| {
                                    warn!("Could not layout active workspace \
                                           for view {:?}: {:?}",
                                            view, err)
                                });
                        },
                        Ok(false) => {},
                        Err(err) => warn!("Could not set {:?} fullscreen: {:?}",
                                           view, err)
                    }
                } else {
                    warn!("Could not find view {:?} in tree", view);
                }
            }
        }
    }

    fn view_request_move(&mut self, view: WlcView, _dest: Point) {
        if let Ok(mut tree) = try_lock_tree() {
            if let Err(err) = tree.set_active_view(view) {
                warn!("view_request_move error: {:?}", err);
            }
        }
    }

    fn view_request_resize(&mut self, view: WlcView, edge: ResizeEdge, point: Point) {
        if let Ok(mut tree) = try_lock_tree() {
            let in_action = try_lock_action()
                .map(|action| action.is_some())
                .unwrap_or(false);
            if in_action {
                if let Ok(id) = tree.lookup_handle(view.into()) {
                    if let Err(err) = tree.resize_container(id, edge, point) {
                        warn!("resize_container returned error: {:#?}",
                                err);
                    }
                }
            }
        }
    }

    fn on_keyboard_key(&mut self, _view: WlcView, _time: u32, mods: KeyboardModifiers,
                            key: u32, state: KeyState) -> bool {
        let empty_mods: KeyboardModifiers = KeyboardModifiers {
                mods: MOD_NONE,
                leds: KeyboardLed::empty()
        };
        let sym = keyboard::get_keysym_for_key(key, empty_mods);
        let press = KeyPress::new(mods.mods, sym);

        if state == KeyState::Pressed {
            if let Some(key) = keys::get(&press) {
                info!("[key] Found an action for {}, blocking event", press);
                let action = key.event;
                let passthrough = key.passthrough;
                match action {
                    KeyEvent::Command(func) => {
                        func();
                    },
                    KeyEvent::Lua => {
                        match lua::send(LuaQuery::HandleKey(press)) {
                            Ok(_) => {},
                            Err(err) => {
                                // We may want to wait for Lua's reply from
                                // keypresses; for example if the table is tampered
                                // with or Lua is restarted or Lua has an error.
                                // ATM Lua asynchronously logs this but in the future
                                // an error popup/etc is a good idea.
                                warn!("Error sending keypress: {:?}", err);
                            }
                        }
                    }
                }
                return !passthrough
            }
        }

        return EVENT_PASS_THROUGH
    }

    fn view_request_geometry(&mut self, view: WlcView, geometry: Geometry) {
        if geometry.size.w < MIN_SIZE.w || geometry.size.h < MIN_SIZE.h {
            warn!("Ignoring requested geometry {:#?}, which is below min {:#?}",
                  geometry, MIN_SIZE);
            return;
        }
        if let Ok(mut tree) = try_lock_tree() {
            match tree.update_floating_geometry(view, geometry) {
                Ok(()) | Err(TreeError::ViewNotFound(_)) => {},
                err => warn!("Could not find view {:#?} \
                              in order to update geometry w/ {:#?} \
                              because of {:#?}",
                             view, geometry, err)
            }
        }
    }

    fn on_pointer_button(&mut self, view: WlcView, _time: u32,
                            mods: KeyboardModifiers, button: u32,
                                state: ButtonState, point: Point) -> bool {
        if state == ButtonState::Pressed {
            let mouse_mod = keys::mouse_modifier();
            if button == LEFT_CLICK && !view.is_root() {
                if let Ok(mut tree) = try_lock_tree() {
                    tree.set_active_view(view).unwrap_or_else(|_| {
                        // still focus on view, even if not in tree.
                        view.focus();
                    });
                    if mods.mods.contains(mouse_mod) {
                        let action = Action {
                            view: view,
                            grab: point,
                            edges: ResizeEdge::empty()
                        };
                        set_performing_action(Some(action));
                    }
                }
            } else if button == RIGHT_CLICK && !view.is_root() {
                info!("User right clicked w/ mods \"{:?}\" on {:?}", mods, view);
                if let Ok(mut tree) = try_lock_tree() {
                    tree.set_active_view(view).ok();
                }
                if mods.mods.contains(mouse_mod) {
                    let action = Action {
                        view: view,
                        grab: point,
                        edges: ResizeEdge::empty()
                    };
                    set_performing_action(Some(action));
                    let geometry = view.get_geometry()
                        .expect("Could not get geometry of the view");
                    let halfw = geometry.origin.x + geometry.size.w as i32 / 2;
                    let halfh = geometry.origin.y + geometry.size.h as i32 / 2;

                    {
                        let mut action: Action = try_lock_action().ok().and_then(|guard| *guard)
                            .unwrap_or(Action {
                                view: view,
                                grab: point,
                                edges: ResizeEdge::empty()
                            });
                        let flag_x = if point.x < halfw {
                            RESIZE_LEFT
                        } else if point.x > halfw {
                            RESIZE_RIGHT
                        } else {
                            ResizeEdge::empty()
                        };

                        let flag_y = if point.y < halfh {
                            RESIZE_TOP
                        } else if point.y > halfh {
                            RESIZE_BOTTOM
                        } else {
                            ResizeEdge::empty()
                        };

                        action.edges = flag_x | flag_y;
                        set_performing_action(Some(action));
                    }
                    view.set_state(VIEW_RESIZING, true);
                    return EVENT_BLOCKED
                }
            }
        } else {
            if let Ok(lock) = try_lock_action() {
                match *lock {
                    Some(action) => {
                        let view = action.view;
                        if view.get_state().contains(VIEW_RESIZING) {
                            view.set_state(VIEW_RESIZING, false);
                        }
                    },
                    _ => {}
                }
            }
            set_performing_action(None);
        }
        EVENT_PASS_THROUGH
    }

    fn on_pointer_scroll(&mut self, _view: WlcView, _time: u32,
                            _mods_ptr: KeyboardModifiers, _axis: ScrollAxis,
                            _heights: [f64; 2]) -> bool {
        EVENT_PASS_THROUGH
    }

    fn on_pointer_motion(&mut self, view: WlcView, _time: u32, point: Point) -> bool {
        let mut result = EVENT_PASS_THROUGH;
        let mut maybe_action = None;
        {
            if let Ok(action_lock) = try_lock_action() {
                maybe_action = action_lock.clone();
            }
        }
        match maybe_action {
            None => result = EVENT_PASS_THROUGH,
            Some(action) => {
                if action.edges.bits() != 0 {
                    if let Ok(mut tree) = try_lock_tree() {
                        if let Ok(active_id) = tree.lookup_handle(view.into()) {
                            match tree.resize_container(active_id, action.edges, point) {
                                // Return early here to not set the pointer
                                Ok(_) => return EVENT_BLOCKED,
                                Err(err) => warn!("Could not resize: {:#?}", err)
                            }
                        }
                    }
                } else {
                    if let Ok(mut tree) = try_lock_tree() {
                        match tree.try_drag_active(point) {
                            Ok(_) => result = EVENT_BLOCKED,
                            Err(TreeError::PerformingAction(_)) |
                            Err(TreeError::Movement(MovementError::NotFloating(_))) =>
                                result = EVENT_PASS_THROUGH,
                            Err(err) => {
                                warn!("Unexpected drarg error: {:#?}", err);
                                result = EVENT_PASS_THROUGH
                            }
                        }
                    }
                }
            }
        }
        pointer::set_position(point);
        result
    }

    fn view_pre_render(&mut self, view: WlcView) {
        if let Ok(mut tree) = lock_tree() {
            tree.render_borders(view).unwrap_or_else(|err| {
                match err {
                    // TODO Only filter if background or bar
                    TreeError::ViewNotFound(_) => {},
                    err => warn!("Error while rendering borders: {:?}", err)
                }
            })
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 Chao Lin & William Sergeant (Sorbonne University)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

pub use self::unreachable_rule::*;

grammar! unreachable_rule{
    // test0 =  "a"*
    //         /"a"+  // is detected

    test1 =  "a"
            /"ab"

    test2 =  "ab"
            /"a"

    test3 =  "a"
            /"a"

    test4 =  "abcd"
            /"a" "bc"

    test4bis = "a" "bc"
             / "abcd"

    keyword = "proc"/"par"/"space"/"end"/"pre"
         / "read" / "write" / "readwrite" / "or" / "and" / "not"
         / "when" / "then" / "else" / "loop" / "pause up"
         / "pause" / "stop" / "in" / "word_line" / "singe_time"
         / "single_space" / "bot" / "top" / "ref" / "module"
         / "run" / "true" / "false" / "unknown" / "nothing"
         / "universe" / "suspend" / "abort" / "java_kw"

    // test5 =  "a"*
    //         /"a"?  // is detected

    // test6 =  "a"
    //         /!"a"
    //
    // test7 = !"a"
    //         /"a"
    //
    // test8 =  "a" !"a"
    //         /"a"
    //
    // test9 = "a"
    //         /&"a"
    //
    // test10 = &"a"
    //         /"a"
    //
    // test11 = "b"
    //         /!"a"

    // test12 = .
    //         /"a" // is detected
}
<commit_msg>[tests] Add tests for character class in unreachable rule<commit_after>// Copyright 2018 Chao Lin & William Sergeant (Sorbonne University)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

pub use self::unreachable_rule::*;

grammar! unreachable_rule{
    // test0 =  "a"*
    //         /"a"+  // is detected

    // test1 =  "a"
    //         /"ab"
    //
    test2 =  "ab"
            / "a"
    // r1 = ["a-c"] -> () / "b" -> () // problem of span
    //
    // test3 =  "a"
    //         /"a"
    //
    // test4 =  "abcd"
    //         /"a" "bc"
    //
    // test4bis = "a" "bc"
    //          / "abcd"

    // keyword = "proc"/"par"/"space"/"end"/"pre"
    //      / "read" / "write" / "readwrite" / "or" / "and" / "not"
    //      / "when" / "then" / "else" / "loop" / "pause up"
    //      / "pause" / "stop" / "in" / "word_line" / "singe_time"
    //      / "single_space" / "bot" / "top" / "ref" / "module"
    //      / "run" / "true" / "false" / "unknown" / "nothing"
    //      / "universe" / "suspend" / "abort" / "java_kw"

    // test5 =  "a"*
    //         /"a"?  // is detected

    // test6 =  "a"
    //         /!"a"
    //
    // test7 = !"a"
    //         /"a"
    //
    // test8 =  "a" !"a"
    //         /"a"
    //
    // test9 = "a"
    //         /&"a"
    //
    // test10 = &"a"
    //         /"a"
    //
    // test11 = "b"
    //         /!"a"

    // test12 = .
    //         /"a" // is detected
}
<|endoftext|>


<commit_before>use CL::*;
use CL::ll::*;
use hl;
use hl::*;
use error::check;
use std::sys;
use std::libc;
use std::ptr;
use std::vec;
use std::cast;

struct Vector<T> {
    cl_buffer: cl_mem,
    size:      uint,
    context:   @ComputeContext,
}

#[unsafe_destructor]
impl<T> Drop for Vector<T>
{
    #[fixed_stack_segment] #[inline(never)]
    fn drop(&mut self)
    { unsafe { clReleaseMemObject(self.cl_buffer); } }
}

impl<T> Vector<T> {
    #[fixed_stack_segment] #[inline(never)]
    pub fn from_vec(ctx: @ComputeContext, v: &[T]) -> Vector<T> {
        unsafe {
            do v.as_imm_buf |p, len| {
                let status = 0;
                let byte_size = (len * sys::size_of::<T>()) as libc::size_t;

                let buf = clCreateBuffer(ctx.ctx.ctx,
                CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR,
                byte_size,
                p as *libc::c_void,
                ptr::to_unsafe_ptr(&status));
                check(status, "Could not allocate buffer");

                //let status = clEnqueueWriteBuffer(
                //    ctx.q, buf, CL_TRUE, 0, byte_size, p as *libc::c_void,
                //    0, ptr::null(), ptr::null());

                Vector {
                    cl_buffer: buf,
                    size:      len,
                    context:   ctx,
                }
            }
        }
    }

    #[fixed_stack_segment] #[inline(never)]
    pub fn rewrite(&mut self, v: &[T]) {
        if self.size < v.len() {
            fail!("Cannot copy cpu buffer on a smaller gpu buffer.")
        }

        unsafe {
            do v.as_imm_buf |p, len|
            {
                let byte_size = (len * sys::size_of::<T>()) as libc::size_t;

                let status = clEnqueueWriteBuffer(
                    self.context.q.cqueue, self.cl_buffer, CL_TRUE, 0, byte_size, p as *libc::c_void,
                    0, ptr::null(), ptr::null());

                check(status, "Could not write buffer");
            }
        }
    }

    pub fn to_vec(self) -> ~[T] {
        unsafe {
            let mut result = ~[];
            result.reserve(self.size);
            vec::raw::set_len(&mut result, self.size);

            self.to_existing_vec(result);

            result
        }
    }

    #[fixed_stack_segment] #[inline(never)]
    pub fn to_existing_vec(&self, out: &mut [T]) {
        if out.len() < self.size {
            fail!("Cannot copy gpu buffer on a smaller cpu buffer.")
        }

        unsafe {
            do out.as_imm_buf |p, len| {
                clEnqueueReadBuffer(
                    self.context.q.cqueue, self.cl_buffer, CL_TRUE, 0,
                    (len * sys::size_of::<T>()) as libc::size_t,
                    p as *libc::c_void, 0, ptr::null(), ptr::null());
            }
        }
    }
}

impl<T> hl::KernelArg for Vector<T>
{
    fn get_value(&self) -> (libc::size_t, *libc::c_void) {
        (sys::size_of::<cl_mem>() as libc::size_t,
         ptr::to_unsafe_ptr(&self.cl_buffer) as *libc::c_void)
    }
}

struct CLBuffer {
    cl_buffer: cl_mem
}

pub struct Unique<T> {
    cl_buffer: CLBuffer,
    size: uint,
    context: @ComputeContext,
}

impl Drop for CLBuffer {
    #[fixed_stack_segment] #[inline(never)]
    fn drop(&mut self) {
        unsafe {
            clReleaseMemObject(self.cl_buffer);
        }
    }
}

impl<T> Unique<T> {
    #[fixed_stack_segment] #[inline(never)]
    pub fn from_vec(ctx: @ComputeContext, v: ~[T]) -> Unique<T> {
        unsafe
        {
            let byte_size
                = 6 * sys::size_of::<uint>()
                + v.len() * sys::size_of::<T>();
            let byte_size = byte_size as libc::size_t;

            let len = v.len();

            let addr: *libc::c_void = cast::transmute_copy(&v);

            let status = 0;
            let buf = clCreateBuffer(ctx.ctx.ctx,
                                     CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR,
                                     byte_size,
                                     addr,
                                     ptr::to_unsafe_ptr(&status));
            check(status, "Could not allocate buffer");

            Unique {
                cl_buffer: CLBuffer { cl_buffer: buf },
                size: len,
                context: ctx,
            }
        }
    }

    #[fixed_stack_segment] #[inline(never)]
    pub fn to_vec(self) -> ~[T] {
        unsafe {
            let mut result = ~[];
            result.reserve(self.size);
            vec::raw::set_len(&mut result, self.size);
            do result.as_imm_buf |p, len| {
                clEnqueueReadBuffer(
                    self.context.q.cqueue, self.cl_buffer.cl_buffer, CL_TRUE,
                    // Skip the header, we have a new one here.
                    (6 * sys::size_of::<uint>()) as libc::size_t,
                    (len * sys::size_of::<T>()) as libc::size_t,
                    p as *libc::c_void, 0, ptr::null(), ptr::null());

            }
            result
        } }

}

impl<T> ::hl::KernelArg for Unique<T> {
    fn get_value(&self) -> (libc::size_t, *libc::c_void) {
        (sys::size_of::<cl_mem>() as libc::size_t,
         ptr::to_unsafe_ptr(&self.cl_buffer) as *libc::c_void)
    }
}

#[cfg(test)]
mod test {
  use hl::*;
  use vector::*;

  macro_rules! expect (
      ($test: expr, $expected: expr) => ({
          let test = $test;
          let expected = $expected;
          if test != expected {
              fail!(fmt!("Test failure in %s: expected %?, got %?",
                         stringify!($test),
                         expected, test))
          }
      })
  )

    #[test]
    fn unique_vector() {
        let ctx = create_compute_context();

        let x = ~[1, 2, 3, 4, 5];
        let gx = Unique::from_vec(ctx, x.clone());
        let y = gx.to_vec();
        expect!(y, x);
    }

  #[test]
  fn gpu_vector() {
      let ctx = create_compute_context();

      let x = ~[1, 2, 3, 4, 5];
      let gx = Vector::from_vec(ctx, x);
      let y = gx.to_vec();
      expect!(x, y);
  }
}
<commit_msg>Fixed unit tests for Unique.<commit_after>use CL::*;
use CL::ll::*;
use hl;
use hl::*;
use error::check;
use std::sys;
use std::libc;
use std::ptr;
use std::vec;
use std::cast;
use std::unstable;

struct Vector<T> {
    cl_buffer: cl_mem,
    size:      uint,
    context:   @ComputeContext,
}

#[unsafe_destructor]
impl<T> Drop for Vector<T>
{
    #[fixed_stack_segment] #[inline(never)]
    fn drop(&mut self)
    { unsafe { clReleaseMemObject(self.cl_buffer); } }
}

impl<T> Vector<T> {
    #[fixed_stack_segment] #[inline(never)]
    pub fn from_vec(ctx: @ComputeContext, v: &[T]) -> Vector<T> {
        unsafe {
            do v.as_imm_buf |p, len| {
                let status = 0;
                let byte_size = (len * sys::size_of::<T>()) as libc::size_t;

                let buf = clCreateBuffer(ctx.ctx.ctx,
                CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR,
                byte_size,
                p as *libc::c_void,
                ptr::to_unsafe_ptr(&status));
                check(status, "Could not allocate buffer");

                //let status = clEnqueueWriteBuffer(
                //    ctx.q, buf, CL_TRUE, 0, byte_size, p as *libc::c_void,
                //    0, ptr::null(), ptr::null());

                Vector {
                    cl_buffer: buf,
                    size:      len,
                    context:   ctx,
                }
            }
        }
    }

    #[fixed_stack_segment] #[inline(never)]
    pub fn rewrite(&mut self, v: &[T]) {
        if self.size < v.len() {
            fail!("Cannot copy cpu buffer on a smaller gpu buffer.")
        }

        unsafe {
            do v.as_imm_buf |p, len|
            {
                let byte_size = (len * sys::size_of::<T>()) as libc::size_t;

                let status = clEnqueueWriteBuffer(
                    self.context.q.cqueue, self.cl_buffer, CL_TRUE, 0, byte_size, p as *libc::c_void,
                    0, ptr::null(), ptr::null());

                check(status, "Could not write buffer");
            }
        }
    }

    pub fn to_vec(self) -> ~[T] {
        unsafe {
            let mut result = ~[];
            result.reserve(self.size);
            vec::raw::set_len(&mut result, self.size);

            self.to_existing_vec(result);

            result
        }
    }

    #[fixed_stack_segment] #[inline(never)]
    pub fn to_existing_vec(&self, out: &mut [T]) {
        if out.len() < self.size {
            fail!("Cannot copy gpu buffer on a smaller cpu buffer.")
        }

        unsafe {
            do out.as_imm_buf |p, len| {
                clEnqueueReadBuffer(
                    self.context.q.cqueue, self.cl_buffer, CL_TRUE, 0,
                    (len * sys::size_of::<T>()) as libc::size_t,
                    p as *libc::c_void, 0, ptr::null(), ptr::null());
            }
        }
    }
}

impl<T> hl::KernelArg for Vector<T>
{
    fn get_value(&self) -> (libc::size_t, *libc::c_void) {
        (sys::size_of::<cl_mem>() as libc::size_t,
         ptr::to_unsafe_ptr(&self.cl_buffer) as *libc::c_void)
    }
}

struct CLBuffer {
    cl_buffer: cl_mem
}

pub struct Unique<T> {
    cl_buffer: CLBuffer,
    size: uint,
    context: @ComputeContext,
}

impl Drop for CLBuffer {
    #[fixed_stack_segment] #[inline(never)]
    fn drop(&mut self) {
        unsafe {
            clReleaseMemObject(self.cl_buffer);
        }
    }
}

impl<T> Unique<T> {
    #[fixed_stack_segment] #[inline(never)]
    pub fn from_vec(ctx: @ComputeContext, v: ~[T]) -> Unique<T> {
        unsafe
        {
            let byte_size
                = sys::size_of::<unstable::raw::Vec<T>>()
                - sys::size_of::<T>()
                + v.len() * sys::size_of::<T>();
            let byte_size = byte_size as libc::size_t;

            let len = v.len();

            let addr: *libc::c_void = cast::transmute_copy(&v);

            let status = 0;
            let buf = clCreateBuffer(ctx.ctx.ctx,
                                     CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR,
                                     byte_size,
                                     addr,
                                     ptr::to_unsafe_ptr(&status));
            check(status, "Could not allocate buffer");

            Unique {
                cl_buffer: CLBuffer { cl_buffer: buf },
                size: len,
                context: ctx,
            }
        }
    }

    #[fixed_stack_segment] #[inline(never)]
    pub fn to_vec(self) -> ~[T] {
        unsafe {
            let mut result = ~[];
            result.reserve(self.size);
            vec::raw::set_len(&mut result, self.size);
            do result.as_imm_buf |p, len| {
                clEnqueueReadBuffer(
                    self.context.q.cqueue, self.cl_buffer.cl_buffer, CL_TRUE,
                    // Skip the header, we have a new one here.
                    (sys::size_of::<unstable::raw::Vec<T>>() - sys::size_of::<T>())  as libc::size_t,
                    (len * sys::size_of::<T>()) as libc::size_t,
                    p as *libc::c_void, 0, ptr::null(), ptr::null());

            }
            result
        } }

}

impl<T> ::hl::KernelArg for Unique<T> {
    fn get_value(&self) -> (libc::size_t, *libc::c_void) {
        (sys::size_of::<cl_mem>() as libc::size_t,
         ptr::to_unsafe_ptr(&self.cl_buffer) as *libc::c_void)
    }
}

#[cfg(test)]
mod test {
  use hl::*;
  use vector::*;

  macro_rules! expect (
      ($test: expr, $expected: expr) => ({
          let test = $test;
          let expected = $expected;
          if test != expected {
              fail!(fmt!("Test failure in %s: expected %?, got %?",
                         stringify!($test),
                         expected, test))
          }
      })
  )

    #[test]
    fn unique_vector() {
        let ctx = create_compute_context();

        let x = ~[1, 2, 3, 4, 5, 6];
        let gx = Unique::from_vec(ctx, x.clone());
        let y = gx.to_vec();
        expect!(y, x);
    }

  #[test]
  fn gpu_vector() {
      let ctx = create_compute_context();

      let x = ~[1, 2, 3, 4, 5];
      let gx = Vector::from_vec(ctx, x);
      let y = gx.to_vec();
      expect!(x, y);
  }
}
<|endoftext|>