<commit_before>// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(std_misc, core, old_path)]

extern crate csv;
extern crate string_cache;
extern crate "rustc-serialize" as rustc_serialize;

use string_cache::Atom;
use string_cache::atom::repr;

use std::{env, cmp};
use std::num::FromPrimitive;
use std::collections::hash_map::{HashMap, Entry};

#[derive(RustcDecodable, Debug)]
struct Event {
    event: String,
    id: u64,
    string: Option<String>,
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, FromPrimitive)]
#[repr(u8)]
enum Kind {
    Dynamic,
    Inline,
    Static,
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
struct Summary {
    kind: Kind,
    times: usize,
}

fn main() {
    let filename = env::args().skip(1).next()
        .expect("Usage: string-cache-summarize-events foo.csv");
    let path = &Path::new(filename);
    let mut file = csv::Reader::from_file(path).unwrap();

    // Over the lifetime of a program, one dynamic atom might get interned at
    // several addresses, and one address may be used to intern several
    // different strings.  For this reason we must separately track the
    // currently-allocated atoms and the summary of all atoms ever created.
    let mut dynamic: HashMap<u64, String> = HashMap::new();
    let mut peak_dynamic = 0;
    let mut summary: HashMap<String, Summary> = HashMap::new();
    let mut inserts = 0;

    for record in file.decode() {
        let ev: Event = record.unwrap();
        match &ev.event[..] {
            "intern" => {
                let tag = (ev.id & 0xf) as u8;
                assert!(tag <= repr::STATIC_TAG);

                let string = match tag {
                    repr::DYNAMIC_TAG => dynamic[ev.id].clone(),

                    // FIXME: We really shouldn't be allowed to do this. It's a memory-safety
                    // hazard; the field is only public for the atom!() macro.
                    _ => Atom { data: ev.id }.as_slice().to_string(),
                };

                match summary.entry(string) {
                    Entry::Occupied(entry) => entry.into_mut().times += 1,
                    Entry::Vacant(entry) => {
                        entry.insert(Summary {
                            kind: FromPrimitive::from_u8(tag).unwrap(),
                            times: 1,
                        });
                    }
                }
            },

            "insert" => {
                assert!(!dynamic.contains_key(&ev.id));
                dynamic.insert(ev.id, ev.string.expect("no string to insert"));
                peak_dynamic = cmp::max(peak_dynamic, dynamic.len());
                inserts += 1;
            }

            "remove" => {
                assert!(dynamic.contains_key(&ev.id));
                dynamic.remove(&ev.id);
            }

            e => panic!("unknown event {}", e),
        }
    }

    // Get all records, in a stable order.
    let mut summary: Vec<_> = summary.into_iter().collect();
    summary.sort_by(|&(ref a, _), &(ref b, _)| a.cmp(b));

    // Sort by number of occurrences, descending.
    summary.sort_by(|&(_, a), &(_, b)| b.times.cmp(&a.times));
    let longest_atom = summary.iter().map(|&(ref k, _)| k.len())
        .max().unwrap_or(0);

    let pad = |c, n| {
        for _ in range(n, longest_atom) {
            print!("{}", c);
        }
    };

    let mut total = 0;
    let mut by_kind = [0, 0, 0];
    for &(_, Summary { kind, times }) in &summary {
        total += times;
        by_kind[kind as usize] += times;
    }

    println!("\n");
    println!("kind       times   pct");
    println!("-------  -------  ----");
    for (k, &n) in by_kind.iter().enumerate() {
        let k: Kind = FromPrimitive::from_usize(k).unwrap();
        print!("{:7?}  {:7}  {:4.1}",
            k, n, 100.0 * (n as f64) / (total as f64));

        match k {
            Kind::Dynamic => println!("    {} inserts, peak size {}, miss rate {:4.1}%",
                inserts, peak_dynamic, 100.0 * (inserts as f64) / (n as f64)),
            _ => println!(""),
        }
    }
    println!("");
    println!("total    {:7}", total);
    println!("\n");

    pad(' ', 4);
    println!("atom   times  kind");
    pad('-', 4);
    println!("----  ------  -------");
    for (string, Summary { kind, times }) in summary {
        use std::str::StrExt;
        pad(' ', string.chars().count());
        println!("{}  {:6}  {:?}", string, times, kind);
    }
}
<commit_msg>Upgrade examples/summarize-events<commit_after>// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(core)]

extern crate csv;
extern crate string_cache;
extern crate rustc_serialize;

use string_cache::Atom;
use string_cache::atom::repr;

use std::{env, cmp};
use std::num::FromPrimitive;
use std::collections::hash_map::{HashMap, Entry};
use std::path::Path;

#[derive(RustcDecodable, Debug)]
struct Event {
    event: String,
    id: u64,
    string: Option<String>,
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, FromPrimitive)]
#[repr(u8)]
enum Kind {
    Dynamic,
    Inline,
    Static,
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
struct Summary {
    kind: Kind,
    times: usize,
}

fn main() {
    let filename = env::args().skip(1).next()
        .expect("Usage: string-cache-summarize-events foo.csv");
    let path = &Path::new(&filename);
    let mut file = csv::Reader::from_file(path).unwrap();

    // Over the lifetime of a program, one dynamic atom might get interned at
    // several addresses, and one address may be used to intern several
    // different strings.  For this reason we must separately track the
    // currently-allocated atoms and the summary of all atoms ever created.
    let mut dynamic: HashMap<u64, String> = HashMap::new();
    let mut peak_dynamic = 0;
    let mut summary: HashMap<String, Summary> = HashMap::new();
    let mut inserts = 0;

    for record in file.decode() {
        let ev: Event = record.unwrap();
        match &ev.event[..] {
            "intern" => {
                let tag = (ev.id & 0xf) as u8;
                assert!(tag <= repr::STATIC_TAG);

                let string = match tag {
                    repr::DYNAMIC_TAG => dynamic[&ev.id].clone(),

                    // FIXME: We really shouldn't be allowed to do this. It's a memory-safety
                    // hazard; the field is only public for the atom!() macro.
                    _ => Atom { data: ev.id }.as_slice().to_string(),
                };

                match summary.entry(string) {
                    Entry::Occupied(entry) => entry.into_mut().times += 1,
                    Entry::Vacant(entry) => {
                        entry.insert(Summary {
                            kind: FromPrimitive::from_u8(tag).unwrap(),
                            times: 1,
                        });
                    }
                }
            },

            "insert" => {
                assert!(!dynamic.contains_key(&ev.id));
                dynamic.insert(ev.id, ev.string.expect("no string to insert"));
                peak_dynamic = cmp::max(peak_dynamic, dynamic.len());
                inserts += 1;
            }

            "remove" => {
                assert!(dynamic.contains_key(&ev.id));
                dynamic.remove(&ev.id);
            }

            e => panic!("unknown event {}", e),
        }
    }

    // Get all records, in a stable order.
    let mut summary: Vec<_> = summary.into_iter().collect();
    summary.sort_by(|&(ref a, _), &(ref b, _)| a.cmp(b));

    // Sort by number of occurrences, descending.
    summary.sort_by(|&(_, a), &(_, b)| b.times.cmp(&a.times));
    let longest_atom = summary.iter().map(|&(ref k, _)| k.len())
        .max().unwrap_or(0);

    let pad = |c, n| {
        for _ in n..longest_atom {
            print!("{}", c);
        }
    };

    let mut total = 0;
    let mut by_kind = [0, 0, 0];
    for &(_, Summary { kind, times }) in &summary {
        total += times;
        by_kind[kind as usize] += times;
    }

    println!("\n");
    println!("kind       times   pct");
    println!("-------  -------  ----");
    for (k, &n) in by_kind.iter().enumerate() {
        let k: Kind = FromPrimitive::from_usize(k).unwrap();
        print!("{:7?}  {:7}  {:4.1}",
            k, n, 100.0 * (n as f64) / (total as f64));

        match k {
            Kind::Dynamic => println!("    {} inserts, peak size {}, miss rate {:4.1}%",
                inserts, peak_dynamic, 100.0 * (inserts as f64) / (n as f64)),
            _ => println!(""),
        }
    }
    println!("");
    println!("total    {:7}", total);
    println!("\n");

    pad(' ', 4);
    println!("atom   times  kind");
    pad('-', 4);
    println!("----  ------  -------");
    for (string, Summary { kind, times }) in summary {
        pad(' ', string.chars().count());
        println!("{}  {:6}  {:?}", string, times, kind);
    }
}
<|endoftext|>


<commit_before>fn main() {
	// TODO
}

<commit_msg>Fix tabs -> spaces<commit_after>fn main() {
    // TODO
}

<|endoftext|>


<commit_before>use engine::EngineData;
use image_convert::image_to_surface;
use scene::SceneName;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::pixels::{Color, PixelFormatEnum};
use sdl2::rect::{Rect, Point};
use sdl2::render::{WindowCanvas, Texture, TextureCreator};
use sdl2::surface::Surface;
use sdl2::video::WindowContext;
use sdl2_engine_helpers::scene::{Scene, BoxedScene, SceneChangeEvent};
use sdl2_engine_helpers::transform::TransformContext;
use std::fs::File;
use std::io::Result;
use std::path::Path;
use map::{Facet, map_id_to_facet, MAP_DETAILS};
use uorustlibs::map::{Block, StaticLocation};
use uorustlibs::art::{ArtReader, Art};
use caches::art_cache::ArtCache;

const STEP_X: u32 = 1;
const STEP_Y: u32 = 1;
const MAX_BLOCKS_WIDTH: u32 = 6;
const MAX_BLOCKS_HEIGHT: u32 = 6;

pub struct WorldScene<'a> {
    art_cache: ArtCache<'a>,
    facet: Facet,
    map_id: u8,
    exiting: bool,
}

fn cell_at(x: i32, y: i32) -> TransformContext {
    TransformContext::new()
        .transform(
            (22 * 7) + (22 * x) - (y * 22),
            (22 * y) + (x * 22)
        )
}

// TODO: Make this less nasty
fn block_at(x: i32, y: i32) -> TransformContext {
    TransformContext::new()
        .transform(
            (22 * 8) * x - (y * (22 * 8)) + (22 * 16),
            (22 * 8) * y + (x * (22 * 8)) - (22 * 24)
        )
}

impl<'a> WorldScene<'a> {
    pub fn new<'b>(engine_data: &mut EngineData<'b>, texture_creator: &'a TextureCreator<WindowContext>) -> BoxedScene<'a, Event, SceneName, EngineData<'b>> {
        let reader = ArtReader::new(&Path::new("./assets/artidx.mul"), &Path::new("./assets/art.mul")).expect("Could not load art");
        let scene = Box::new(WorldScene {
            exiting: false,
            map_id: 0,
            facet: map_id_to_facet(0),
            art_cache: ArtCache::new(texture_creator),
        });
        scene
    }

    pub fn draw_page(&mut self, renderer: &mut WindowCanvas) {
        self.facet.get_lens(MAX_BLOCKS_WIDTH, MAX_BLOCKS_HEIGHT).map(|lens| {
            for y in 0..lens.height {
                for x in 0..lens.width {
                    let (ref block, ref statics) = lens.blocks[(x + (y * MAX_BLOCKS_WIDTH)) as usize];
                    let transform = block_at(x as i32, y as i32);
                    self.draw_block(renderer, block, statics, &transform);
                }
            }
        });
    }

    pub fn draw_block(&mut self, renderer: &mut WindowCanvas, block: &Option<Block>, statics: &Option<Vec<StaticLocation>>, context: &TransformContext){
        block.map(|block| {
            for y in 0..8 {
                for x in 0..8 {
                    let cell = block.cells[y * 8 + x];
                    self.art_cache.read_tile(cell.graphic as u32).as_ref().map(|tile| {
                        let query = tile.query();
                        let new_context = cell_at(x as i32, y as i32).merge(context);
                        new_context.copy(renderer, &tile, None, Rect::new(0, 0, query.width, query.height));
                    });
                }
            }
        });
    }

}

impl<'a, 'b> Scene<Event, SceneName, EngineData<'b>> for WorldScene<'a> {
    fn render(&mut self, renderer: &mut WindowCanvas, _engine_data: &mut EngineData, _tick: u64) {
        renderer.clear();
        self.draw_page(renderer);
        renderer.present();
    }

    fn handle_event(&mut self, event: &Event, engine_data: &mut EngineData, _tick: u64) {
        match *event {
            Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                self.exiting = true
            },
            Event::KeyDown { keycode: Some(Keycode::Left), .. } => {
                if self.facet.x >= STEP_X as u32 {
                    self.facet.x -= STEP_X as u32;
                }
            },
            Event::KeyDown { keycode: Some(Keycode::Right), .. } => {
                self.facet.x += STEP_X as u32;
            },
            Event::KeyDown { keycode: Some(Keycode::Up), .. } => {
                if self.facet.y >= STEP_Y as u32 {
                    self.facet.y -= STEP_Y as u32;
                }
            },
            Event::KeyDown { keycode: Some(Keycode::Down), .. } => {
                self.facet.y += STEP_Y as u32;
            },
            Event::KeyDown { keycode: Some(Keycode::Tab), .. } => {
                self.map_id = (self.map_id + 1) % MAP_DETAILS.len() as u8;
                self.facet = map_id_to_facet(self.map_id);
            },
             _ => ()
        }
    }

    fn think(&mut self, _engine_data: &mut EngineData, _tick: u64) -> Option<SceneChangeEvent<SceneName>> {
        if self.exiting {
            Some(SceneChangeEvent::PopScene)
        } else {
            None
        }
    }
}
<commit_msg>Tile heights<commit_after>use engine::EngineData;
use image_convert::image_to_surface;
use scene::SceneName;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::pixels::{Color, PixelFormatEnum};
use sdl2::rect::{Rect, Point};
use sdl2::render::{WindowCanvas, Texture, TextureCreator};
use sdl2::surface::Surface;
use sdl2::video::WindowContext;
use sdl2_engine_helpers::scene::{Scene, BoxedScene, SceneChangeEvent};
use sdl2_engine_helpers::transform::TransformContext;
use std::fs::File;
use std::io::Result;
use std::path::Path;
use map::{Facet, map_id_to_facet, MAP_DETAILS};
use uorustlibs::map::{Block, StaticLocation};
use uorustlibs::art::{ArtReader, Art};
use caches::art_cache::ArtCache;

const STEP_X: u32 = 1;
const STEP_Y: u32 = 1;
const MAX_BLOCKS_WIDTH: u32 = 6;
const MAX_BLOCKS_HEIGHT: u32 = 6;

pub struct WorldScene<'a> {
    art_cache: ArtCache<'a>,
    facet: Facet,
    map_id: u8,
    exiting: bool,
}

fn cell_at(x: i32, y: i32) -> TransformContext {
    TransformContext::new()
        .transform(
            (22 * 7) + (22 * x) - (y * 22),
            (22 * y) + (x * 22)
        )
}

// TODO: Make this less nasty
fn block_at(x: i32, y: i32) -> TransformContext {
    TransformContext::new()
        .transform(
            (22 * 8) * x - (y * (22 * 8)) + (22 * 16),
            (22 * 8) * y + (x * (22 * 8)) - (22 * 24)
        )
}

impl<'a> WorldScene<'a> {
    pub fn new<'b>(engine_data: &mut EngineData<'b>, texture_creator: &'a TextureCreator<WindowContext>) -> BoxedScene<'a, Event, SceneName, EngineData<'b>> {
        let reader = ArtReader::new(&Path::new("./assets/artidx.mul"), &Path::new("./assets/art.mul")).expect("Could not load art");
        let scene = Box::new(WorldScene {
            exiting: false,
            map_id: 0,
            facet: map_id_to_facet(0),
            art_cache: ArtCache::new(texture_creator),
        });
        scene
    }

    pub fn draw_page(&mut self, renderer: &mut WindowCanvas) {
        self.facet.get_lens(MAX_BLOCKS_WIDTH, MAX_BLOCKS_HEIGHT).map(|lens| {
            for y in 0..lens.height {
                for x in 0..lens.width {
                    let (ref block, ref statics) = lens.blocks[(x + (y * MAX_BLOCKS_WIDTH)) as usize];
                    let transform = block_at(x as i32, y as i32);
                    self.draw_block(renderer, block, statics, &transform);
                }
            }
        });
    }

    pub fn draw_block(&mut self, renderer: &mut WindowCanvas, block: &Option<Block>, statics: &Option<Vec<StaticLocation>>, context: &TransformContext){
        block.map(|block| {
            for y in 0..8 {
                for x in 0..8 {
                    let cell = block.cells[y * 8 + x];
                    self.art_cache.read_tile(cell.graphic as u32).as_ref().map(|tile| {
                        let query = tile.query();
                        let new_context = cell_at(x as i32, y as i32).merge(context).transform(0, -cell.altitude as i32);
                        new_context.copy(renderer, &tile, None, Rect::new(0, 0, query.width, query.height));
                    });
                }
            }
        });
    }
}

impl<'a, 'b> Scene<Event, SceneName, EngineData<'b>> for WorldScene<'a> {
    fn render(&mut self, renderer: &mut WindowCanvas, _engine_data: &mut EngineData, _tick: u64) {
        renderer.clear();
        self.draw_page(renderer);
        renderer.present();
    }

    fn handle_event(&mut self, event: &Event, engine_data: &mut EngineData, _tick: u64) {
        match *event {
            Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                self.exiting = true
            },
            Event::KeyDown { keycode: Some(Keycode::Left), .. } => {
                if self.facet.x >= STEP_X as u32 {
                    self.facet.x -= STEP_X as u32;
                }
            },
            Event::KeyDown { keycode: Some(Keycode::Right), .. } => {
                self.facet.x += STEP_X as u32;
            },
            Event::KeyDown { keycode: Some(Keycode::Up), .. } => {
                if self.facet.y >= STEP_Y as u32 {
                    self.facet.y -= STEP_Y as u32;
                }
            },
            Event::KeyDown { keycode: Some(Keycode::Down), .. } => {
                self.facet.y += STEP_Y as u32;
            },
            Event::KeyDown { keycode: Some(Keycode::Tab), .. } => {
                self.map_id = (self.map_id + 1) % MAP_DETAILS.len() as u8;
                self.facet = map_id_to_facet(self.map_id);
            },
             _ => ()
        }
    }

    fn think(&mut self, _engine_data: &mut EngineData, _tick: u64) -> Option<SceneChangeEvent<SceneName>> {
        if self.exiting {
            Some(SceneChangeEvent::PopScene)
        } else {
            None
        }
    }
}
<|endoftext|>


<commit_before>use core::ops::Deref;
use core::ops::DerefMut;

use xen::event;

#[allow(dead_code)]
static mut CONS: InnerConsole = InnerConsole::new();

type ConsRingIdx = u32;

#[repr(C)]
pub struct ConsoleInterface {
    input: [u8; 1024],
    output: [u8; 2048],
    in_cons: ConsRingIdx,
    in_prod: ConsRingIdx,
    out_cons: ConsRingIdx,
    out_prod: ConsRingIdx,
}

struct InnerConsole {
    pub interface: *mut ConsoleInterface,
    pub port: event::EvtchnPort,
}

impl InnerConsole {
    pub const fn new() -> InnerConsole {
        InnerConsole {
            interface: 0 as *mut ConsoleInterface,
            port: 0,
        }
    }
}

impl Deref for InnerConsole {
    type Target = ConsoleInterface;

    #[inline]
    fn deref(&self) -> &ConsoleInterface {
        // This isn't totally safe. If the interface has not been initialized
        // this would cause some problems. For this to be safe, the console
        // MUST be initialized before being used
        unsafe {
            &(*self.interface)
        }
    }
}

impl DerefMut for InnerConsole {
    #[inline]
    fn deref_mut(&mut self) -> &mut ConsoleInterface {
        // See deref
        unsafe {
            &mut (*self.interface)
        }
    }
}
<commit_msg>console: Add public type interface<commit_after>use core::ops::Deref;
use core::ops::DerefMut;

use xen::event;

static mut CONS: InnerConsole = InnerConsole::new();

type ConsRingIdx = u32;

#[repr(C)]
pub struct ConsoleInterface {
    input: [u8; 1024],
    output: [u8; 2048],
    in_cons: ConsRingIdx,
    in_prod: ConsRingIdx,
    out_cons: ConsRingIdx,
    out_prod: ConsRingIdx,
}

struct InnerConsole {
    pub interface: *mut ConsoleInterface,
    pub port: event::EvtchnPort,
}

impl InnerConsole {
    pub const fn new() -> InnerConsole {
        InnerConsole {
            interface: 0 as *mut ConsoleInterface,
            port: 0,
        }
    }
}

impl Deref for InnerConsole {
    type Target = ConsoleInterface;

    #[inline]
    fn deref(&self) -> &ConsoleInterface {
        // This isn't totally safe. If the interface has not been initialized
        // this would cause some problems. For this to be safe, the console
        // MUST be initialized before being used
        unsafe {
            &(*self.interface)
        }
    }
}

impl DerefMut for InnerConsole {
    #[inline]
    fn deref_mut(&mut self) -> &mut ConsoleInterface {
        // See deref
        unsafe {
            &mut (*self.interface)
        }
    }
}

pub struct Console {
   console: &'static mut InnerConsole
}

pub fn console() -> Console {
    unsafe {
        Console {
            console: &mut CONS,
        }
    }
}

impl Console {
    pub fn set_interface(&mut self, interface: *mut ConsoleInterface) {
        self.console.interface = interface
    }

    pub fn set_port(&mut self, port: event::EvtchnPort) {
        self.console.port = port
    }
}
<|endoftext|>


<commit_before>/// Figure 8.29 Print selected fields from system’s accounting file
///
/// Status: compiles and runs on MacOs, didn't yet check if the output is correct
/// (at least ac_comm looks good)

#[macro_use(cstr)]
extern crate apue;
extern crate libc;

use libc::{fopen, fread, c_char, c_ushort, c_uchar, c_uint, c_int, c_void, ferror};
use apue::{LibcResult, err_sys, array_to_string};

const AFORK: u8 = 0x01; // fork'd but not exec'd
const ASU: u8 = 0x02; // used super-user permissions
const ACORE: u8 = 0x08; // dumped core
const AXSIG: u8 = 0x10; // killed by a signal

// taken via bindgen from /usr/include/sys/acct.h
#[repr(C)]
#[derive(Copy, Clone)]
#[derive(Debug)]
pub struct acct {
    pub ac_comm: [c_char; 10usize],
    pub ac_utime: c_ushort,
    pub ac_stime: c_ushort,
    pub ac_etime: c_ushort,
    pub ac_btime: c_uint,
    pub ac_uid: c_uint,
    pub ac_gid: c_uint,
    pub ac_mem: c_ushort,
    pub ac_io: c_ushort,
    pub ac_tty: c_int,
    pub ac_flag: c_uchar,
}

fn flag2str(acdata: acct, flag: u8, char: &str) -> &str {
    if acdata.ac_flag & flag > 0 { char } else { " " }
}

fn main() {
    unsafe {
        let mut args = std::env::args();
        if args.len() != 2 {
            println!("usage: {} filename", args.next().unwrap());
            return;
        }
        let fname = args.next_back().unwrap();
        let fp = fopen(cstr!(fname.clone()), cstr!("r"))
            .to_option()
            .expect(&format!("can't open {}", fname));
        let mut acdata: acct = std::mem::zeroed();
        while fread(&mut acdata as *mut _ as *mut c_void,
              std::mem::size_of::<acct>(),
              1,
              fp) == 1 {
            acdata.ac_comm[9] = 0; // 0-terminate string, otherwise: buffer-over-read
            println!("{:10} e = {:8} chars = {:8} {} {} {} {}",
                     array_to_string(&acdata.ac_comm),
                     acdata.ac_etime,
                     acdata.ac_io,
                     flag2str(acdata, ACORE, "D"),
                     flag2str(acdata, AXSIG, "X"),
                     flag2str(acdata, AFORK, "F"),
                     flag2str(acdata, ASU, "S"));
        }
        if ferror(fp) != 0 {
            err_sys("read error");
        }
    }
}<commit_msg>Make it work on Linux, add documentation<commit_after>/// Figure 8.29 Print selected fields from system’s accounting file
///
/// Takeaway: on linux I first took acct instead of acct_v3, which had
/// "funny" results
///
/// Things which could be improved in this code:
///
/// - use bindgen as macro directly in here instead of copy-pasting output
///   from bindgen commandline output
/// - maybe there's a better way to nul terminate string without doing
///   a copy of the string
///
// To try this script out:
//
// on linux:
// $ sudo accton /var/log/account/pacct
// .. do a few commands
// $ f29-acdata /var/log/account/pacct
//
// on mac:
// $ sudo accton /var/account/acct
// .. do a few commands
// $ f29-acdata /var/account/acct
#[macro_use(cstr)]
extern crate apue;
extern crate libc;

use libc::{fopen, fread, c_char, c_ushort, c_uint, c_void, ferror};
#[cfg(target_os = "macos")]
use libc::{c_uchar, c_int};

use apue::{LibcResult, err_sys, array_to_string};

const AFORK: u8 = 0x01; // fork'd but not exec'd
const ASU: u8 = 0x02; // used super-user permissions
const ACORE: u8 = 0x08; // dumped core
const AXSIG: u8 = 0x10; // killed by a signal

#[cfg(target_os = "macos")]
const COMM_LEN:usize = 10;
#[cfg(target_os = "linux")]
const COMM_LEN:usize = 16;

// taken via bindgen from /usr/include/sys/acct.h
#[repr(C)]
#[derive(Copy, Clone)]
#[derive(Debug)]
#[cfg(target_os = "macos")]
pub struct acct {
    pub ac_comm: [c_char; 10usize],
    pub ac_utime: c_ushort,
    pub ac_stime: c_ushort,
    pub ac_etime: c_ushort,
    pub ac_btime: c_uint,
    pub ac_uid: c_uint,
    pub ac_gid: c_uint,
    pub ac_mem: c_ushort,
    pub ac_io: c_ushort,
    pub ac_tty: c_int,
    pub ac_flag: c_uchar,
}

// taken via bindgen from /usr/include/linux/acct.h (acct_v3)
#[repr(C)]
#[derive(Copy, Clone)]
#[derive(Debug)]
#[cfg(target_os = "linux")]
pub struct acct {
    pub ac_flag: c_char,
    pub ac_version: c_char,
    pub ac_tty: c_ushort,
    pub ac_exitcode: c_uint,
    pub ac_uid: c_uint,
    pub ac_gid: c_uint,
    pub ac_pid: c_uint,
    pub ac_ppid: c_uint,
    pub ac_btime: c_uint,
    pub ac_etime: f32,
    pub ac_utime: c_ushort,
    pub ac_stime: c_ushort,
    pub ac_mem: c_ushort,
    pub ac_io: c_ushort,
    pub ac_rw: c_ushort,
    pub ac_minflt: c_ushort,
    pub ac_majflt: c_ushort,
    pub ac_swaps: c_ushort,
    pub ac_comm: [c_char; 16usize],
}

fn flag2str(acdata: acct, flag: u8, char: &str) -> &str {
    if acdata.ac_flag as u8 & flag > 0 {
        char
    } else {
        " "
    }
}

fn main() {
    unsafe {
        let mut args = std::env::args();
        if args.len() != 2 {
            println!("usage: {} filename", args.next().unwrap());
            return;
        }
        let fname = args.next_back().unwrap();
        let fp = fopen(cstr!(fname.clone()), cstr!("r"))
            .to_option()
            .expect(&format!("can't open {}", fname));
        let mut acdata: acct = std::mem::zeroed();
        while fread(&mut acdata as *mut _ as *mut c_void,
                    std::mem::size_of::<acct>(),
                    1,
                    fp) == 1 {

            // manually nul terminate string
            let mut ac_comm = vec![0; COMM_LEN+1];
            ac_comm[..COMM_LEN].clone_from_slice(&acdata.ac_comm);

            println!("{:16} e = {:8}, chars = {:7}, {} {} {} {}",
                     // std::str::from_utf8(ac_comm),
                     array_to_string(&ac_comm),
                     acdata.ac_etime,
                     acdata.ac_io,
                     flag2str(acdata, ACORE, "D"),
                     flag2str(acdata, AXSIG, "X"),
                     flag2str(acdata, AFORK, "F"),
                     flag2str(acdata, ASU, "S"))
        }
        if ferror(fp) != 0 {
            err_sys("read error");
        }
    }
}
<|endoftext|>


<commit_before>extern crate edit_distance;

#[test]
fn simple() {
    assert_eq!(edit_distance::edit_distance("kitten", "sitting"), 3);
    assert_eq!(edit_distance::edit_distance("Tier", "Tor"), 2);
}

#[test]
fn same() {
    assert_eq!(edit_distance::edit_distance("kitten", "kitten"), 0);
}

#[test]
fn empty_a() {
    assert_eq!(edit_distance::edit_distance("", "kitten"), 6);
}

#[test]
fn empty_b() {
    assert_eq!(edit_distance::edit_distance("sitting", ""), 7);
}

#[test]
fn empty_both() {
    assert_eq!(edit_distance::edit_distance("", ""), 0);
}

#[test]
fn unicode_misc() {
    assert_eq!(edit_distance::edit_distance("üö", "uo"), 2);
}

#[test]
fn unicode_thai() {
    assert_eq!(edit_distance::edit_distance("ฎ ฏ ฐ", "a b c"), 3);
}

#[test]
fn unicode_misc_equal() {
    assert_eq!(edit_distance::edit_distance("☀☂☃☄", "☀☂☃☄"), 0);
}

extern crate quickcheck;
use quickcheck::quickcheck;

#[test]
fn at_least_size_difference_property() {
    fn at_least_size_difference(a: String, b: String) -> bool {
        let size_a = a.chars().count() as i32;
        let size_b = b.chars().count() as i32;
        let diff = (size_a - size_b).abs();

        edit_distance::edit_distance(&a, &b) >= diff
    }

    quickcheck(at_least_size_difference as fn(a: String, b: String) -> bool);
}

#[test]
fn at_most_length_of_longer_property() {
    fn at_most_size_of_longer(a: String, b: String) -> bool {
        let upper_bound = *[a.chars().count(),
                            b.chars().count()]
            .iter()
            .max()
            .unwrap() as i32;
        edit_distance::edit_distance(&a, &b) <= upper_bound
    }

    quickcheck(at_most_size_of_longer as fn(a: String, b: String) -> bool);
}

#[test]
fn zero_iff_a_equals_b_property() {
    fn zero_iff_a_equals_b(a: String, b: String) -> bool {
        let d = edit_distance::edit_distance(&a, &b);

        if a == b {
            d == 0
        } else {
            d > 0
        }
    }

    quickcheck(zero_iff_a_equals_b as fn(a: String, b: String) -> bool);
}
<commit_msg>Triangle inequality<commit_after>extern crate edit_distance;

#[test]
fn simple() {
    assert_eq!(edit_distance::edit_distance("kitten", "sitting"), 3);
    assert_eq!(edit_distance::edit_distance("Tier", "Tor"), 2);
}

#[test]
fn same() {
    assert_eq!(edit_distance::edit_distance("kitten", "kitten"), 0);
}

#[test]
fn empty_a() {
    assert_eq!(edit_distance::edit_distance("", "kitten"), 6);
}

#[test]
fn empty_b() {
    assert_eq!(edit_distance::edit_distance("sitting", ""), 7);
}

#[test]
fn empty_both() {
    assert_eq!(edit_distance::edit_distance("", ""), 0);
}

#[test]
fn unicode_misc() {
    assert_eq!(edit_distance::edit_distance("üö", "uo"), 2);
}

#[test]
fn unicode_thai() {
    assert_eq!(edit_distance::edit_distance("ฎ ฏ ฐ", "a b c"), 3);
}

#[test]
fn unicode_misc_equal() {
    assert_eq!(edit_distance::edit_distance("☀☂☃☄", "☀☂☃☄"), 0);
}

extern crate quickcheck;
use quickcheck::quickcheck;

#[test]
fn at_least_size_difference_property() {
    fn at_least_size_difference(a: String, b: String) -> bool {
        let size_a = a.chars().count() as i32;
        let size_b = b.chars().count() as i32;
        let diff = (size_a - size_b).abs();

        edit_distance::edit_distance(&a, &b) >= diff
    }

    quickcheck(at_least_size_difference as fn(a: String, b: String) -> bool);
}

#[test]
fn at_most_length_of_longer_property() {
    fn at_most_size_of_longer(a: String, b: String) -> bool {
        let upper_bound = *[a.chars().count(),
                            b.chars().count()]
            .iter()
            .max()
            .unwrap() as i32;
        edit_distance::edit_distance(&a, &b) <= upper_bound
    }

    quickcheck(at_most_size_of_longer as fn(a: String, b: String) -> bool);
}

#[test]
fn zero_iff_a_equals_b_property() {
    fn zero_iff_a_equals_b(a: String, b: String) -> bool {
        let d = edit_distance::edit_distance(&a, &b);

        if a == b {
            d == 0
        } else {
            d > 0
        }
    }

    quickcheck(zero_iff_a_equals_b as fn(a: String, b: String) -> bool);
}

#[test]
fn triangle_inequality_property() {
    fn triangle_inequality(a: String, b: String, c: String) -> bool {
        edit_distance::edit_distance(&a, &b) <=
            edit_distance::edit_distance(&a, &c) +
            edit_distance::edit_distance(&b, &c)
    }

    quickcheck(triangle_inequality as fn(a: String, b: String, c: String) -> bool);
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate sorted;

use sorted::*;

order_by_key!{ Key0AscOrder:
    fn (K: Ord + Copy, T)(entry: (K,T)) -> K { entry.0 }
}

order_by_key!{ KeySecondOrder:
    fn (K: Ord + Copy, T)(entry: (T,K)) -> K { entry.1 }
}

#[test]
fn sorted_array() {
    let arr = [7, 2, 9, 6];
    let v = AscendingOrder::by_sorting(arr);
    assert_eq!(*v.as_inner(), [2, 6, 7, 9]);
}

#[test]
fn ascending_order() {
    let arr = AscendingOrder::by_sorting([3, 4, 1, 2]);
    assert_eq!(*arr.as_inner(), [1, 2, 3, 4]);
}

#[test]
fn descending_order() {
    let arr = DescendingOrder::by_sorting([1, 3, 4, 2]);
    assert_eq!(*arr.as_inner(), [4, 3, 2, 1]);
}

#[test]
fn sorted_slice() {
    let mut arr = [3, 2, 4, 1];
    let s = AscendingOrder::by_sorting(&mut arr[..]);
    assert_eq!(s.as_inner(), &[1, 2, 3, 4]);
}

#[test]
fn sorted_vec() {
    let v = AscendingOrder::by_sorting(vec![4, 3, 1, 2]);
    assert_eq!(v.as_slice(), &[1, 2, 3, 4]);
}

#[test]
fn sort_by_first() {
    let s = vec![(5, 3), (2, 7), (3, 4)];
    let v = KeyOrder::<keys::Key0, AscendingOrder>::by_sorting(s);
    assert_eq!(&[(2, 7), (3, 4), (5, 3)], v.as_slice());
}

#[test]
fn sort_by_second() {
    let s = vec![(5, 3, 9), (2, 7, 2), (3, 4, 4)];
    let v = KeyOrder::<keys::Key2, DescendingOrder>::by_sorting(s);
    assert_eq!(&[(5, 3, 9), (3, 4, 4), (2, 7, 2)], v.as_slice());
}

#[test]
fn sort_by_property() {
    #[derive(Debug, Clone, Copy, PartialEq)]
    struct Record { stuff: i32, id: u32 };
    impl Record {
        pub fn new(n: u32) -> Self { Record{ stuff: 0, id: n} }
    }
    #[derive(Debug, Clone, Copy)]
    struct IdKey;
    impl Key<Record> for IdKey {
        type Key = u32;
        fn key(r: &Record) -> Self::Key {
            r.id
        }
    }

    let v = KeyOrder::<IdKey, AscendingOrder>::by_sorting(
        vec![Record::new(2), Record::new(3), Record::new(1)]
    );
    assert_eq!(
        &v.as_slice(),
        &[Record::new(1), Record::new(2), Record::new(3)]
    );
}

#[test]
fn sorted_slice_from_sorted_vec() {
    fn take_sorted_slice<'a>(slice: Sorted<'a, &'a [i32], AscendingOrder>) {
        assert_eq!(&[1, 2, 4, 9, 33][..], *slice);
    }
    let vec = AscendingOrder::by_sorting(vec![4, 9, 2, 33, 1]);
    take_sorted_slice(vec.as_ref());
}

/// TODO: Can you get a Sorted<'a, &vec, O> from Sorted::as_ref?
#[test]
fn uhm() {
    let vec = AscendingOrder::by_sorting(vec![3,2,4,1]);
    let rvec: Sorted<&Vec<i32>, AscendingOrder> = vec.as_ref();
    rvec.as_slice();
}

#[test]
#[cfg(feature="unstable")]
fn sorted_vec_from_sorted_slice() {
    type SortedVec<'a, T, O> = Sorted<'a, Vec<T>, O>;
    let mut arr = [5, 3, 7, 9];
    let slice = AscendingOrder::by_sorting(&mut arr[..]);
    let vec = SortedVec::from(slice);
    assert_eq!([3, 5, 7, 9], vec.as_slice());
}

#[test]
fn take_sorted_iterator() {
    fn take_sorted<I>(sorted: I)
        where I: IntoIterator<Item = i32> + IsSorted
    {
        let v: Vec<_> = sorted.into_iter().collect();
        assert_eq!(vec![2, 3, 8, 10], v);
    }
    let vec = AscendingOrder::by_sorting(vec![3, 8, 2, 10]);
    take_sorted(vec);
}

#[test]
fn take_sorted_ref_iterator() {
    fn take_sorted_ref<'a,I>(sorted: I)
        where I: IntoIterator<Item = &'a i32> + IsSorted
    {
        let v: Vec<_> = sorted.into_iter().cloned().collect();
        assert_eq!([1,2,3,4], v.as_slice());
    }
    let vec = AscendingOrder::by_sorting(vec![3,4,1,2]);
    take_sorted_ref(vec.iter());
}

#[test]
fn sorted_insert() {
    let mut vec = AscendingOrder::by_sorting(vec![4, 8, 2, 0]);
    vec.insert(6);
    assert_eq!([0, 2, 4, 6, 8], vec.as_slice());
}

#[test]
fn sorted_vec_from_sorted_iterator() {
    type SortedVec<'a, T, O> = Sorted<'a, Vec<T>, O>;
    let v0 = AscendingOrder::by_sorting(vec![3,1,4,2]);
    let it = v0.into_iter();
    let v1 = SortedVec::from_iter(it);
    assert_eq!(
        &[1,2,3,4],
        v1.as_slice()
    );
}<commit_msg>Adding test to show how to sort by a &str key.<commit_after>#[macro_use]
extern crate sorted;

use sorted::*;

order_by_key!{ Key0AscOrder:
    fn (K: Ord + Copy, T)(entry: (K,T)) -> K { entry.0 }
}

order_by_key!{ KeySecondOrder:
    fn (K: Ord + Copy, T)(entry: (T,K)) -> K { entry.1 }
}

#[test]
fn sorted_array() {
    let arr = [7, 2, 9, 6];
    let v = AscendingOrder::by_sorting(arr);
    assert_eq!(*v.as_inner(), [2, 6, 7, 9]);
}

#[test]
fn ascending_order() {
    let arr = AscendingOrder::by_sorting([3, 4, 1, 2]);
    assert_eq!(*arr.as_inner(), [1, 2, 3, 4]);
}

#[test]
fn descending_order() {
    let arr = DescendingOrder::by_sorting([1, 3, 4, 2]);
    assert_eq!(*arr.as_inner(), [4, 3, 2, 1]);
}

#[test]
fn sorted_slice() {
    let mut arr = [3, 2, 4, 1];
    let s = AscendingOrder::by_sorting(&mut arr[..]);
    assert_eq!(s.as_inner(), &[1, 2, 3, 4]);
}

#[test]
fn sorted_vec() {
    let v = AscendingOrder::by_sorting(vec![4, 3, 1, 2]);
    assert_eq!(v.as_slice(), &[1, 2, 3, 4]);
}

#[test]
fn sort_by_first() {
    let s = vec![(5, 3), (2, 7), (3, 4)];
    let v = KeyOrder::<keys::Key0, AscendingOrder>::by_sorting(s);
    assert_eq!(&[(2, 7), (3, 4), (5, 3)], v.as_slice());
}

#[test]
fn sort_by_second() {
    let s = vec![(5, 3, 9), (2, 7, 2), (3, 4, 4)];
    let v = KeyOrder::<keys::Key2, DescendingOrder>::by_sorting(s);
    assert_eq!(&[(5, 3, 9), (3, 4, 4), (2, 7, 2)], v.as_slice());
}

#[test]
fn sort_with_property_key_type() {
    #[derive(Debug, Clone, Copy, PartialEq)]
    struct Record { stuff: i32, id: u32 };
    impl Record {
        pub fn new(n: u32) -> Self { Record{ stuff: 0, id: n} }
    }
    #[derive(Debug, Clone, Copy)]
    struct IdKey;
    impl Key<Record> for IdKey {
        type Key = u32;
        fn key(r: &Record) -> Self::Key { r.id }
    }

    let v = KeyOrder::<IdKey, AscendingOrder>::by_sorting(
        vec![Record::new(2), Record::new(3), Record::new(1)]
    );
    assert_eq!(
        &v.as_slice(),
        &[Record::new(1), Record::new(2), Record::new(3)]
    );
}

#[test]
fn sort_by_property_string() {
    use std::cmp::Ordering;
    #[derive(Debug, Clone, PartialEq)]
    struct Person { name: String, x: i32 };
    impl Person {
        pub fn new(n: &str) -> Self {
            Self { name: n.to_string(), x: 0 }
        }
    }
    #[derive(Debug, Clone, Copy)]
    struct OrderByName;
    impl SortOrder<Person> for OrderByName {
        fn cmp(a: &Person, b: &Person) -> Ordering {
            a.name.cmp(&b.name)
        }
    }
    let v = OrderByName::by_sorting(
        vec![Person::new("Bob"), Person::new("Cecil"), Person::new("Alice")]
    );
    assert_eq!(
        v.as_slice(),
        &[Person::new("Alice"), Person::new("Bob"), Person::new("Cecil")]
    );
}

#[test]
fn sorted_slice_from_sorted_vec() {
    fn take_sorted_slice<'a>(slice: Sorted<'a, &'a [i32], AscendingOrder>) {
        assert_eq!(&[1, 2, 4, 9, 33][..], *slice);
    }
    let vec = AscendingOrder::by_sorting(vec![4, 9, 2, 33, 1]);
    take_sorted_slice(vec.as_ref());
}

/// TODO: Can you get a Sorted<'a, &vec, O> from Sorted::as_ref?
#[test]
fn uhm() {
    let vec = AscendingOrder::by_sorting(vec![3,2,4,1]);
    let rvec: Sorted<&Vec<i32>, AscendingOrder> = vec.as_ref();
    rvec.as_slice();
}

#[test]
#[cfg(feature="unstable")]
fn sorted_vec_from_sorted_slice() {
    type SortedVec<'a, T, O> = Sorted<'a, Vec<T>, O>;
    let mut arr = [5, 3, 7, 9];
    let slice = AscendingOrder::by_sorting(&mut arr[..]);
    let vec = SortedVec::from(slice);
    assert_eq!([3, 5, 7, 9], vec.as_slice());
}

#[test]
fn take_sorted_iterator() {
    fn take_sorted<I>(sorted: I)
        where I: IntoIterator<Item = i32> + IsSorted
    {
        let v: Vec<_> = sorted.into_iter().collect();
        assert_eq!(vec![2, 3, 8, 10], v);
    }
    let vec = AscendingOrder::by_sorting(vec![3, 8, 2, 10]);
    take_sorted(vec);
}

#[test]
fn take_sorted_ref_iterator() {
    fn take_sorted_ref<'a,I>(sorted: I)
        where I: IntoIterator<Item = &'a i32> + IsSorted
    {
        let v: Vec<_> = sorted.into_iter().cloned().collect();
        assert_eq!([1,2,3,4], v.as_slice());
    }
    let vec = AscendingOrder::by_sorting(vec![3,4,1,2]);
    take_sorted_ref(vec.iter());
}

#[test]
fn sorted_insert() {
    let mut vec = AscendingOrder::by_sorting(vec![4, 8, 2, 0]);
    vec.insert(6);
    assert_eq!([0, 2, 4, 6, 8], vec.as_slice());
}

#[test]
fn sorted_vec_from_sorted_iterator() {
    type SortedVec<'a, T, O> = Sorted<'a, Vec<T>, O>;
    let v0 = AscendingOrder::by_sorting(vec![3,1,4,2]);
    let it = v0.into_iter();
    let v1 = SortedVec::from_iter(it);
    assert_eq!(
        &[1,2,3,4],
        v1.as_slice()
    );
}<|endoftext|>


<commit_before>
use super::*;
use std::marker::PhantomData;

/// An incoming COM interface pointer.
///
/// Intercom will implement the various `[com_interface]` traits for the
/// corresponding `ComItf<T>` type.
///
/// This applies only to the pure interfaces.  Implicit interfaces created
/// through `#[com_interface] impl MyStruct` constructs are not supported for
/// `ComItf<T>`.
#[fundamental]
#[repr(C)]
pub struct ComItf<T> where T: ?Sized {
    ptr: RawComPtr,
    phantom: PhantomData<T>,
}

impl<T> ComItf<T> where T: ?Sized {

    /// Creates a `ComItf<T>` from a raw COM interface pointer.
    ///
    /// # Safety
    ///
    /// The `ptr` __must__ be a valid COM interface pointer for an interface
    /// of type `T`.
    pub unsafe fn wrap( ptr : RawComPtr ) -> ComItf<T> {
        ComItf {
            ptr: ptr,
            phantom: PhantomData,
        }
    }

    /// Gets the raw COM pointer from the `ComItf<T>`.
    pub fn ptr( this : &Self ) -> RawComPtr { this.ptr }

    /// Returns a `ComItf<T>` value that references a null pointer.
    ///
    /// # Safety
    ///
    /// The `ComItf<T>` returned by the function will be invalid for any
    /// method calls. Its purpose is to act as a return value from COM
    /// methods in the case of an error result.
    pub unsafe fn null_itf() -> ComItf<T> {
        ComItf {
            ptr: ::std::ptr::null_mut(),
            phantom: PhantomData,
        }
    }
}

impl<T> AsRef<ComItf<IUnknown>> for ComItf<T> where T: ?Sized {

    fn as_ref( &self ) -> &ComItf<IUnknown> {
        unsafe { &*( self as *const _ as *const ComItf<IUnknown> ) }
    }
}

impl<'a, S, T: IidOf> std::convert::TryFrom<&'a ComItf<S>> for ComItf<T>
where
    T: ?Sized,
    S: ?Sized,
{
    type Error = ::HRESULT;

    fn try_from( other : &'a ComItf<S> ) -> Result<ComItf<T>, ::HRESULT> {
        let iunk : &ComItf<IUnknown> = other.as_ref();

        match iunk.query_interface( T::iid() ) {
            Ok( ptr ) => Ok( ComItf::<T> {
                ptr: ptr,
                phantom: PhantomData::<T>
            } ),
            Err( e ) => Err( e )
        }
    }
}
<commit_msg>Remove TryFrom for ComItf<commit_after>
use super::*;
use std::marker::PhantomData;

/// An incoming COM interface pointer.
///
/// Intercom will implement the various `[com_interface]` traits for the
/// corresponding `ComItf<T>` type.
///
/// This applies only to the pure interfaces.  Implicit interfaces created
/// through `#[com_interface] impl MyStruct` constructs are not supported for
/// `ComItf<T>`.
#[fundamental]
#[repr(C)]
pub struct ComItf<T> where T: ?Sized {
    ptr: RawComPtr,
    phantom: PhantomData<T>,
}

impl<T> ComItf<T> where T: ?Sized {

    /// Creates a `ComItf<T>` from a raw COM interface pointer.
    ///
    /// # Safety
    ///
    /// The `ptr` __must__ be a valid COM interface pointer for an interface
    /// of type `T`.
    pub unsafe fn wrap( ptr : RawComPtr ) -> ComItf<T> {
        ComItf {
            ptr: ptr,
            phantom: PhantomData,
        }
    }

    /// Gets the raw COM pointer from the `ComItf<T>`.
    pub fn ptr( this : &Self ) -> RawComPtr { this.ptr }

    /// Returns a `ComItf<T>` value that references a null pointer.
    ///
    /// # Safety
    ///
    /// The `ComItf<T>` returned by the function will be invalid for any
    /// method calls. Its purpose is to act as a return value from COM
    /// methods in the case of an error result.
    pub unsafe fn null_itf() -> ComItf<T> {
        ComItf {
            ptr: ::std::ptr::null_mut(),
            phantom: PhantomData,
        }
    }

    pub fn try_into< U: IidOf + ?Sized >(
        &self
    ) -> Result< ComItf<U>, ::HRESULT >
    {
        let iunk : &ComItf<IUnknown> = self.as_ref();

        match iunk.query_interface( U::iid() ) {
            Ok( ptr ) => Ok( ComItf::<U> {
                ptr: ptr,
                phantom: PhantomData
            } ),
            Err( e ) => Err( e )
        }
    }
}

impl<T> AsRef<ComItf<IUnknown>> for ComItf<T> where T: ?Sized {

    fn as_ref( &self ) -> &ComItf<IUnknown> {
        unsafe { &*( self as *const _ as *const ComItf<IUnknown> ) }
    }
}
<|endoftext|>


<commit_before>use std::rc::*;
use super::super::util::clonecell::*;
use super::super::tree::*;

use super::component::*;

struct Subscription<TData: Clone> {
    callback: ConsumerCallback,
    data: TData
}

type SubscriptionRef<TData> = Rc<Subscription<TData>>;

///
/// The subscription manager is an interior mutable type that can store subscriptions created from consumers.
/// The principle use case is to make it so that publishers and consumers can share a list of subscriptions.
///
pub struct SubscriptionManager<TData: Clone> {
    subscriptions: CloneCell<Vec<SubscriptionRef<TData>>>
}

impl<TData: Clone> SubscriptionManager<TData> {
    ///
    /// Creates a new subscription manager
    ///
    pub fn new() -> SubscriptionManager<TData> {
        SubscriptionManager { subscriptions: CloneCell::new(vec![]) }
    }

    ///
    /// Modifies this subscription manager to add the specified subscription
    ///
    pub fn add_subscription(&self, callback_data: TData, callback: ConsumerCallback) {
        // Turn the callback into a reference
        let new_callback = Rc::new(Subscription { callback: callback, data: callback_data });

        // Retrieve and update the subscriptions
        let mut subscriptions = self.subscriptions.get();
        subscriptions.push(new_callback);
        self.subscriptions.set(subscriptions);
    }

    ///
    /// Calls the subscriptions matching a particular filter
    ///
    pub fn call_subscriptions(&self, call_filter: &Fn(&TData) -> bool, change: &TreeChange) {
        // Retrieve the active subscriptions
        let subscriptions = self.subscriptions.get();

        // Call any subscription matching the filter
        for possible_subscription in subscriptions {
            if call_filter(&possible_subscription.data) {
                let callback = &possible_subscription.callback;
                callback(change);
            }
        }
    }
}

#[cfg(test)]
mod subscriptionmanager_tests {
    use std::rc::*;
    use std::cell::*;

    use super::*;
    use super::super::super::tree::*;

    #[test]
    pub fn can_call_subscription() {
        // Create a subscription manager and a sample change (doesn't matter what the change is)
        let manager         = SubscriptionManager::<i32>::new();
        let a_change        = TreeChange::new(&TreeAddress::Here, TreeChangeType::Child, TreeExtent::ThisNode, &"".to_tree_node());

        // Store the change count in a shared cell
        let change_count    = Rc::new(Cell::<i32>::new(0));
        let callback_count  = change_count.clone();

        // Must initially be 0
        assert!(change_count.get() == 0);

        // Create a subscription that updates the change count
        manager.add_subscription(0, Box::new(move |_change: &TreeChange| {
            let count_value = callback_count.get();
            let new_value   = count_value + 1;
            callback_count.set(new_value);
        }));

        // Call the subscription a few times (result should update)
        manager.call_subscriptions(&|_data| { true }, &a_change);
        assert!(change_count.get() == 1);
        manager.call_subscriptions(&|_data| { true }, &a_change);
        assert!(change_count.get() == 2);
    }

    #[test]
    pub fn can_filter_subscriptions() {
        // Create a subscription manager and a sample change (doesn't matter what the change is)
        let manager         = SubscriptionManager::<i32>::new();
        let a_change        = TreeChange::new(&TreeAddress::Here, TreeChangeType::Child, TreeExtent::ThisNode, &"".to_tree_node());

        // Store the change count in a shared cell
        let change_count    = Rc::new(Cell::<i32>::new(0));
        let callback_count  = change_count.clone();

        // Must initially be 0
        assert!(change_count.get() == 0);

        // Create a subscription that updates the change count
        manager.add_subscription(0, Box::new(move |_change: &TreeChange| {
            let count_value = callback_count.get();
            let new_value   = count_value + 1;
            callback_count.set(new_value);
        }));

        // Call the subscription a few times (result should not update)
        manager.call_subscriptions(&|_data| { false }, &a_change);
        assert!(change_count.get() == 0);
        manager.call_subscriptions(&|_data| { false }, &a_change);
        assert!(change_count.get() == 0);
    }
}
<commit_msg>Add a test that checks that multiple subscriptions are supported and filter correctly.<commit_after>use std::rc::*;
use super::super::util::clonecell::*;
use super::super::tree::*;

use super::component::*;

struct Subscription<TData: Clone> {
    callback: ConsumerCallback,
    data: TData
}

type SubscriptionRef<TData> = Rc<Subscription<TData>>;

///
/// The subscription manager is an interior mutable type that can store subscriptions created from consumers.
/// The principle use case is to make it so that publishers and consumers can share a list of subscriptions.
///
pub struct SubscriptionManager<TData: Clone> {
    subscriptions: CloneCell<Vec<SubscriptionRef<TData>>>
}

impl<TData: Clone> SubscriptionManager<TData> {
    ///
    /// Creates a new subscription manager
    ///
    pub fn new() -> SubscriptionManager<TData> {
        SubscriptionManager { subscriptions: CloneCell::new(vec![]) }
    }

    ///
    /// Modifies this subscription manager to add the specified subscription
    ///
    pub fn add_subscription(&self, callback_data: TData, callback: ConsumerCallback) {
        // Turn the callback into a reference
        let new_callback = Rc::new(Subscription { callback: callback, data: callback_data });

        // Retrieve and update the subscriptions
        let mut subscriptions = self.subscriptions.get();
        subscriptions.push(new_callback);
        self.subscriptions.set(subscriptions);
    }

    ///
    /// Calls the subscriptions matching a particular filter
    ///
    pub fn call_subscriptions(&self, call_filter: &Fn(&TData) -> bool, change: &TreeChange) {
        // Retrieve the active subscriptions
        let subscriptions = self.subscriptions.get();

        // Call any subscription matching the filter
        for possible_subscription in subscriptions {
            if call_filter(&possible_subscription.data) {
                let callback = &possible_subscription.callback;
                callback(change);
            }
        }
    }
}

#[cfg(test)]
mod subscriptionmanager_tests {
    use std::rc::*;
    use std::cell::*;

    use super::*;
    use super::super::super::tree::*;

    #[test]
    pub fn can_call_subscription() {
        // Create a subscription manager and a sample change (doesn't matter what the change is)
        let manager         = SubscriptionManager::<i32>::new();
        let a_change        = TreeChange::new(&TreeAddress::Here, TreeChangeType::Child, TreeExtent::ThisNode, &"".to_tree_node());

        // Store the change count in a shared cell
        let change_count    = Rc::new(Cell::<i32>::new(0));
        let callback_count  = change_count.clone();

        // Must initially be 0
        assert!(change_count.get() == 0);

        // Create a subscription that updates the change count
        manager.add_subscription(0, Box::new(move |_change: &TreeChange| {
            let count_value = callback_count.get();
            let new_value   = count_value + 1;
            callback_count.set(new_value);
        }));

        // Call the subscription a few times (result should update)
        manager.call_subscriptions(&|_data| { true }, &a_change);
        assert!(change_count.get() == 1);
        manager.call_subscriptions(&|_data| { true }, &a_change);
        assert!(change_count.get() == 2);
    }

    #[test]
    pub fn can_filter_all_subscriptions() {
        // Create a subscription manager and a sample change (doesn't matter what the change is)
        let manager         = SubscriptionManager::<i32>::new();
        let a_change        = TreeChange::new(&TreeAddress::Here, TreeChangeType::Child, TreeExtent::ThisNode, &"".to_tree_node());

        // Store the change count in a shared cell
        let change_count    = Rc::new(Cell::<i32>::new(0));
        let callback_count  = change_count.clone();

        // Must initially be 0
        assert!(change_count.get() == 0);

        // Create a subscription that updates the change count
        manager.add_subscription(0, Box::new(move |_change: &TreeChange| {
            let count_value = callback_count.get();
            let new_value   = count_value + 1;
            callback_count.set(new_value);
        }));

        // Call the subscription a few times (result should not update)
        manager.call_subscriptions(&|_data| { false }, &a_change);
        assert!(change_count.get() == 0);
        manager.call_subscriptions(&|_data| { false }, &a_change);
        assert!(change_count.get() == 0);
    }

    #[test]
    pub fn can_filter_some_subscriptions() {
        // Create a subscription manager and a sample change (doesn't matter what the change is)
        let manager         = SubscriptionManager::<i32>::new();
        let a_change        = TreeChange::new(&TreeAddress::Here, TreeChangeType::Child, TreeExtent::ThisNode, &"".to_tree_node());

        // Store the change count in a shared cell
        let change_count    = Rc::new(Cell::<i32>::new(0));
        let callback_count  = change_count.clone();
        let callback_count2 = change_count.clone();

        // Must initially be 0
        assert!(change_count.get() == 0);

        // Create a subscription that updates the change count
        manager.add_subscription(0, Box::new(move |_change: &TreeChange| {
            let count_value = callback_count.get();
            let new_value   = count_value + 1;
            callback_count.set(new_value);
        }));
        manager.add_subscription(1, Box::new(move |_change: &TreeChange| {
            let count_value = callback_count2.get();
            let new_value   = count_value + 1;
            callback_count2.set(new_value);
        }));

        // Call the subscription a few times (result should not update)
        manager.call_subscriptions(&|_data| { true }, &a_change);
        assert!(change_count.get() == 2);
        manager.call_subscriptions(&|_data| { false }, &a_change);
        assert!(change_count.get() == 2);
        manager.call_subscriptions(&|data| { *data == 1 }, &a_change);
        assert!(change_count.get() == 3);
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Element nodes.

use dom::attr::Attr;
use dom::attrlist::AttrList;
use dom::bindings::utils::{Reflectable, DOMString, ErrorResult, Fallible, Reflector};
use dom::bindings::utils::{null_str_as_empty, NamespaceError};
use dom::bindings::utils::{InvalidCharacter, QName, Name, InvalidXMLName, xml_name_type};
use dom::htmlcollection::HTMLCollection;
use dom::clientrect::ClientRect;
use dom::clientrectlist::ClientRectList;
use dom::document::AbstractDocument;
use dom::node::{AbstractNode, ElementNodeTypeId, Node};
use dom::document;
use dom::namespace;
use dom::namespace::{Namespace, Null};
use layout_interface::{ContentBoxQuery, ContentBoxResponse, ContentBoxesQuery};
use layout_interface::{ContentBoxesResponse, ContentChangedDocumentDamage};
use layout_interface::{MatchSelectorsDocumentDamage};
use style;

use std::str::eq;
use std::ascii::StrAsciiExt;

pub struct Element {
    node: Node,
    tag_name: ~str,     // TODO: This should be an atom, not a ~str.
    namespace: Namespace,
    attrs: ~[@mut Attr],
    style_attribute: Option<style::PropertyDeclarationBlock>,
    attr_list: Option<@mut AttrList>
}

impl Reflectable for Element {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        self.node.reflector()
    }

    fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
        self.node.mut_reflector()
    }
}

#[deriving(Eq)]
pub enum ElementTypeId {
    HTMLElementTypeId,
    HTMLAnchorElementTypeId,
    HTMLAppletElementTypeId,
    HTMLAreaElementTypeId,
    HTMLAudioElementTypeId,
    HTMLBaseElementTypeId,
    HTMLBRElementTypeId,
    HTMLBodyElementTypeId,
    HTMLButtonElementTypeId,
    HTMLCanvasElementTypeId,
    HTMLDataElementTypeId,
    HTMLDataListElementTypeId,
    HTMLDirectoryElementTypeId,
    HTMLDListElementTypeId,
    HTMLDivElementTypeId,
    HTMLEmbedElementTypeId,
    HTMLFieldSetElementTypeId,
    HTMLFontElementTypeId,
    HTMLFormElementTypeId,
    HTMLFrameElementTypeId,
    HTMLFrameSetElementTypeId,
    HTMLHRElementTypeId,
    HTMLHeadElementTypeId,
    HTMLHeadingElementTypeId,
    HTMLHtmlElementTypeId,
    HTMLIframeElementTypeId,
    HTMLImageElementTypeId,
    HTMLInputElementTypeId,
    HTMLLabelElementTypeId,
    HTMLLegendElementTypeId,
    HTMLLinkElementTypeId,
    HTMLLIElementTypeId,
    HTMLMainElementTypeId,
    HTMLMapElementTypeId,
    HTMLMediaElementTypeId,
    HTMLMetaElementTypeId,
    HTMLMeterElementTypeId,
    HTMLModElementTypeId,
    HTMLObjectElementTypeId,
    HTMLOListElementTypeId,
    HTMLOptGroupElementTypeId,
    HTMLOptionElementTypeId,
    HTMLOutputElementTypeId,
    HTMLParagraphElementTypeId,
    HTMLParamElementTypeId,
    HTMLPreElementTypeId,
    HTMLProgressElementTypeId,
    HTMLQuoteElementTypeId,
    HTMLScriptElementTypeId,
    HTMLSelectElementTypeId,
    HTMLSourceElementTypeId,
    HTMLSpanElementTypeId,
    HTMLStyleElementTypeId,
    HTMLTableElementTypeId,
    HTMLTableCaptionElementTypeId,
    HTMLTableCellElementTypeId,
    HTMLTableDataCellElementTypeId,
    HTMLTableHeaderCellElementTypeId,
    HTMLTableColElementTypeId,
    HTMLTableRowElementTypeId,
    HTMLTableSectionElementTypeId,
    HTMLTemplateElementTypeId,
    HTMLTextAreaElementTypeId,
    HTMLTimeElementTypeId,
    HTMLTitleElementTypeId,
    HTMLTrackElementTypeId,
    HTMLUListElementTypeId,
    HTMLVideoElementTypeId,
    HTMLUnknownElementTypeId,
}

//
// Element methods
//

impl Element {
    pub fn new_inherited(type_id: ElementTypeId, tag_name: ~str, namespace: Namespace, document: AbstractDocument) -> Element {
        Element {
            node: Node::new_inherited(ElementNodeTypeId(type_id), document),
            tag_name: tag_name,
            namespace: namespace,
            attrs: ~[],
            attr_list: None,
            style_attribute: None,
        }
    }

    pub fn normalize_attr_name(&self, name: Option<DOMString>) -> ~str {
        //FIXME: Throw for XML-invalid names
        let owner = self.node.owner_doc();
        if owner.document().doctype == document::HTML { // && self.namespace == Namespace::HTML
            null_str_as_empty(&name).to_ascii_lower()
        } else {
            null_str_as_empty(&name)
        }
    }

    pub fn get_attribute(&self,
                         namespace: Namespace,
                         name: &str) -> Option<@mut Attr> {
        // FIXME: only case-insensitive in the HTML namespace (as opposed to SVG, etc.)
        let name = name.to_ascii_lower();
        self.attrs.iter().find(|attr| {
            name == attr.local_name && attr.namespace == namespace
        }).map(|&x| x)
    }

    // FIXME(pcwalton): This is kind of confusingly named relative to the above...
    pub fn get_attr(&self, namespace: Namespace, name: &str) -> Option<~str> {
        self.get_attribute(namespace, name).map(|attr| attr.value.clone())
    }

    pub fn set_attr(&mut self, abstract_self: AbstractNode, name: DOMString, value: DOMString)
                    -> ErrorResult {
        // FIXME: HTML-in-HTML only.
        let name = name.to_ascii_lower();
        self.set_attribute(abstract_self, namespace::Null, name, value)
    }

    pub fn set_attribute(&mut self,
                         abstract_self: AbstractNode,
                         namespace: Namespace,
                         name: DOMString,
                         value: DOMString) -> ErrorResult {
        //FIXME: Throw for XML-invalid names
        //FIXME: Throw for XMLNS-invalid names
        let (prefix, local_name) = if name.contains(":")  {
            let parts: ~[&str] = name.splitn(':', 1).collect();
            (Some(parts[0].to_owned()), parts[1].to_owned())
        } else {
            (None, name.clone())
        };
        match prefix {
            Some(ref prefix_str) => {
                if (namespace == namespace::Null ||
                    (eq(prefix_str, &~"xml") && namespace != namespace::XML) ||
                    (eq(prefix_str, &~"xmlns") && namespace != namespace::XMLNS)) {
                    return Err(NamespaceError);
                }
            },
            None => {}
        }

        self.node.wait_until_safe_to_modify_dom();

        // FIXME: reduce the time of `value.clone()`.
        let mut old_raw_value: Option<DOMString> = None;
        for attr in self.attrs.iter() {
            if attr.local_name == local_name {
                old_raw_value = Some(attr.set_value(value.clone()));
                break;
            }
        }

        if old_raw_value.is_none() {
            let win = self.node.owner_doc().document().window;
            let new_attr = Attr::new_ns(win, local_name.clone(), value.clone(),
                                        name.clone(), namespace.clone(),
                                        prefix);
            self.attrs.push(new_attr);
        }

        if namespace == namespace::Null {
            self.after_set_attr(abstract_self, local_name, value, old_raw_value);
        }
        Ok(())
    }

    fn after_set_attr(&mut self,
                      abstract_self: AbstractNode,
                      local_name: DOMString,
                      value: DOMString,
                      old_value: Option<DOMString>) {

        match local_name.as_slice() {
            "style" => {
                self.style_attribute = Some(style::parse_style_attribute(value))
            }
            "id" => {
                let doc = self.node.owner_doc();
                let doc = doc.mut_document();
                doc.update_idmap(abstract_self, value.clone(), old_value);
            }
            _ => ()
        }

        //XXXjdm We really need something like a vtable so we can call AfterSetAttr.
        //       This hardcoding is awful.
        match abstract_self.type_id() {
            ElementNodeTypeId(HTMLImageElementTypeId) => {
                abstract_self.with_mut_image_element(|image| {
                    image.AfterSetAttr(local_name.clone(), value.clone());
                });
            }
            ElementNodeTypeId(HTMLIframeElementTypeId) => {
                abstract_self.with_mut_iframe_element(|iframe| {
                    iframe.AfterSetAttr(local_name.clone(), value.clone());
                });
            }
            _ => ()
        }

        if abstract_self.is_in_doc() {
            let damage = match local_name.as_slice() {
                "style" | "id" | "class" => MatchSelectorsDocumentDamage,
                _ => ContentChangedDocumentDamage
            };
            let document = self.node.owner_doc();
            document.document().damage_and_reflow(damage);
        }
    }
}

// http://www.whatwg.org/html/#reflecting-content-attributes-in-idl-attributes
impl Element {
    pub fn get_url_attribute(&self, name: &str) -> DOMString {
        // XXX Resolve URL.
        self.get_string_attribute(name)
    }
    pub fn set_url_attribute(&mut self, abstract_self: AbstractNode,
                             name: &str, value: DOMString) {
        self.set_string_attribute(abstract_self, name, value);
    }

    pub fn get_string_attribute(&self, name: &str) -> DOMString {
        match self.get_attr(Null, name) {
            Some(x) => x,
            None => ~""
        }
    }
    pub fn set_string_attribute(&mut self, abstract_self: AbstractNode,
                                name: &str, value: DOMString) {
        assert!(name == name.to_ascii_lower());
        self.set_attribute(abstract_self, Null, name.to_owned(), value);
    }
}

impl Element {
    pub fn TagName(&self) -> DOMString {
        self.tag_name.to_ascii_upper()
    }

    pub fn Id(&self, _abstract_self: AbstractNode) -> DOMString {
        self.get_string_attribute("id")
    }

    pub fn SetId(&mut self, abstract_self: AbstractNode, id: DOMString) {
        self.set_string_attribute(abstract_self, "id", id);
    }

    pub fn Attributes(&mut self, abstract_self: AbstractNode) -> @mut AttrList {
        match self.attr_list {
            None => {
                let window = self.node.owner_doc().document().window;
                let list = AttrList::new(window, abstract_self);
                self.attr_list = Some(list);
                list
            }
            Some(list) => list
        }
    }

    pub fn GetAttribute(&self, name: DOMString) -> Option<DOMString> {
        self.get_attr(Null, name).map(|s| s.to_owned())
    }

    pub fn GetAttributeNS(&self, namespace: Option<DOMString>, local_name: DOMString) -> Option<DOMString> {
        let namespace = Namespace::from_str(namespace);
        self.get_attribute(namespace, local_name)
            .map(|attr| attr.value.clone())
    }

    pub fn SetAttribute(&mut self, abstract_self: AbstractNode, name: DOMString, value: DOMString)
                        -> ErrorResult {
        self.set_attr(abstract_self, name, value);
        Ok(())
    }

    pub fn SetAttributeNS(&mut self,
                          abstract_self: AbstractNode,
                          namespace_url: Option<DOMString>,
                          name: DOMString,
                          value: DOMString) -> ErrorResult {
        let name_type = xml_name_type(name);
        match name_type {
            InvalidXMLName => return Err(InvalidCharacter),
            Name => return Err(NamespaceError),
            QName => {}
        }

        let namespace = Namespace::from_str(namespace_url);
        self.set_attribute(abstract_self, namespace, name, value)
    }

    pub fn RemoveAttribute(&self, _name: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn RemoveAttributeNS(&self, _namespace: Option<DOMString>, _localname: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn HasAttribute(&self, name: DOMString) -> bool {
        self.GetAttribute(name).is_some()
    }

    pub fn HasAttributeNS(&self, namespace: Option<DOMString>, local_name: DOMString) -> bool {
        self.GetAttributeNS(namespace, local_name).is_some()
    }

    pub fn GetElementsByTagName(&self, _localname: DOMString) -> @mut HTMLCollection {
        HTMLCollection::new(self.node.owner_doc().document().window, ~[])
    }

    pub fn GetElementsByTagNameNS(&self, _namespace: Option<DOMString>, _localname: DOMString) -> Fallible<@mut HTMLCollection> {
        Ok(HTMLCollection::new(self.node.owner_doc().document().window, ~[]))
    }

    pub fn GetElementsByClassName(&self, _names: DOMString) -> @mut HTMLCollection {
        HTMLCollection::new(self.node.owner_doc().document().window, ~[])
    }

    pub fn MozMatchesSelector(&self, _selector: DOMString) -> Fallible<bool> {
        Ok(false)
    }

    pub fn SetCapture(&self, _retargetToElement: bool) {
    }

    pub fn ReleaseCapture(&self) {
    }

    pub fn MozRequestFullScreen(&self) {
    }

    pub fn MozRequestPointerLock(&self) {
    }

    pub fn GetClientRects(&self, abstract_self: AbstractNode) -> @mut ClientRectList {
        let win = self.node.owner_doc().document().window;
        let node = abstract_self;
        assert!(node.is_element());
        let (port, chan) = Chan::new();
        let rects =
            match win.page.query_layout(ContentBoxesQuery(node, chan), port) {
                ContentBoxesResponse(rects) => {
                    rects.map(|r| {
                        ClientRect::new(
                            win,
                            r.origin.y,
                            r.origin.y + r.size.height,
                            r.origin.x,
                            r.origin.x + r.size.width)
                    })
                },
            };

        ClientRectList::new(win, rects)
    }

    pub fn GetBoundingClientRect(&self, abstract_self: AbstractNode) -> @mut ClientRect {
        let win = self.node.owner_doc().document().window;
        let node = abstract_self;
        assert!(node.is_element());
        let (port, chan) = Chan::new();
        match win.page.query_layout(ContentBoxQuery(node, chan), port) {
            ContentBoxResponse(rect) => {
                ClientRect::new(
                    win,
                    rect.origin.y,
                    rect.origin.y + rect.size.height,
                    rect.origin.x,
                    rect.origin.x + rect.size.width)
            }
        }
    }

    pub fn ScrollIntoView(&self, _top: bool) {
    }

    pub fn ScrollTop(&self) -> i32 {
        0
    }

    pub fn SetScrollTop(&mut self, _scroll_top: i32) {
    }

    pub fn ScrollLeft(&self) -> i32 {
        0
    }

    pub fn SetScrollLeft(&mut self, _scroll_left: i32) {
    }

    pub fn ScrollWidth(&self) -> i32 {
        0
    }

    pub fn ScrollHeight(&self) -> i32 {
        0
    }

    pub fn ClientTop(&self) -> i32 {
        0
    }

    pub fn ClientLeft(&self) -> i32 {
        0
    }

    pub fn ClientWidth(&self) -> i32 {
        0
    }

    pub fn ClientHeight(&self) -> i32 {
        0
    }

    pub fn GetInnerHTML(&self) -> Fallible<DOMString> {
        Ok(~"")
    }

    pub fn SetInnerHTML(&mut self, _value: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn GetOuterHTML(&self) -> Fallible<DOMString> {
        Ok(~"")
    }

    pub fn SetOuterHTML(&mut self, _value: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn InsertAdjacentHTML(&mut self, _position: DOMString, _text: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn QuerySelector(&self, _selectors: DOMString) -> Fallible<Option<AbstractNode>> {
        Ok(None)
    }
}
<commit_msg>Remove needless code.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Element nodes.

use dom::attr::Attr;
use dom::attrlist::AttrList;
use dom::bindings::utils::{Reflectable, DOMString, ErrorResult, Fallible, Reflector};
use dom::bindings::utils::{null_str_as_empty, NamespaceError};
use dom::bindings::utils::{InvalidCharacter, QName, Name, InvalidXMLName, xml_name_type};
use dom::htmlcollection::HTMLCollection;
use dom::clientrect::ClientRect;
use dom::clientrectlist::ClientRectList;
use dom::document::AbstractDocument;
use dom::node::{AbstractNode, ElementNodeTypeId, Node};
use dom::document;
use dom::namespace;
use dom::namespace::{Namespace, Null};
use layout_interface::{ContentBoxQuery, ContentBoxResponse, ContentBoxesQuery};
use layout_interface::{ContentBoxesResponse, ContentChangedDocumentDamage};
use layout_interface::{MatchSelectorsDocumentDamage};
use style;

use std::str::eq;
use std::ascii::StrAsciiExt;

pub struct Element {
    node: Node,
    tag_name: ~str,     // TODO: This should be an atom, not a ~str.
    namespace: Namespace,
    attrs: ~[@mut Attr],
    style_attribute: Option<style::PropertyDeclarationBlock>,
    attr_list: Option<@mut AttrList>
}

impl Reflectable for Element {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        self.node.reflector()
    }

    fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
        self.node.mut_reflector()
    }
}

#[deriving(Eq)]
pub enum ElementTypeId {
    HTMLElementTypeId,
    HTMLAnchorElementTypeId,
    HTMLAppletElementTypeId,
    HTMLAreaElementTypeId,
    HTMLAudioElementTypeId,
    HTMLBaseElementTypeId,
    HTMLBRElementTypeId,
    HTMLBodyElementTypeId,
    HTMLButtonElementTypeId,
    HTMLCanvasElementTypeId,
    HTMLDataElementTypeId,
    HTMLDataListElementTypeId,
    HTMLDirectoryElementTypeId,
    HTMLDListElementTypeId,
    HTMLDivElementTypeId,
    HTMLEmbedElementTypeId,
    HTMLFieldSetElementTypeId,
    HTMLFontElementTypeId,
    HTMLFormElementTypeId,
    HTMLFrameElementTypeId,
    HTMLFrameSetElementTypeId,
    HTMLHRElementTypeId,
    HTMLHeadElementTypeId,
    HTMLHeadingElementTypeId,
    HTMLHtmlElementTypeId,
    HTMLIframeElementTypeId,
    HTMLImageElementTypeId,
    HTMLInputElementTypeId,
    HTMLLabelElementTypeId,
    HTMLLegendElementTypeId,
    HTMLLinkElementTypeId,
    HTMLLIElementTypeId,
    HTMLMainElementTypeId,
    HTMLMapElementTypeId,
    HTMLMediaElementTypeId,
    HTMLMetaElementTypeId,
    HTMLMeterElementTypeId,
    HTMLModElementTypeId,
    HTMLObjectElementTypeId,
    HTMLOListElementTypeId,
    HTMLOptGroupElementTypeId,
    HTMLOptionElementTypeId,
    HTMLOutputElementTypeId,
    HTMLParagraphElementTypeId,
    HTMLParamElementTypeId,
    HTMLPreElementTypeId,
    HTMLProgressElementTypeId,
    HTMLQuoteElementTypeId,
    HTMLScriptElementTypeId,
    HTMLSelectElementTypeId,
    HTMLSourceElementTypeId,
    HTMLSpanElementTypeId,
    HTMLStyleElementTypeId,
    HTMLTableElementTypeId,
    HTMLTableCaptionElementTypeId,
    HTMLTableCellElementTypeId,
    HTMLTableDataCellElementTypeId,
    HTMLTableHeaderCellElementTypeId,
    HTMLTableColElementTypeId,
    HTMLTableRowElementTypeId,
    HTMLTableSectionElementTypeId,
    HTMLTemplateElementTypeId,
    HTMLTextAreaElementTypeId,
    HTMLTimeElementTypeId,
    HTMLTitleElementTypeId,
    HTMLTrackElementTypeId,
    HTMLUListElementTypeId,
    HTMLVideoElementTypeId,
    HTMLUnknownElementTypeId,
}

//
// Element methods
//

impl Element {
    pub fn new_inherited(type_id: ElementTypeId, tag_name: ~str, namespace: Namespace, document: AbstractDocument) -> Element {
        Element {
            node: Node::new_inherited(ElementNodeTypeId(type_id), document),
            tag_name: tag_name,
            namespace: namespace,
            attrs: ~[],
            attr_list: None,
            style_attribute: None,
        }
    }

    pub fn normalize_attr_name(&self, name: Option<DOMString>) -> ~str {
        //FIXME: Throw for XML-invalid names
        let owner = self.node.owner_doc();
        if owner.document().doctype == document::HTML { // && self.namespace == Namespace::HTML
            null_str_as_empty(&name).to_ascii_lower()
        } else {
            null_str_as_empty(&name)
        }
    }

    pub fn get_attribute(&self,
                         namespace: Namespace,
                         name: &str) -> Option<@mut Attr> {
        // FIXME: only case-insensitive in the HTML namespace (as opposed to SVG, etc.)
        let name = name.to_ascii_lower();
        self.attrs.iter().find(|attr| {
            name == attr.local_name && attr.namespace == namespace
        }).map(|&x| x)
    }

    // FIXME(pcwalton): This is kind of confusingly named relative to the above...
    pub fn get_attr(&self, namespace: Namespace, name: &str) -> Option<~str> {
        self.get_attribute(namespace, name).map(|attr| attr.value.clone())
    }

    pub fn set_attr(&mut self, abstract_self: AbstractNode, name: DOMString, value: DOMString)
                    -> ErrorResult {
        // FIXME: HTML-in-HTML only.
        let name = name.to_ascii_lower();
        self.set_attribute(abstract_self, namespace::Null, name, value)
    }

    pub fn set_attribute(&mut self,
                         abstract_self: AbstractNode,
                         namespace: Namespace,
                         name: DOMString,
                         value: DOMString) -> ErrorResult {
        //FIXME: Throw for XML-invalid names
        //FIXME: Throw for XMLNS-invalid names
        let (prefix, local_name) = if name.contains(":")  {
            let parts: ~[&str] = name.splitn(':', 1).collect();
            (Some(parts[0].to_owned()), parts[1].to_owned())
        } else {
            (None, name.clone())
        };
        match prefix {
            Some(ref prefix_str) => {
                if (namespace == namespace::Null ||
                    (eq(prefix_str, &~"xml") && namespace != namespace::XML) ||
                    (eq(prefix_str, &~"xmlns") && namespace != namespace::XMLNS)) {
                    return Err(NamespaceError);
                }
            },
            None => {}
        }

        self.node.wait_until_safe_to_modify_dom();

        // FIXME: reduce the time of `value.clone()`.
        let mut old_raw_value: Option<DOMString> = None;
        for attr in self.attrs.iter() {
            if attr.local_name == local_name {
                old_raw_value = Some(attr.set_value(value.clone()));
                break;
            }
        }

        if old_raw_value.is_none() {
            let win = self.node.owner_doc().document().window;
            let new_attr = Attr::new_ns(win, local_name.clone(), value.clone(),
                                        name.clone(), namespace.clone(),
                                        prefix);
            self.attrs.push(new_attr);
        }

        if namespace == namespace::Null {
            self.after_set_attr(abstract_self, local_name, value, old_raw_value);
        }
        Ok(())
    }

    fn after_set_attr(&mut self,
                      abstract_self: AbstractNode,
                      local_name: DOMString,
                      value: DOMString,
                      old_value: Option<DOMString>) {

        match local_name.as_slice() {
            "style" => {
                self.style_attribute = Some(style::parse_style_attribute(value))
            }
            "id" => {
                let doc = self.node.owner_doc();
                let doc = doc.mut_document();
                doc.update_idmap(abstract_self, value.clone(), old_value);
            }
            _ => ()
        }

        //XXXjdm We really need something like a vtable so we can call AfterSetAttr.
        //       This hardcoding is awful.
        match abstract_self.type_id() {
            ElementNodeTypeId(HTMLImageElementTypeId) => {
                abstract_self.with_mut_image_element(|image| {
                    image.AfterSetAttr(local_name.clone(), value.clone());
                });
            }
            ElementNodeTypeId(HTMLIframeElementTypeId) => {
                abstract_self.with_mut_iframe_element(|iframe| {
                    iframe.AfterSetAttr(local_name.clone(), value.clone());
                });
            }
            _ => ()
        }

        if abstract_self.is_in_doc() {
            let damage = match local_name.as_slice() {
                "style" | "id" | "class" => MatchSelectorsDocumentDamage,
                _ => ContentChangedDocumentDamage
            };
            let document = self.node.owner_doc();
            document.document().damage_and_reflow(damage);
        }
    }
}

// http://www.whatwg.org/html/#reflecting-content-attributes-in-idl-attributes
impl Element {
    pub fn get_url_attribute(&self, name: &str) -> DOMString {
        // XXX Resolve URL.
        self.get_string_attribute(name)
    }
    pub fn set_url_attribute(&mut self, abstract_self: AbstractNode,
                             name: &str, value: DOMString) {
        self.set_string_attribute(abstract_self, name, value);
    }

    pub fn get_string_attribute(&self, name: &str) -> DOMString {
        match self.get_attr(Null, name) {
            Some(x) => x,
            None => ~""
        }
    }
    pub fn set_string_attribute(&mut self, abstract_self: AbstractNode,
                                name: &str, value: DOMString) {
        assert!(name == name.to_ascii_lower());
        self.set_attribute(abstract_self, Null, name.to_owned(), value);
    }
}

impl Element {
    pub fn TagName(&self) -> DOMString {
        self.tag_name.to_ascii_upper()
    }

    pub fn Id(&self, _abstract_self: AbstractNode) -> DOMString {
        self.get_string_attribute("id")
    }

    pub fn SetId(&mut self, abstract_self: AbstractNode, id: DOMString) {
        self.set_string_attribute(abstract_self, "id", id);
    }

    pub fn Attributes(&mut self, abstract_self: AbstractNode) -> @mut AttrList {
        match self.attr_list {
            None => {
                let window = self.node.owner_doc().document().window;
                let list = AttrList::new(window, abstract_self);
                self.attr_list = Some(list);
                list
            }
            Some(list) => list
        }
    }

    pub fn GetAttribute(&self, name: DOMString) -> Option<DOMString> {
        self.get_attr(Null, name).map(|s| s.to_owned())
    }

    pub fn GetAttributeNS(&self, namespace: Option<DOMString>, local_name: DOMString) -> Option<DOMString> {
        let namespace = Namespace::from_str(namespace);
        self.get_attribute(namespace, local_name)
            .map(|attr| attr.value.clone())
    }

    pub fn SetAttribute(&mut self, abstract_self: AbstractNode, name: DOMString, value: DOMString)
                        -> ErrorResult {
        self.set_attr(abstract_self, name, value)
    }

    pub fn SetAttributeNS(&mut self,
                          abstract_self: AbstractNode,
                          namespace_url: Option<DOMString>,
                          name: DOMString,
                          value: DOMString) -> ErrorResult {
        let name_type = xml_name_type(name);
        match name_type {
            InvalidXMLName => return Err(InvalidCharacter),
            Name => return Err(NamespaceError),
            QName => {}
        }

        let namespace = Namespace::from_str(namespace_url);
        self.set_attribute(abstract_self, namespace, name, value)
    }

    pub fn RemoveAttribute(&self, _name: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn RemoveAttributeNS(&self, _namespace: Option<DOMString>, _localname: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn HasAttribute(&self, name: DOMString) -> bool {
        self.GetAttribute(name).is_some()
    }

    pub fn HasAttributeNS(&self, namespace: Option<DOMString>, local_name: DOMString) -> bool {
        self.GetAttributeNS(namespace, local_name).is_some()
    }

    pub fn GetElementsByTagName(&self, _localname: DOMString) -> @mut HTMLCollection {
        HTMLCollection::new(self.node.owner_doc().document().window, ~[])
    }

    pub fn GetElementsByTagNameNS(&self, _namespace: Option<DOMString>, _localname: DOMString) -> Fallible<@mut HTMLCollection> {
        Ok(HTMLCollection::new(self.node.owner_doc().document().window, ~[]))
    }

    pub fn GetElementsByClassName(&self, _names: DOMString) -> @mut HTMLCollection {
        HTMLCollection::new(self.node.owner_doc().document().window, ~[])
    }

    pub fn MozMatchesSelector(&self, _selector: DOMString) -> Fallible<bool> {
        Ok(false)
    }

    pub fn SetCapture(&self, _retargetToElement: bool) {
    }

    pub fn ReleaseCapture(&self) {
    }

    pub fn MozRequestFullScreen(&self) {
    }

    pub fn MozRequestPointerLock(&self) {
    }

    pub fn GetClientRects(&self, abstract_self: AbstractNode) -> @mut ClientRectList {
        let win = self.node.owner_doc().document().window;
        let node = abstract_self;
        assert!(node.is_element());
        let (port, chan) = Chan::new();
        let rects =
            match win.page.query_layout(ContentBoxesQuery(node, chan), port) {
                ContentBoxesResponse(rects) => {
                    rects.map(|r| {
                        ClientRect::new(
                            win,
                            r.origin.y,
                            r.origin.y + r.size.height,
                            r.origin.x,
                            r.origin.x + r.size.width)
                    })
                },
            };

        ClientRectList::new(win, rects)
    }

    pub fn GetBoundingClientRect(&self, abstract_self: AbstractNode) -> @mut ClientRect {
        let win = self.node.owner_doc().document().window;
        let node = abstract_self;
        assert!(node.is_element());
        let (port, chan) = Chan::new();
        match win.page.query_layout(ContentBoxQuery(node, chan), port) {
            ContentBoxResponse(rect) => {
                ClientRect::new(
                    win,
                    rect.origin.y,
                    rect.origin.y + rect.size.height,
                    rect.origin.x,
                    rect.origin.x + rect.size.width)
            }
        }
    }

    pub fn ScrollIntoView(&self, _top: bool) {
    }

    pub fn ScrollTop(&self) -> i32 {
        0
    }

    pub fn SetScrollTop(&mut self, _scroll_top: i32) {
    }

    pub fn ScrollLeft(&self) -> i32 {
        0
    }

    pub fn SetScrollLeft(&mut self, _scroll_left: i32) {
    }

    pub fn ScrollWidth(&self) -> i32 {
        0
    }

    pub fn ScrollHeight(&self) -> i32 {
        0
    }

    pub fn ClientTop(&self) -> i32 {
        0
    }

    pub fn ClientLeft(&self) -> i32 {
        0
    }

    pub fn ClientWidth(&self) -> i32 {
        0
    }

    pub fn ClientHeight(&self) -> i32 {
        0
    }

    pub fn GetInnerHTML(&self) -> Fallible<DOMString> {
        Ok(~"")
    }

    pub fn SetInnerHTML(&mut self, _value: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn GetOuterHTML(&self) -> Fallible<DOMString> {
        Ok(~"")
    }

    pub fn SetOuterHTML(&mut self, _value: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn InsertAdjacentHTML(&mut self, _position: DOMString, _text: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn QuerySelector(&self, _selectors: DOMString) -> Fallible<Option<AbstractNode>> {
        Ok(None)
    }
}
<|endoftext|>