<commit_before>// Code for creating styled buffers

use crate::snippet::{Style, StyledString};

#[derive(Debug)]
pub struct StyledBuffer {
    text: Vec<Vec<StyledChar>>,
}

#[derive(Debug)]
struct StyledChar {
    chr: char,
    style: Style,
}

impl StyledChar {
    fn new(chr: char, style: Style) -> Self {
        StyledChar { chr, style }
    }
}

impl Default for StyledChar {
    fn default() -> Self {
        StyledChar::new(' ', Style::NoStyle)
    }
}

impl StyledBuffer {
    pub fn new() -> StyledBuffer {
        StyledBuffer { text: vec![] }
    }

    /// Returns content of `StyledBuffer` splitted by lines and line styles
    pub fn render(&self) -> Vec<Vec<StyledString>> {
        // Tabs are assumed to have been replaced by spaces in calling code.
        debug_assert!(self.text.iter().all(|r| !r.iter().any(|sc| sc.chr == '\t')));

        let mut output: Vec<Vec<StyledString>> = vec![];
        let mut styled_vec: Vec<StyledString> = vec![];

        for styled_row in &self.text {
            let mut current_style = Style::NoStyle;
            let mut current_text = String::new();

            for sc in styled_row {
                if sc.style != current_style {
                    if !current_text.is_empty() {
                        styled_vec.push(StyledString { text: current_text, style: current_style });
                    }
                    current_style = sc.style;
                    current_text = String::new();
                }
                current_text.push(sc.chr);
            }
            if !current_text.is_empty() {
                styled_vec.push(StyledString { text: current_text, style: current_style });
            }

            // We're done with the row, push and keep going
            output.push(styled_vec);

            styled_vec = vec![];
        }

        output
    }

    fn ensure_lines(&mut self, line: usize) {
        while line >= self.text.len() {
            self.text.push(vec![]);
        }
    }

    /// Sets `chr` with `style` for given `line`, `col`.
    /// If line not exist in `StyledBuffer`, adds lines up to given
    /// and fills last line with spaces and `Style::NoStyle` style
    pub fn putc(&mut self, line: usize, col: usize, chr: char, style: Style) {
        self.ensure_lines(line);
        if col < self.text[line].len() {
            self.text[line][col] = StyledChar::new(chr, style);
        } else {
            let mut i = self.text[line].len();
            while i < col {
                self.text[line].push(StyledChar::default());
                i += 1;
            }
            self.text[line].push(StyledChar::new(chr, style));
        }
    }

    /// Sets `string` with `style` for given `line`, starting from `col`.
    /// If line not exist in `StyledBuffer`, adds lines up to given
    /// and fills last line with spaces and `Style::NoStyle` style
    pub fn puts(&mut self, line: usize, col: usize, string: &str, style: Style) {
        let mut n = col;
        for c in string.chars() {
            self.putc(line, n, c, style);
            n += 1;
        }
    }

    /// For given `line` inserts `string` with `style` before old content of that line,
    /// adding lines if needed
    pub fn prepend(&mut self, line: usize, string: &str, style: Style) {
        self.ensure_lines(line);
        let string_len = string.chars().count();

        // Push the old content over to make room for new content
        for _ in 0..string_len {
            self.text[line].insert(0, StyledChar::default());
        }

        self.puts(line, 0, string, style);
    }

    /// For given `line` inserts `string` with `style` after old content of that line,
    /// adding lines if needed
    pub fn append(&mut self, line: usize, string: &str, style: Style) {
        if line >= self.text.len() {
            self.puts(line, 0, string, style);
        } else {
            let col = self.text[line].len();
            self.puts(line, col, string, style);
        }
    }

    pub fn num_lines(&self) -> usize {
        self.text.len()
    }

    /// Set `style` for `line`, `col_start..col_end` range if:
    /// 1. That line and column range exist in `StyledBuffer`
    /// 2. `overwrite` is `true` or existing style is `Style::NoStyle` or `Style::Quotation`
    pub fn set_style_range(
        &mut self,
        line: usize,
        col_start: usize,
        col_end: usize,
        style: Style,
        overwrite: bool,
    ) {
        for col in col_start..col_end {
            self.set_style(line, col, style, overwrite);
        }
    }

    /// Set `style` for `line`, `col` if:
    /// 1. That line and column exist in `StyledBuffer`
    /// 2. Existing style is `Style::NoStyle` or `Style::Quotation` or `overwrite` is `true`
    pub fn set_style(&mut self, line: usize, col: usize, style: Style, overwrite: bool) {
        if let Some(ref mut line) = self.text.get_mut(line) {
            if let Some(StyledChar { style: s, .. }) = line.get_mut(col) {
                if *s == Style::NoStyle || *s == Style::Quotation || overwrite {
                    *s = style;
                }
            }
        }
    }
}
<commit_msg>StyledBuffer::prepend: if line is empty, insert content without inserting spaces<commit_after>// Code for creating styled buffers

use crate::snippet::{Style, StyledString};

#[derive(Debug)]
pub struct StyledBuffer {
    text: Vec<Vec<StyledChar>>,
}

#[derive(Debug)]
struct StyledChar {
    chr: char,
    style: Style,
}

impl StyledChar {
    fn new(chr: char, style: Style) -> Self {
        StyledChar { chr, style }
    }
}

impl Default for StyledChar {
    fn default() -> Self {
        StyledChar::new(' ', Style::NoStyle)
    }
}

impl StyledBuffer {
    pub fn new() -> StyledBuffer {
        StyledBuffer { text: vec![] }
    }

    /// Returns content of `StyledBuffer` splitted by lines and line styles
    pub fn render(&self) -> Vec<Vec<StyledString>> {
        // Tabs are assumed to have been replaced by spaces in calling code.
        debug_assert!(self.text.iter().all(|r| !r.iter().any(|sc| sc.chr == '\t')));

        let mut output: Vec<Vec<StyledString>> = vec![];
        let mut styled_vec: Vec<StyledString> = vec![];

        for styled_row in &self.text {
            let mut current_style = Style::NoStyle;
            let mut current_text = String::new();

            for sc in styled_row {
                if sc.style != current_style {
                    if !current_text.is_empty() {
                        styled_vec.push(StyledString { text: current_text, style: current_style });
                    }
                    current_style = sc.style;
                    current_text = String::new();
                }
                current_text.push(sc.chr);
            }
            if !current_text.is_empty() {
                styled_vec.push(StyledString { text: current_text, style: current_style });
            }

            // We're done with the row, push and keep going
            output.push(styled_vec);

            styled_vec = vec![];
        }

        output
    }

    fn ensure_lines(&mut self, line: usize) {
        while line >= self.text.len() {
            self.text.push(vec![]);
        }
    }

    /// Sets `chr` with `style` for given `line`, `col`.
    /// If line not exist in `StyledBuffer`, adds lines up to given
    /// and fills last line with spaces and `Style::NoStyle` style
    pub fn putc(&mut self, line: usize, col: usize, chr: char, style: Style) {
        self.ensure_lines(line);
        if col < self.text[line].len() {
            self.text[line][col] = StyledChar::new(chr, style);
        } else {
            let mut i = self.text[line].len();
            while i < col {
                self.text[line].push(StyledChar::default());
                i += 1;
            }
            self.text[line].push(StyledChar::new(chr, style));
        }
    }

    /// Sets `string` with `style` for given `line`, starting from `col`.
    /// If line not exist in `StyledBuffer`, adds lines up to given
    /// and fills last line with spaces and `Style::NoStyle` style
    pub fn puts(&mut self, line: usize, col: usize, string: &str, style: Style) {
        let mut n = col;
        for c in string.chars() {
            self.putc(line, n, c, style);
            n += 1;
        }
    }

    /// For given `line` inserts `string` with `style` before old content of that line,
    /// adding lines if needed
    pub fn prepend(&mut self, line: usize, string: &str, style: Style) {
        self.ensure_lines(line);
        let string_len = string.chars().count();

        if !self.text[line].is_empty() {
            // Push the old content over to make room for new content
            for _ in 0..string_len {
                self.text[line].insert(0, StyledChar::default());
            }
        }

        self.puts(line, 0, string, style);
    }

    /// For given `line` inserts `string` with `style` after old content of that line,
    /// adding lines if needed
    pub fn append(&mut self, line: usize, string: &str, style: Style) {
        if line >= self.text.len() {
            self.puts(line, 0, string, style);
        } else {
            let col = self.text[line].len();
            self.puts(line, col, string, style);
        }
    }

    pub fn num_lines(&self) -> usize {
        self.text.len()
    }

    /// Set `style` for `line`, `col_start..col_end` range if:
    /// 1. That line and column range exist in `StyledBuffer`
    /// 2. `overwrite` is `true` or existing style is `Style::NoStyle` or `Style::Quotation`
    pub fn set_style_range(
        &mut self,
        line: usize,
        col_start: usize,
        col_end: usize,
        style: Style,
        overwrite: bool,
    ) {
        for col in col_start..col_end {
            self.set_style(line, col, style, overwrite);
        }
    }

    /// Set `style` for `line`, `col` if:
    /// 1. That line and column exist in `StyledBuffer`
    /// 2. Existing style is `Style::NoStyle` or `Style::Quotation` or `overwrite` is `true`
    pub fn set_style(&mut self, line: usize, col: usize, style: Style, overwrite: bool) {
        if let Some(ref mut line) = self.text.get_mut(line) {
            if let Some(StyledChar { style: s, .. }) = line.get_mut(col) {
                if *s == Style::NoStyle || *s == Style::Quotation || overwrite {
                    *s = style;
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>// We add this `extern crate` here to ensure that bindgen is up-to-date and
// rebuilt, even though we aren't using any of its types or functions here, only
// indirectly calling the executable.
#[allow(dead_code)]
extern crate bindgen;

use std::env;
use std::fs;
use std::io::Read;
use std::path::{Path, PathBuf};
use std::process;

const TEST_BATCH_DEFAULT_SIZE: usize = 16;

fn spawn_run_bindgen<P, Q, R>(run_bindgen: P, bindgen: Q, header: R) -> process::Child
    where P: AsRef<Path>,
          Q: AsRef<Path>,
          R: AsRef<Path>
{
    let run_bindgen = run_bindgen.as_ref();
    let bindgen = bindgen.as_ref();
    let header = header.as_ref();

    // Convert from "tests/headers/foo.hpp" to "tests/expectations/foo.rs" by
    // saving the filename, popping off "headers/foo.hpp", pushing
    // "expectations", pushing the saved filename, and finally modifying the
    // extension.

    let mut expected = PathBuf::from(header);
    let file_name = expected.file_name()
        .expect("Should have filename")
        .to_os_string();
    expected.pop();
    expected.pop();
    expected.push("expectations");
    expected.push(file_name);
    expected.set_extension("rs");

    let mut cmd = process::Command::new(run_bindgen);
    cmd.stdout(process::Stdio::piped())
        .stderr(process::Stdio::piped())
        .arg(bindgen)
        .arg(header)
        .arg(expected);

    if cfg!(feature = "llvm_stable") {
        cmd.arg("--feature")
            .arg("llvm_stable");
    }

    cmd.spawn()
        .expect("Should be able to spawn run-bindgen.py child process")
}

#[test]
fn run_bindgen_tests() {
    let crate_root = env::var("CARGO_MANIFEST_DIR")
        .expect("should have CARGO_MANIFEST_DIR environment variable");

    let mut run_bindgen = PathBuf::from(&crate_root);
    run_bindgen.push("tests");
    run_bindgen.push("tools");
    run_bindgen.push("run-bindgen.py");

    let mut bindgen = PathBuf::from(&crate_root);
    bindgen.push("target");
    bindgen.push("debug");
    bindgen.push("bindgen");
    if !bindgen.is_file() {
        panic!("{} is not a file! Build bindgen before running tests.",
               bindgen.display());
    }

    let mut headers_dir = PathBuf::from(&crate_root);
    headers_dir.push("tests");
    headers_dir.push("headers");

    let entries = fs::read_dir(&headers_dir)
        .expect("Should read directory")
        .map(|result| result.expect("Should read directory entry"));

    let tests = entries.filter(|entry| {
        match entry.path().extension().map(|s| s.to_str()) {
            Some(Some("h")) |
            Some(Some("hpp")) => true,
            _ => false,
        }
    }).collect::<Vec<_>>();

    let batch_size = env::var("BINDGEN_TEST_BATCH_SIZE")
        .ok()
        .and_then(|x| x.parse::<usize>().ok())
        .unwrap_or(TEST_BATCH_DEFAULT_SIZE);

    // Spawn batch_size child to run in parallel
    // and wait on all of them before processing the next batch

    let children = tests.chunks(batch_size).map(|x| {
        x.iter().map(|entry| {
            let child = spawn_run_bindgen(run_bindgen.clone(), bindgen.clone(), entry.path());
            (entry.path(), child)
        }).collect::<Vec<_>>()
    });

    let failures: Vec<_> = children.flat_map(|x| {
        x.into_iter().filter_map(|(path, mut child)| {
            let passed = child.wait()
                .expect("Should wait on child process")
                .success();

            if passed { None } else { Some((path, child)) }
        })
    })
    .collect();

    let num_failures = failures.len();

    for (path, child) in failures {
        println!("FAIL: {}", path.display());

        let mut buf = String::new();

        child.stdout
            .expect("should have stdout piped")
            .read_to_string(&mut buf)
            .expect("should read child's stdout");
        for line in buf.lines() {
            println!("child stdout> {}", line);
        }

        child.stderr
            .expect("should have stderr piped")
            .read_to_string(&mut buf)
            .expect("should read child's stderr");
        for line in buf.lines() {
            println!("child stderr> {}", line);
        }
    }

    if num_failures > 0 {
        panic!("{} test failures!", num_failures);
    }
}
<commit_msg>Use the appropriate debug/release bindgen binary in tests<commit_after>// We add this `extern crate` here to ensure that bindgen is up-to-date and
// rebuilt, even though we aren't using any of its types or functions here, only
// indirectly calling the executable.
#[allow(dead_code)]
extern crate bindgen;

use std::env;
use std::fs;
use std::io::Read;
use std::path::{Path, PathBuf};
use std::process;

const TEST_BATCH_DEFAULT_SIZE: usize = 16;

fn spawn_run_bindgen<P, Q, R>(run_bindgen: P, bindgen: Q, header: R) -> process::Child
    where P: AsRef<Path>,
          Q: AsRef<Path>,
          R: AsRef<Path>
{
    let run_bindgen = run_bindgen.as_ref();
    let bindgen = bindgen.as_ref();
    let header = header.as_ref();

    // Convert from "tests/headers/foo.hpp" to "tests/expectations/foo.rs" by
    // saving the filename, popping off "headers/foo.hpp", pushing
    // "expectations", pushing the saved filename, and finally modifying the
    // extension.

    let mut expected = PathBuf::from(header);
    let file_name = expected.file_name()
        .expect("Should have filename")
        .to_os_string();
    expected.pop();
    expected.pop();
    expected.push("expectations");
    expected.push(file_name);
    expected.set_extension("rs");

    let mut cmd = process::Command::new(run_bindgen);
    cmd.stdout(process::Stdio::piped())
        .stderr(process::Stdio::piped())
        .arg(bindgen)
        .arg(header)
        .arg(expected);

    if cfg!(feature = "llvm_stable") {
        cmd.arg("--feature")
            .arg("llvm_stable");
    }

    cmd.spawn()
        .expect("Should be able to spawn run-bindgen.py child process")
}

#[test]
fn run_bindgen_tests() {
    let crate_root = env::var("CARGO_MANIFEST_DIR")
        .expect("should have CARGO_MANIFEST_DIR environment variable");

    let mut run_bindgen = PathBuf::from(&crate_root);
    run_bindgen.push("tests");
    run_bindgen.push("tools");
    run_bindgen.push("run-bindgen.py");

    let mut bindgen = PathBuf::from(&crate_root);
    bindgen.push("target");
    if cfg!(debug_assertions) {
        bindgen.push("debug");
    } else {
        bindgen.push("release");
    }
    bindgen.push("bindgen");
    if !bindgen.is_file() {
        panic!("{} is not a file! Build bindgen before running tests.",
               bindgen.display());
    }

    let mut headers_dir = PathBuf::from(&crate_root);
    headers_dir.push("tests");
    headers_dir.push("headers");

    let entries = fs::read_dir(&headers_dir)
        .expect("Should read directory")
        .map(|result| result.expect("Should read directory entry"));

    let tests = entries.filter(|entry| {
        match entry.path().extension().map(|s| s.to_str()) {
            Some(Some("h")) |
            Some(Some("hpp")) => true,
            _ => false,
        }
    }).collect::<Vec<_>>();

    let batch_size = env::var("BINDGEN_TEST_BATCH_SIZE")
        .ok()
        .and_then(|x| x.parse::<usize>().ok())
        .unwrap_or(TEST_BATCH_DEFAULT_SIZE);

    // Spawn batch_size child to run in parallel
    // and wait on all of them before processing the next batch

    let children = tests.chunks(batch_size).map(|x| {
        x.iter().map(|entry| {
            let child = spawn_run_bindgen(run_bindgen.clone(), bindgen.clone(), entry.path());
            (entry.path(), child)
        }).collect::<Vec<_>>()
    });

    let failures: Vec<_> = children.flat_map(|x| {
        x.into_iter().filter_map(|(path, mut child)| {
            let passed = child.wait()
                .expect("Should wait on child process")
                .success();

            if passed { None } else { Some((path, child)) }
        })
    })
    .collect();

    let num_failures = failures.len();

    for (path, child) in failures {
        println!("FAIL: {}", path.display());

        let mut buf = String::new();

        child.stdout
            .expect("should have stdout piped")
            .read_to_string(&mut buf)
            .expect("should read child's stdout");
        for line in buf.lines() {
            println!("child stdout> {}", line);
        }

        child.stderr
            .expect("should have stderr piped")
            .read_to_string(&mut buf)
            .expect("should read child's stderr");
        for line in buf.lines() {
            println!("child stderr> {}", line);
        }
    }

    if num_failures > 0 {
        panic!("{} test failures!", num_failures);
    }
}
<|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/. */

#![allow(unsafe_code)]

//! A drop-in replacement for string_cache, but backed by Gecko `nsIAtom`s.

use gecko_bindings::bindings::Gecko_AddRefAtom;
use gecko_bindings::bindings::Gecko_Atomize;
use gecko_bindings::bindings::Gecko_Atomize16;
use gecko_bindings::bindings::Gecko_ReleaseAtom;
use gecko_bindings::structs::nsIAtom;
use nsstring::{nsAString, nsString};
use precomputed_hash::PrecomputedHash;
use std::ascii::AsciiExt;
use std::borrow::{Cow, Borrow};
use std::char::{self, DecodeUtf16};
use std::fmt::{self, Write};
use std::hash::{Hash, Hasher};
use std::iter::Cloned;
use std::mem;
use std::ops::Deref;
use std::slice;

#[macro_use]
#[allow(improper_ctypes, non_camel_case_types, missing_docs)]
pub mod atom_macro {
    include!(concat!(env!("OUT_DIR"), "/gecko/atom_macro.rs"));
}

#[macro_use]
pub mod namespace;

pub use self::namespace::{Namespace, WeakNamespace};

macro_rules! local_name {
    ($s: tt) => { atom!($s) }
}

/// A strong reference to a Gecko atom.
#[derive(PartialEq, Eq)]
pub struct Atom(*mut WeakAtom);

/// An atom *without* a strong reference.
///
/// Only usable as `&'a WeakAtom`,
/// where `'a` is the lifetime of something that holds a strong reference to that atom.
pub struct WeakAtom(nsIAtom);

/// A BorrowedAtom for Gecko is just a weak reference to a `nsIAtom`, that
/// hasn't been bumped.
pub type BorrowedAtom<'a> = &'a WeakAtom;

impl Deref for Atom {
    type Target = WeakAtom;

    #[inline]
    fn deref(&self) -> &WeakAtom {
        unsafe {
            &*self.0
        }
    }
}

impl PrecomputedHash for Atom {
    #[inline]
    fn precomputed_hash(&self) -> u32 {
        self.get_hash()
    }
}

impl Borrow<WeakAtom> for Atom {
    #[inline]
    fn borrow(&self) -> &WeakAtom {
        self
    }
}

impl Eq for WeakAtom {}
impl PartialEq for WeakAtom {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        let weak: *const WeakAtom = self;
        let other: *const WeakAtom = other;
        weak == other
    }
}

unsafe impl Send for Atom {}
unsafe impl Sync for Atom {}
unsafe impl Sync for WeakAtom {}

impl WeakAtom {
    /// Construct a `WeakAtom` from a raw `nsIAtom`.
    #[inline]
    pub unsafe fn new<'a>(atom: *const nsIAtom) -> &'a mut Self {
        &mut *(atom as *mut WeakAtom)
    }

    /// Clone this atom, bumping the refcount if the atom is not static.
    #[inline]
    pub fn clone(&self) -> Atom {
        Atom::from(self.as_ptr())
    }

    /// Get the atom hash.
    #[inline]
    pub fn get_hash(&self) -> u32 {
        self.0.mHash
    }

    /// Get the atom as a slice of utf-16 chars.
    #[inline]
    pub fn as_slice(&self) -> &[u16] {
        unsafe {
            slice::from_raw_parts((*self.as_ptr()).mString, self.len() as usize)
        }
    }

    // NOTE: don't expose this, since it's slow, and easy to be misused.
    fn chars(&self) -> DecodeUtf16<Cloned<slice::Iter<u16>>> {
        char::decode_utf16(self.as_slice().iter().cloned())
    }

    /// Execute `cb` with the string that this atom represents.
    ///
    /// Find alternatives to this function when possible, please, since it's
    /// pretty slow.
    pub fn with_str<F, Output>(&self, cb: F) -> Output
        where F: FnOnce(&str) -> Output
    {
        // FIXME(bholley): We should measure whether it makes more sense to
        // cache the UTF-8 version in the Gecko atom table somehow.
        let owned = self.to_string();
        cb(&owned)
    }

    /// Convert this Atom into a string, decoding the UTF-16 bytes.
    ///
    /// Find alternatives to this function when possible, please, since it's
    /// pretty slow.
    #[inline]
    pub fn to_string(&self) -> String {
        String::from_utf16(self.as_slice()).unwrap()
    }

    /// Returns whether this atom is static.
    #[inline]
    pub fn is_static(&self) -> bool {
        unsafe {
            (*self.as_ptr()).mIsStatic() != 0
        }
    }

    /// Returns the length of the atom string.
    #[inline]
    pub fn len(&self) -> u32 {
        // FIXME(emilio): re-introduce bitfield accessors:
        //
        // https://github.com/servo/rust-bindgen/issues/519
        unsafe {
            (*self.as_ptr())._bitfield_1 & 0x7FFFFFFF
        }
    }

    /// Returns whether this atom is the empty string.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns the atom as a mutable pointer.
    #[inline]
    pub fn as_ptr(&self) -> *mut nsIAtom {
        let const_ptr: *const nsIAtom = &self.0;
        const_ptr as *mut nsIAtom
    }

    /// Convert this atom to ASCII lower-case
    pub fn to_ascii_lowercase(&self) -> Atom {
        let slice = self.as_slice();
        match slice.iter().position(|&char16| (b'A' as u16) <= char16 && char16 <= (b'Z' as u16)) {
            None => self.clone(),
            Some(i) => {
                let mut buffer: [u16; 64] = unsafe { mem::uninitialized() };
                let mut vec;
                let mutable_slice = if let Some(buffer_prefix) = buffer.get_mut(..slice.len()) {
                    buffer_prefix.copy_from_slice(slice);
                    buffer_prefix
                } else {
                    vec = slice.to_vec();
                    &mut vec
                };
                for char16 in &mut mutable_slice[i..] {
                    if *char16 <= 0x7F {
                        *char16 = (*char16 as u8).to_ascii_lowercase() as u16
                    }
                }
                Atom::from(&*mutable_slice)
            }
        }
    }

    /// Return whether two atoms are ASCII-case-insensitive matches
    pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
        if self == other {
            return true;
        }

        let a = self.as_slice();
        let b = other.as_slice();
        a.len() == b.len() && a.iter().zip(b).all(|(&a16, &b16)| {
            if a16 <= 0x7F && b16 <= 0x7F {
                (a16 as u8).eq_ignore_ascii_case(&(b16 as u8))
            } else {
                a16 == b16
            }
        })
    }

    /// Return whether this atom is an ASCII-case-insensitive match for the given string
    pub fn eq_str_ignore_ascii_case(&self, other: &str) -> bool {
        self.chars().map(|r| r.map(|c: char| c.to_ascii_lowercase()))
        .eq(other.chars().map(|c: char| Ok(c.to_ascii_lowercase())))
    }
}

impl fmt::Debug for WeakAtom {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        write!(w, "Gecko WeakAtom({:p}, {})", self, self)
    }
}

impl fmt::Display for WeakAtom {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        for c in self.chars() {
            w.write_char(c.unwrap_or(char::REPLACEMENT_CHARACTER))?
        }
        Ok(())
    }
}

impl Atom {
    /// Execute a callback with the atom represented by `ptr`.
    pub unsafe fn with<F, R>(ptr: *mut nsIAtom, callback: F) -> R where F: FnOnce(&Atom) -> R {
        let atom = Atom(WeakAtom::new(ptr));
        let ret = callback(&atom);
        mem::forget(atom);
        ret
    }

    /// Creates an atom from an static atom pointer without checking in release
    /// builds.
    ///
    /// Right now it's only used by the atom macro, and ideally it should keep
    /// that way, now we have sugar for is_static, creating atoms using
    /// Atom::from should involve almost no overhead.
    #[inline]
    unsafe fn from_static(ptr: *mut nsIAtom) -> Self {
        let atom = Atom(ptr as *mut WeakAtom);
        debug_assert!(atom.is_static(),
                      "Called from_static for a non-static atom!");
        atom
    }

    /// Creates an atom from a dynamic atom pointer that has already had AddRef
    /// called on it.
    #[inline]
    pub unsafe fn from_addrefed(ptr: *mut nsIAtom) -> Self {
        debug_assert!(!ptr.is_null());
        unsafe {
            Atom(WeakAtom::new(ptr))
        }
    }

    /// Convert this atom into an addrefed nsIAtom pointer.
    #[inline]
    pub fn into_addrefed(self) -> *mut nsIAtom {
        let ptr = self.as_ptr();
        mem::forget(self);
        ptr
    }
}

impl Hash for Atom {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        state.write_u32(self.get_hash());
    }
}

impl Hash for WeakAtom {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        state.write_u32(self.get_hash());
    }
}

impl Clone for Atom {
    #[inline(always)]
    fn clone(&self) -> Atom {
        Atom::from(self.as_ptr())
    }
}

impl Drop for Atom {
    #[inline]
    fn drop(&mut self) {
        if !self.is_static() {
            unsafe {
                Gecko_ReleaseAtom(self.as_ptr());
            }
        }
    }
}

impl Default for Atom {
    #[inline]
    fn default() -> Self {
        atom!("")
    }
}

impl fmt::Debug for Atom {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        write!(w, "Gecko Atom({:p}, {})", self.0, self)
    }
}

impl fmt::Display for Atom {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        unsafe {
            (&*self.0).fmt(w)
        }
    }
}

impl<'a> From<&'a str> for Atom {
    #[inline]
    fn from(string: &str) -> Atom {
        debug_assert!(string.len() <= u32::max_value() as usize);
        unsafe {
            Atom(WeakAtom::new(
                Gecko_Atomize(string.as_ptr() as *const _, string.len() as u32)
            ))
        }
    }
}

impl<'a> From<&'a [u16]> for Atom {
    #[inline]
    fn from(slice: &[u16]) -> Atom {
        Atom::from(&*nsString::from(slice))
    }
}

impl<'a> From<&'a nsAString> for Atom {
    #[inline]
    fn from(string: &nsAString) -> Atom {
        unsafe {
            Atom(WeakAtom::new(
                Gecko_Atomize16(string)
            ))
        }
    }
}

impl<'a> From<Cow<'a, str>> for Atom {
    #[inline]
    fn from(string: Cow<'a, str>) -> Atom {
        Atom::from(&*string)
    }
}

impl From<String> for Atom {
    #[inline]
    fn from(string: String) -> Atom {
        Atom::from(&*string)
    }
}

impl From<*mut nsIAtom> for Atom {
    #[inline]
    fn from(ptr: *mut nsIAtom) -> Atom {
        debug_assert!(!ptr.is_null());
        unsafe {
            let ret = Atom(WeakAtom::new(ptr));
            if !ret.is_static() {
                Gecko_AddRefAtom(ptr);
            }
            ret
        }
    }
}
<commit_msg>stylo: We've had bitfield accessors for a while now.<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/. */

#![allow(unsafe_code)]

//! A drop-in replacement for string_cache, but backed by Gecko `nsIAtom`s.

use gecko_bindings::bindings::Gecko_AddRefAtom;
use gecko_bindings::bindings::Gecko_Atomize;
use gecko_bindings::bindings::Gecko_Atomize16;
use gecko_bindings::bindings::Gecko_ReleaseAtom;
use gecko_bindings::structs::nsIAtom;
use nsstring::{nsAString, nsString};
use precomputed_hash::PrecomputedHash;
use std::ascii::AsciiExt;
use std::borrow::{Cow, Borrow};
use std::char::{self, DecodeUtf16};
use std::fmt::{self, Write};
use std::hash::{Hash, Hasher};
use std::iter::Cloned;
use std::mem;
use std::ops::Deref;
use std::slice;

#[macro_use]
#[allow(improper_ctypes, non_camel_case_types, missing_docs)]
pub mod atom_macro {
    include!(concat!(env!("OUT_DIR"), "/gecko/atom_macro.rs"));
}

#[macro_use]
pub mod namespace;

pub use self::namespace::{Namespace, WeakNamespace};

macro_rules! local_name {
    ($s: tt) => { atom!($s) }
}

/// A strong reference to a Gecko atom.
#[derive(PartialEq, Eq)]
pub struct Atom(*mut WeakAtom);

/// An atom *without* a strong reference.
///
/// Only usable as `&'a WeakAtom`,
/// where `'a` is the lifetime of something that holds a strong reference to that atom.
pub struct WeakAtom(nsIAtom);

/// A BorrowedAtom for Gecko is just a weak reference to a `nsIAtom`, that
/// hasn't been bumped.
pub type BorrowedAtom<'a> = &'a WeakAtom;

impl Deref for Atom {
    type Target = WeakAtom;

    #[inline]
    fn deref(&self) -> &WeakAtom {
        unsafe {
            &*self.0
        }
    }
}

impl PrecomputedHash for Atom {
    #[inline]
    fn precomputed_hash(&self) -> u32 {
        self.get_hash()
    }
}

impl Borrow<WeakAtom> for Atom {
    #[inline]
    fn borrow(&self) -> &WeakAtom {
        self
    }
}

impl Eq for WeakAtom {}
impl PartialEq for WeakAtom {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        let weak: *const WeakAtom = self;
        let other: *const WeakAtom = other;
        weak == other
    }
}

unsafe impl Send for Atom {}
unsafe impl Sync for Atom {}
unsafe impl Sync for WeakAtom {}

impl WeakAtom {
    /// Construct a `WeakAtom` from a raw `nsIAtom`.
    #[inline]
    pub unsafe fn new<'a>(atom: *const nsIAtom) -> &'a mut Self {
        &mut *(atom as *mut WeakAtom)
    }

    /// Clone this atom, bumping the refcount if the atom is not static.
    #[inline]
    pub fn clone(&self) -> Atom {
        Atom::from(self.as_ptr())
    }

    /// Get the atom hash.
    #[inline]
    pub fn get_hash(&self) -> u32 {
        self.0.mHash
    }

    /// Get the atom as a slice of utf-16 chars.
    #[inline]
    pub fn as_slice(&self) -> &[u16] {
        unsafe {
            slice::from_raw_parts((*self.as_ptr()).mString, self.len() as usize)
        }
    }

    // NOTE: don't expose this, since it's slow, and easy to be misused.
    fn chars(&self) -> DecodeUtf16<Cloned<slice::Iter<u16>>> {
        char::decode_utf16(self.as_slice().iter().cloned())
    }

    /// Execute `cb` with the string that this atom represents.
    ///
    /// Find alternatives to this function when possible, please, since it's
    /// pretty slow.
    pub fn with_str<F, Output>(&self, cb: F) -> Output
        where F: FnOnce(&str) -> Output
    {
        // FIXME(bholley): We should measure whether it makes more sense to
        // cache the UTF-8 version in the Gecko atom table somehow.
        let owned = self.to_string();
        cb(&owned)
    }

    /// Convert this Atom into a string, decoding the UTF-16 bytes.
    ///
    /// Find alternatives to this function when possible, please, since it's
    /// pretty slow.
    #[inline]
    pub fn to_string(&self) -> String {
        String::from_utf16(self.as_slice()).unwrap()
    }

    /// Returns whether this atom is static.
    #[inline]
    pub fn is_static(&self) -> bool {
        unsafe {
            (*self.as_ptr()).mIsStatic() != 0
        }
    }

    /// Returns the length of the atom string.
    #[inline]
    pub fn len(&self) -> u32 {
        unsafe {
            (*self.as_ptr()).mLength()
        }
    }

    /// Returns whether this atom is the empty string.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns the atom as a mutable pointer.
    #[inline]
    pub fn as_ptr(&self) -> *mut nsIAtom {
        let const_ptr: *const nsIAtom = &self.0;
        const_ptr as *mut nsIAtom
    }

    /// Convert this atom to ASCII lower-case
    pub fn to_ascii_lowercase(&self) -> Atom {
        let slice = self.as_slice();
        match slice.iter().position(|&char16| (b'A' as u16) <= char16 && char16 <= (b'Z' as u16)) {
            None => self.clone(),
            Some(i) => {
                let mut buffer: [u16; 64] = unsafe { mem::uninitialized() };
                let mut vec;
                let mutable_slice = if let Some(buffer_prefix) = buffer.get_mut(..slice.len()) {
                    buffer_prefix.copy_from_slice(slice);
                    buffer_prefix
                } else {
                    vec = slice.to_vec();
                    &mut vec
                };
                for char16 in &mut mutable_slice[i..] {
                    if *char16 <= 0x7F {
                        *char16 = (*char16 as u8).to_ascii_lowercase() as u16
                    }
                }
                Atom::from(&*mutable_slice)
            }
        }
    }

    /// Return whether two atoms are ASCII-case-insensitive matches
    pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
        if self == other {
            return true;
        }

        let a = self.as_slice();
        let b = other.as_slice();
        a.len() == b.len() && a.iter().zip(b).all(|(&a16, &b16)| {
            if a16 <= 0x7F && b16 <= 0x7F {
                (a16 as u8).eq_ignore_ascii_case(&(b16 as u8))
            } else {
                a16 == b16
            }
        })
    }

    /// Return whether this atom is an ASCII-case-insensitive match for the given string
    pub fn eq_str_ignore_ascii_case(&self, other: &str) -> bool {
        self.chars().map(|r| r.map(|c: char| c.to_ascii_lowercase()))
        .eq(other.chars().map(|c: char| Ok(c.to_ascii_lowercase())))
    }
}

impl fmt::Debug for WeakAtom {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        write!(w, "Gecko WeakAtom({:p}, {})", self, self)
    }
}

impl fmt::Display for WeakAtom {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        for c in self.chars() {
            w.write_char(c.unwrap_or(char::REPLACEMENT_CHARACTER))?
        }
        Ok(())
    }
}

impl Atom {
    /// Execute a callback with the atom represented by `ptr`.
    pub unsafe fn with<F, R>(ptr: *mut nsIAtom, callback: F) -> R where F: FnOnce(&Atom) -> R {
        let atom = Atom(WeakAtom::new(ptr));
        let ret = callback(&atom);
        mem::forget(atom);
        ret
    }

    /// Creates an atom from an static atom pointer without checking in release
    /// builds.
    ///
    /// Right now it's only used by the atom macro, and ideally it should keep
    /// that way, now we have sugar for is_static, creating atoms using
    /// Atom::from should involve almost no overhead.
    #[inline]
    unsafe fn from_static(ptr: *mut nsIAtom) -> Self {
        let atom = Atom(ptr as *mut WeakAtom);
        debug_assert!(atom.is_static(),
                      "Called from_static for a non-static atom!");
        atom
    }

    /// Creates an atom from a dynamic atom pointer that has already had AddRef
    /// called on it.
    #[inline]
    pub unsafe fn from_addrefed(ptr: *mut nsIAtom) -> Self {
        debug_assert!(!ptr.is_null());
        unsafe {
            Atom(WeakAtom::new(ptr))
        }
    }

    /// Convert this atom into an addrefed nsIAtom pointer.
    #[inline]
    pub fn into_addrefed(self) -> *mut nsIAtom {
        let ptr = self.as_ptr();
        mem::forget(self);
        ptr
    }
}

impl Hash for Atom {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        state.write_u32(self.get_hash());
    }
}

impl Hash for WeakAtom {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        state.write_u32(self.get_hash());
    }
}

impl Clone for Atom {
    #[inline(always)]
    fn clone(&self) -> Atom {
        Atom::from(self.as_ptr())
    }
}

impl Drop for Atom {
    #[inline]
    fn drop(&mut self) {
        if !self.is_static() {
            unsafe {
                Gecko_ReleaseAtom(self.as_ptr());
            }
        }
    }
}

impl Default for Atom {
    #[inline]
    fn default() -> Self {
        atom!("")
    }
}

impl fmt::Debug for Atom {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        write!(w, "Gecko Atom({:p}, {})", self.0, self)
    }
}

impl fmt::Display for Atom {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        unsafe {
            (&*self.0).fmt(w)
        }
    }
}

impl<'a> From<&'a str> for Atom {
    #[inline]
    fn from(string: &str) -> Atom {
        debug_assert!(string.len() <= u32::max_value() as usize);
        unsafe {
            Atom(WeakAtom::new(
                Gecko_Atomize(string.as_ptr() as *const _, string.len() as u32)
            ))
        }
    }
}

impl<'a> From<&'a [u16]> for Atom {
    #[inline]
    fn from(slice: &[u16]) -> Atom {
        Atom::from(&*nsString::from(slice))
    }
}

impl<'a> From<&'a nsAString> for Atom {
    #[inline]
    fn from(string: &nsAString) -> Atom {
        unsafe {
            Atom(WeakAtom::new(
                Gecko_Atomize16(string)
            ))
        }
    }
}

impl<'a> From<Cow<'a, str>> for Atom {
    #[inline]
    fn from(string: Cow<'a, str>) -> Atom {
        Atom::from(&*string)
    }
}

impl From<String> for Atom {
    #[inline]
    fn from(string: String) -> Atom {
        Atom::from(&*string)
    }
}

impl From<*mut nsIAtom> for Atom {
    #[inline]
    fn from(ptr: *mut nsIAtom) -> Atom {
        debug_assert!(!ptr.is_null());
        unsafe {
            let ret = Atom(WeakAtom::new(ptr));
            if !ret.is_static() {
                Gecko_AddRefAtom(ptr);
            }
            ret
        }
    }
}
<|endoftext|>


<commit_before>use std::process::Command;
use std::env;

fn main() {
    cargo_dep("CSharp");
    cargo_dep("cpp/dynamic");
}

fn cargo_dep(path: &str) {
    let config = match env::var("PROFILE").unwrap_or_else(|e| panic!("Count not get confing from env {}", e)).as_ref() {
        "debug" => "debug",
        "release" => "release",
        cfg => panic!("Unknown config {}", cfg)
    };

    //Run cargo
    let mut cargo = Command::new("cargo");

    cargo.current_dir(path)
        .arg("build");

    if config == "release" {
        cargo.arg("--release");
    }

    cargo.output()
        .unwrap_or_else(|e| panic!("Unable to run cargo {}", e));
}
<commit_msg>Fixing case issue in build script<commit_after>use std::process::Command;
use std::env;

fn main() {
    cargo_dep("CSharp");
    cargo_dep("Cpp/dynamic");
}

fn cargo_dep(path: &str) {
    let config = match env::var("PROFILE").unwrap_or_else(|e| panic!("Count not get confing from env {}", e)).as_ref() {
        "debug" => "debug",
        "release" => "release",
        cfg => panic!("Unknown config {}", cfg)
    };

    //Run cargo
    let mut cargo = Command::new("cargo");

    cargo.current_dir(path)
        .arg("build");

    if config == "release" {
        cargo.arg("--release");
    }

    cargo.output()
        .unwrap_or_else(|e| panic!("Unable to run cargo {}", e));
}
<|endoftext|>


<commit_before>use std::cmp;
use ItemCategory::*;

struct Character {
    hp: i32,
    damage: i32,
    armor: i32
}

impl Character {
    fn new(hp: i32) -> Character {
        Character {hp, damage: 0, armor: 0}
    }
}

#[derive(Debug, PartialEq)]
enum ItemCategory {
    Weapon,
    Armor,
    Ring
}

#[derive(Debug)]
struct Item {
    category: ItemCategory,
    cost: i32,
    damage: i32,
    armor: i32
}

fn get_damage(attacker: &Character, defender: &Character) -> i32 {
    cmp::max(attacker.damage - defender.armor, 1)
}

fn is_winner<'a>(player: &'a Character, target: &'a Character) -> bool {
    let player_damage = get_damage(player, target);
    let target_damage = get_damage(target, player);
    let player_turns = (player.hp as f32 / target_damage as f32).ceil();
    let target_turns = (target.hp as f32 / player_damage as f32).ceil();

    target_turns <= player_turns
}

fn get_item_combinations<'a>(items: &'a Vec<&'a Item>) -> Vec<Vec<&'a Item>> {
    let weapons = items.iter().filter(|x| x.category == Weapon).collect::<Vec<_>>();
    let armors = items.iter().filter(|x| x.category == Armor).collect::<Vec<_>>();
    let rings = items.iter().filter(|x| x.category == Ring).collect::<Vec<_>>();
    let mut choices = Vec::new();

    for &&weapon in weapons.iter() {
        choices.push(vec![weapon]);

        for &&armor in armors.iter() {
            choices.push(vec![weapon, armor]);

            for i in 0..rings.len() {
                choices.push(vec![weapon, *rings[i]]);
                choices.push(vec![weapon, armor, *rings[i]]);

                for j in i + 1..rings.len() {
                    choices.push(vec![weapon, *rings[i], *rings[j]]);
                    choices.push(vec![weapon, armor, *rings[i], *rings[j]]);
                }
            }
        }
    }

    choices
}

fn get_character(hp: i32, items: &Vec<&Item>) -> Character {
    items.iter().fold(Character::new(hp), |mut character, item| {
        character.damage += item.damage;
        character.armor += item.armor;
        character
    })
}

fn get_winning_items<'a>(
    items: &'a Vec<&'a Item>,
    hp: i32,
    target: &Character
) -> Option<Vec<&'a Item>> {
    get_item_combinations(items).into_iter()
    .filter(|combination| {
        is_winner(&get_character(hp, combination), target)
    })
    .min_by_key(|combination| {
        combination.iter()
            .map(|item| item.cost)
            .sum::<i32>()
    })
}

fn main() {
    let items = vec![
        Item {
            category: Weapon,
            cost: 8,
            damage: 4,
            armor: 0
        },
        Item {
            category: Weapon,
            cost: 10,
            damage: 5,
            armor: 0
        },
        Item {
            category: Weapon,
            cost: 25,
            damage: 6,
            armor: 0
        },
        Item {
            category: Weapon,
            cost: 40,
            damage: 7,
            armor: 0
        },
        Item {
            category: Weapon,
            cost: 74,
            damage: 8,
            armor: 0
        },
        Item {
            category: Armor,
            cost: 13,
            damage: 0,
            armor: 1
        },
        Item {
            category: Armor,
            cost: 31,
            damage: 0,
            armor: 2
        },
        Item {
            category: Armor,
            cost: 53,
            damage: 0,
            armor: 3
        },
        Item {
            category: Armor,
            cost: 75,
            damage: 0,
            armor: 4
        },
        Item {
            category: Armor,
            cost: 102,
            damage: 0,
            armor: 5
        },
        Item {
            category: Ring,
            cost: 25,
            damage: 1,
            armor: 0
        },
        Item {
            category: Ring,
            cost: 50,
            damage: 2,
            armor: 0
        },
        Item {
            category: Ring,
            cost: 100,
            damage: 3,
            armor: 0
        },
        Item {
            category: Ring,
            cost: 20,
            damage: 0,
            armor: 1
        },
        Item {
            category: Ring,
            cost: 40,
            damage: 0,
            armor: 2
        },
        Item {
            category: Ring,
            cost: 80,
            damage: 0,
            armor: 3
        }
    ];

    let boss = Character {
        hp: 100,
        damage: 8,
        armor: 2
    };

    let items = items.iter().collect();

    let combinations = get_winning_items(&items, 100, &boss).unwrap();
    println!("{:#?}", combinations);
}
<commit_msg>Add 2015 day 21 part 2 solution<commit_after>use std::cmp;
use ItemCategory::*;

struct Character {
    hp: i32,
    damage: i32,
    armor: i32
}

impl Character {
    fn new(hp: i32) -> Character {
        Character {hp, damage: 0, armor: 0}
    }
}

#[derive(Debug, PartialEq)]
enum ItemCategory {
    Weapon,
    Armor,
    Ring
}

#[derive(Debug)]
struct Item {
    category: ItemCategory,
    cost: i32,
    damage: i32,
    armor: i32
}

fn get_damage(attacker: &Character, defender: &Character) -> i32 {
    cmp::max(attacker.damage - defender.armor, 1)
}

fn is_winner<'a>(player: &'a Character, target: &'a Character) -> bool {
    let player_damage = get_damage(player, target);
    let target_damage = get_damage(target, player);
    let player_turns = (player.hp as f32 / target_damage as f32).ceil();
    let target_turns = (target.hp as f32 / player_damage as f32).ceil();

    target_turns <= player_turns
}

fn list_item_combinations<'a>(items: &'a Vec<&'a Item>) -> Vec<Vec<&'a Item>> {
    let weapons = items.iter().cloned().filter(|x| x.category == Weapon).collect::<Vec<_>>();
    let armors = items.iter().cloned().filter(|x| x.category == Armor).collect::<Vec<_>>();
    let rings = items.iter().cloned().filter(|x| x.category == Ring).collect::<Vec<_>>();
    let mut choices = Vec::new();

    for &weapon in weapons.iter() {
        choices.push(vec![weapon]);

        for i in 0..rings.len() {
            choices.push(vec![weapon, rings[i]]);
            for j in i + 1..rings.len() {
                choices.push(vec![weapon, rings[i], rings[j]]);
            }
        }

        for &armor in armors.iter() {
            choices.push(vec![weapon, armor]);

            for i in 0..rings.len() {
                choices.push(vec![weapon, armor, rings[i]]);
                for j in i + 1..rings.len() {
                    choices.push(vec![weapon, armor, rings[i], rings[j]]);
                }
            }
        }
    }

    choices
}

fn get_character(hp: i32, items: &Vec<&Item>) -> Character {
    items.iter().fold(Character::new(hp), |mut character, item| {
        character.damage += item.damage;
        character.armor += item.armor;
        character
    })
}

fn get_cheapest_winning_items<'a>(
    items: &'a Vec<&'a Item>,
    hp: i32,
    target: &Character
) -> Option<Vec<&'a Item>> {
    list_item_combinations(items).into_iter()
    .filter(|combination| {
        is_winner(&get_character(hp, combination), target)
    })
    .min_by_key(|combination| {
        combination.iter()
        .map(|item| item.cost)
        .sum::<i32>()
    })
}

fn get_costliest_losing_items<'a>(
    items: &'a Vec<&'a Item>,
    hp: i32,
    target: &Character
) -> Option<Vec<&'a Item>> {
    list_item_combinations(items).into_iter()
    .filter(|combination| {
        !is_winner(&get_character(hp, combination), target)
    })
    .max_by_key(|combination| {
        combination.iter()
        .map(|item| item.cost)
        .sum::<i32>()
    })
}

fn main() {
    let items = vec![
        Item {
            category: Weapon,
            cost: 8,
            damage: 4,
            armor: 0
        },
        Item {
            category: Weapon,
            cost: 10,
            damage: 5,
            armor: 0
        },
        Item {
            category: Weapon,
            cost: 25,
            damage: 6,
            armor: 0
        },
        Item {
            category: Weapon,
            cost: 40,
            damage: 7,
            armor: 0
        },
        Item {
            category: Weapon,
            cost: 74,
            damage: 8,
            armor: 0
        },
        Item {
            category: Armor,
            cost: 13,
            damage: 0,
            armor: 1
        },
        Item {
            category: Armor,
            cost: 31,
            damage: 0,
            armor: 2
        },
        Item {
            category: Armor,
            cost: 53,
            damage: 0,
            armor: 3
        },
        Item {
            category: Armor,
            cost: 75,
            damage: 0,
            armor: 4
        },
        Item {
            category: Armor,
            cost: 102,
            damage: 0,
            armor: 5
        },
        Item {
            category: Ring,
            cost: 25,
            damage: 1,
            armor: 0
        },
        Item {
            category: Ring,
            cost: 50,
            damage: 2,
            armor: 0
        },
        Item {
            category: Ring,
            cost: 100,
            damage: 3,
            armor: 0
        },
        Item {
            category: Ring,
            cost: 20,
            damage: 0,
            armor: 1
        },
        Item {
            category: Ring,
            cost: 40,
            damage: 0,
            armor: 2
        },
        Item {
            category: Ring,
            cost: 80,
            damage: 0,
            armor: 3
        }
    ];

    let boss = Character {
        hp: 100,
        damage: 8,
        armor: 2
    };

    let items = items.iter().collect();

    let combinations = get_cheapest_winning_items(&items, 100, &boss).unwrap();
    println!("Part 1: {}", combinations.into_iter().map(|item| item.cost).sum::<i32>());

    let combinations = get_costliest_losing_items(&items, 100, &boss).unwrap();
    println!("Part 2: {}", combinations.into_iter().map(|item| item.cost).sum::<i32>());
}
<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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.

//! Utilities for printing record batches. Note this module is not
//! available unless `feature = "prettyprint"` is enabled.

use crate::record_batch::RecordBatch;

use prettytable::format;
use prettytable::{Cell, Row, Table};

use crate::error::Result;

use super::display::array_value_to_string;

///! Create a visual representation of record batches
pub fn pretty_format_batches(results: &[RecordBatch]) -> Result<String> {
    Ok(create_table(results)?.to_string())
}

///! Prints a visual representation of record batches to stdout
pub fn print_batches(results: &[RecordBatch]) -> Result<()> {
    create_table(results)?.printstd();
    Ok(())
}

///! Convert a series of record batches into a table
fn create_table(results: &[RecordBatch]) -> Result<Table> {
    let mut table = Table::new();
    table.set_format(*format::consts::FORMAT_NO_LINESEP_WITH_TITLE);

    if results.is_empty() {
        return Ok(table);
    }

    let schema = results[0].schema();

    let mut header = Vec::new();
    for field in schema.fields() {
        header.push(Cell::new(&field.name()));
    }
    table.set_titles(Row::new(header));

    for batch in results {
        for row in 0..batch.num_rows() {
            let mut cells = Vec::new();
            for col in 0..batch.num_columns() {
                let column = batch.column(col);
                cells.push(Cell::new(&array_value_to_string(&column, row)?));
            }
            table.add_row(Row::new(cells));
        }
    }

    Ok(table)
}

#[cfg(test)]
mod tests {
    use crate::{
        array::{
            self, new_null_array, Array, Date32Array, Date64Array, PrimitiveBuilder,
            StringBuilder, StringDictionaryBuilder, Time32MillisecondArray,
            Time32SecondArray, Time64MicrosecondArray, Time64NanosecondArray,
            TimestampMicrosecondArray, TimestampMillisecondArray,
            TimestampNanosecondArray, TimestampSecondArray,
        },
        datatypes::{DataType, Field, Int32Type, Schema},
    };

    use super::*;
    use std::sync::Arc;

    #[test]
    fn test_pretty_format_batches() -> Result<()> {
        // define a schema.
        let schema = Arc::new(Schema::new(vec![
            Field::new("a", DataType::Utf8, true),
            Field::new("b", DataType::Int32, true),
        ]));

        // define data.
        let batch = RecordBatch::try_new(
            schema,
            vec![
                Arc::new(array::StringArray::from(vec![
                    Some("a"),
                    Some("b"),
                    None,
                    Some("d"),
                ])),
                Arc::new(array::Int32Array::from(vec![
                    Some(1),
                    None,
                    Some(10),
                    Some(100),
                ])),
            ],
        )?;

        let table = pretty_format_batches(&[batch])?;

        let expected = vec![
            "+---+-----+",
            "| a | b   |",
            "+---+-----+",
            "| a | 1   |",
            "| b |     |",
            "|   | 10  |",
            "| d | 100 |",
            "+---+-----+",
        ];

        let actual: Vec<&str> = table.lines().collect();

        assert_eq!(expected, actual, "Actual result:\n{}", table);

        Ok(())
    }

    #[test]
    fn test_pretty_format_null() {
        let schema = Arc::new(Schema::new(vec![
            Field::new("a", DataType::Utf8, true),
            Field::new("b", DataType::Int32, true),
            Field::new("c", DataType::Null, true),
        ]));

        let num_rows = 4;
        let arrays = schema
            .fields()
            .iter()
            .map(|f| new_null_array(f.data_type(), num_rows))
            .collect();

        // define data (null)
        let batch = RecordBatch::try_new(schema, arrays).unwrap();

        let table = pretty_format_batches(&[batch]).unwrap();

        let expected = vec![
            "+---+---+---+",
            "| a | b | c |",
            "+---+---+---+",
            "|   |   |   |",
            "|   |   |   |",
            "|   |   |   |",
            "|   |   |   |",
            "+---+---+---+",
        ];

        let actual: Vec<&str> = table.lines().collect();

        assert_eq!(expected, actual, "Actual result:\n{:#?}", table);
    }

    #[test]
    fn test_pretty_format_dictionary() -> Result<()> {
        // define a schema.
        let field_type =
            DataType::Dictionary(Box::new(DataType::Int32), Box::new(DataType::Utf8));
        let schema = Arc::new(Schema::new(vec![Field::new("d1", field_type, true)]));

        let keys_builder = PrimitiveBuilder::<Int32Type>::new(10);
        let values_builder = StringBuilder::new(10);
        let mut builder = StringDictionaryBuilder::new(keys_builder, values_builder);

        builder.append("one")?;
        builder.append_null()?;
        builder.append("three")?;
        let array = Arc::new(builder.finish());

        let batch = RecordBatch::try_new(schema, vec![array])?;

        let table = pretty_format_batches(&[batch])?;

        let expected = vec![
            "+-------+",
            "| d1    |",
            "+-------+",
            "| one   |",
            "|       |",
            "| three |",
            "+-------+",
        ];

        let actual: Vec<&str> = table.lines().collect();

        assert_eq!(expected, actual, "Actual result:\n{}", table);

        Ok(())
    }

    /// Generate an array with type $ARRAYTYPE with a numeric value of
    /// $VALUE, and compare $EXPECTED_RESULT to the output of
    /// formatting that array with `pretty_format_batches`
    macro_rules! check_datetime {
        ($ARRAYTYPE:ident, $VALUE:expr, $EXPECTED_RESULT:expr) => {
            let mut builder = $ARRAYTYPE::builder(10);
            builder.append_value($VALUE).unwrap();
            builder.append_null().unwrap();
            let array = builder.finish();

            let schema = Arc::new(Schema::new(vec![Field::new(
                "f",
                array.data_type().clone(),
                true,
            )]));
            let batch = RecordBatch::try_new(schema, vec![Arc::new(array)]).unwrap();

            let table = pretty_format_batches(&[batch]).expect("formatting batches");

            let expected = $EXPECTED_RESULT;
            let actual: Vec<&str> = table.lines().collect();

            assert_eq!(expected, actual, "Actual result:\n\n{:#?}\n\n", actual);
        };
    }

    #[test]
    fn test_pretty_format_timestamp_second() {
        let expected = vec![
            "+---------------------+",
            "| f                   |",
            "+---------------------+",
            "| 1970-05-09 14:25:11 |",
            "|                     |",
            "+---------------------+",
        ];
        check_datetime!(TimestampSecondArray, 11111111, expected);
    }

    #[test]
    fn test_pretty_format_timestamp_millisecond() {
        let expected = vec![
            "+-------------------------+",
            "| f                       |",
            "+-------------------------+",
            "| 1970-01-01 03:05:11.111 |",
            "|                         |",
            "+-------------------------+",
        ];
        check_datetime!(TimestampMillisecondArray, 11111111, expected);
    }

    #[test]
    fn test_pretty_format_timestamp_microsecond() {
        let expected = vec![
            "+----------------------------+",
            "| f                          |",
            "+----------------------------+",
            "| 1970-01-01 00:00:11.111111 |",
            "|                            |",
            "+----------------------------+",
        ];
        check_datetime!(TimestampMicrosecondArray, 11111111, expected);
    }

    #[test]
    fn test_pretty_format_timestamp_nanosecond() {
        let expected = vec![
            "+-------------------------------+",
            "| f                             |",
            "+-------------------------------+",
            "| 1970-01-01 00:00:00.011111111 |",
            "|                               |",
            "+-------------------------------+",
        ];
        check_datetime!(TimestampNanosecondArray, 11111111, expected);
    }

    #[test]
    fn test_pretty_format_date_32() {
        let expected = vec![
            "+------------+",
            "| f          |",
            "+------------+",
            "| 1973-05-19 |",
            "|            |",
            "+------------+",
        ];
        check_datetime!(Date32Array, 1234, expected);
    }

    #[test]
    fn test_pretty_format_date_64() {
        let expected = vec![
            "+------------+",
            "| f          |",
            "+------------+",
            "| 2005-03-18 |",
            "|            |",
            "+------------+",
        ];
        check_datetime!(Date64Array, 1111111100000, expected);
    }

    #[test]
    fn test_pretty_format_time_32_second() {
        let expected = vec![
            "+----------+",
            "| f        |",
            "+----------+",
            "| 00:18:31 |",
            "|          |",
            "+----------+",
        ];
        check_datetime!(Time32SecondArray, 1111, expected);
    }

    #[test]
    fn test_pretty_format_time_32_millisecond() {
        let expected = vec![
            "+--------------+",
            "| f            |",
            "+--------------+",
            "| 03:05:11.111 |",
            "|              |",
            "+--------------+",
        ];
        check_datetime!(Time32MillisecondArray, 11111111, expected);
    }

    #[test]
    fn test_pretty_format_time_64_microsecond() {
        let expected = vec![
            "+-----------------+",
            "| f               |",
            "+-----------------+",
            "| 00:00:11.111111 |",
            "|                 |",
            "+-----------------+",
        ];
        check_datetime!(Time64MicrosecondArray, 11111111, expected);
    }

    #[test]
    fn test_pretty_format_time_64_nanosecond() {
        let expected = vec![
            "+--------------------+",
            "| f                  |",
            "+--------------------+",
            "| 00:00:00.011111111 |",
            "|                    |",
            "+--------------------+",
        ];
        check_datetime!(Time64NanosecondArray, 11111111, expected);
    }
}
<commit_msg>ARROW-11898: [Rust] Pretty print columns<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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.

//! Utilities for printing record batches. Note this module is not
//! available unless `feature = "prettyprint"` is enabled.

use crate::{array::ArrayRef, record_batch::RecordBatch};

use prettytable::format;
use prettytable::{Cell, Row, Table};

use crate::error::Result;

use super::display::array_value_to_string;

///! Create a visual representation of record batches
pub fn pretty_format_batches(results: &[RecordBatch]) -> Result<String> {
    Ok(create_table(results)?.to_string())
}

///! Create a visual representation of columns
pub fn pretty_format_columns(col_name: &str, results: &[ArrayRef]) -> Result<String> {
    Ok(create_column(col_name, results)?.to_string())
}

///! Prints a visual representation of record batches to stdout
pub fn print_batches(results: &[RecordBatch]) -> Result<()> {
    create_table(results)?.printstd();
    Ok(())
}

///! Prints a visual representation of a list of column to stdout
pub fn print_columns(col_name: &str, results: &[ArrayRef]) -> Result<()> {
    create_column(col_name, results)?.printstd();
    Ok(())
}

///! Convert a series of record batches into a table
fn create_table(results: &[RecordBatch]) -> Result<Table> {
    let mut table = Table::new();
    table.set_format(*format::consts::FORMAT_NO_LINESEP_WITH_TITLE);

    if results.is_empty() {
        return Ok(table);
    }

    let schema = results[0].schema();

    let mut header = Vec::new();
    for field in schema.fields() {
        header.push(Cell::new(&field.name()));
    }
    table.set_titles(Row::new(header));

    for batch in results {
        for row in 0..batch.num_rows() {
            let mut cells = Vec::new();
            for col in 0..batch.num_columns() {
                let column = batch.column(col);
                cells.push(Cell::new(&array_value_to_string(&column, row)?));
            }
            table.add_row(Row::new(cells));
        }
    }

    Ok(table)
}

fn create_column(field: &str, columns: &[ArrayRef]) -> Result<Table> {
    let mut table = Table::new();
    table.set_format(*format::consts::FORMAT_NO_LINESEP_WITH_TITLE);

    if columns.is_empty() {
        return Ok(table);
    }

    let header = vec![Cell::new(field)];
    table.set_titles(Row::new(header));

    for col in columns {
        for row in 0..col.len() {
            let mut cells = Vec::new();
            cells.push(Cell::new(&array_value_to_string(&col, row)?));
            table.add_row(Row::new(cells));
        }
    }

    Ok(table)
}

#[cfg(test)]
mod tests {
    use crate::{
        array::{
            self, new_null_array, Array, Date32Array, Date64Array, PrimitiveBuilder,
            StringBuilder, StringDictionaryBuilder, Time32MillisecondArray,
            Time32SecondArray, Time64MicrosecondArray, Time64NanosecondArray,
            TimestampMicrosecondArray, TimestampMillisecondArray,
            TimestampNanosecondArray, TimestampSecondArray,
        },
        datatypes::{DataType, Field, Int32Type, Schema},
    };

    use super::*;
    use std::sync::Arc;

    #[test]
    fn test_pretty_format_batches() -> Result<()> {
        // define a schema.
        let schema = Arc::new(Schema::new(vec![
            Field::new("a", DataType::Utf8, true),
            Field::new("b", DataType::Int32, true),
        ]));

        // define data.
        let batch = RecordBatch::try_new(
            schema,
            vec![
                Arc::new(array::StringArray::from(vec![
                    Some("a"),
                    Some("b"),
                    None,
                    Some("d"),
                ])),
                Arc::new(array::Int32Array::from(vec![
                    Some(1),
                    None,
                    Some(10),
                    Some(100),
                ])),
            ],
        )?;

        let table = pretty_format_batches(&[batch])?;

        let expected = vec![
            "+---+-----+",
            "| a | b   |",
            "+---+-----+",
            "| a | 1   |",
            "| b |     |",
            "|   | 10  |",
            "| d | 100 |",
            "+---+-----+",
        ];

        let actual: Vec<&str> = table.lines().collect();

        assert_eq!(expected, actual, "Actual result:\n{}", table);

        Ok(())
    }

    #[test]
    fn test_pretty_format_columns() -> Result<()> {
        let columns = vec![
            Arc::new(array::StringArray::from(vec![
                Some("a"),
                Some("b"),
                None,
                Some("d"),
            ])) as ArrayRef,
            Arc::new(array::StringArray::from(vec![Some("e"), None, Some("g")])),
        ];

        let table = pretty_format_columns("a", &columns)?;

        let expected = vec![
            "+---+", "| a |", "+---+", "| a |", "| b |", "|   |", "| d |", "| e |",
            "|   |", "| g |", "+---+",
        ];

        let actual: Vec<&str> = table.lines().collect();

        assert_eq!(expected, actual, "Actual result:\n{}", table);

        Ok(())
    }

    #[test]
    fn test_pretty_format_null() {
        let schema = Arc::new(Schema::new(vec![
            Field::new("a", DataType::Utf8, true),
            Field::new("b", DataType::Int32, true),
            Field::new("c", DataType::Null, true),
        ]));

        let num_rows = 4;
        let arrays = schema
            .fields()
            .iter()
            .map(|f| new_null_array(f.data_type(), num_rows))
            .collect();

        // define data (null)
        let batch = RecordBatch::try_new(schema, arrays).unwrap();

        let table = pretty_format_batches(&[batch]).unwrap();

        let expected = vec![
            "+---+---+---+",
            "| a | b | c |",
            "+---+---+---+",
            "|   |   |   |",
            "|   |   |   |",
            "|   |   |   |",
            "|   |   |   |",
            "+---+---+---+",
        ];

        let actual: Vec<&str> = table.lines().collect();

        assert_eq!(expected, actual, "Actual result:\n{:#?}", table);
    }

    #[test]
    fn test_pretty_format_dictionary() -> Result<()> {
        // define a schema.
        let field_type =
            DataType::Dictionary(Box::new(DataType::Int32), Box::new(DataType::Utf8));
        let schema = Arc::new(Schema::new(vec![Field::new("d1", field_type, true)]));

        let keys_builder = PrimitiveBuilder::<Int32Type>::new(10);
        let values_builder = StringBuilder::new(10);
        let mut builder = StringDictionaryBuilder::new(keys_builder, values_builder);

        builder.append("one")?;
        builder.append_null()?;
        builder.append("three")?;
        let array = Arc::new(builder.finish());

        let batch = RecordBatch::try_new(schema, vec![array])?;

        let table = pretty_format_batches(&[batch])?;

        let expected = vec![
            "+-------+",
            "| d1    |",
            "+-------+",
            "| one   |",
            "|       |",
            "| three |",
            "+-------+",
        ];

        let actual: Vec<&str> = table.lines().collect();

        assert_eq!(expected, actual, "Actual result:\n{}", table);

        Ok(())
    }

    /// Generate an array with type $ARRAYTYPE with a numeric value of
    /// $VALUE, and compare $EXPECTED_RESULT to the output of
    /// formatting that array with `pretty_format_batches`
    macro_rules! check_datetime {
        ($ARRAYTYPE:ident, $VALUE:expr, $EXPECTED_RESULT:expr) => {
            let mut builder = $ARRAYTYPE::builder(10);
            builder.append_value($VALUE).unwrap();
            builder.append_null().unwrap();
            let array = builder.finish();

            let schema = Arc::new(Schema::new(vec![Field::new(
                "f",
                array.data_type().clone(),
                true,
            )]));
            let batch = RecordBatch::try_new(schema, vec![Arc::new(array)]).unwrap();

            let table = pretty_format_batches(&[batch]).expect("formatting batches");

            let expected = $EXPECTED_RESULT;
            let actual: Vec<&str> = table.lines().collect();

            assert_eq!(expected, actual, "Actual result:\n\n{:#?}\n\n", actual);
        };
    }

    #[test]
    fn test_pretty_format_timestamp_second() {
        let expected = vec![
            "+---------------------+",
            "| f                   |",
            "+---------------------+",
            "| 1970-05-09 14:25:11 |",
            "|                     |",
            "+---------------------+",
        ];
        check_datetime!(TimestampSecondArray, 11111111, expected);
    }

    #[test]
    fn test_pretty_format_timestamp_millisecond() {
        let expected = vec![
            "+-------------------------+",
            "| f                       |",
            "+-------------------------+",
            "| 1970-01-01 03:05:11.111 |",
            "|                         |",
            "+-------------------------+",
        ];
        check_datetime!(TimestampMillisecondArray, 11111111, expected);
    }

    #[test]
    fn test_pretty_format_timestamp_microsecond() {
        let expected = vec![
            "+----------------------------+",
            "| f                          |",
            "+----------------------------+",
            "| 1970-01-01 00:00:11.111111 |",
            "|                            |",
            "+----------------------------+",
        ];
        check_datetime!(TimestampMicrosecondArray, 11111111, expected);
    }

    #[test]
    fn test_pretty_format_timestamp_nanosecond() {
        let expected = vec![
            "+-------------------------------+",
            "| f                             |",
            "+-------------------------------+",
            "| 1970-01-01 00:00:00.011111111 |",
            "|                               |",
            "+-------------------------------+",
        ];
        check_datetime!(TimestampNanosecondArray, 11111111, expected);
    }

    #[test]
    fn test_pretty_format_date_32() {
        let expected = vec![
            "+------------+",
            "| f          |",
            "+------------+",
            "| 1973-05-19 |",
            "|            |",
            "+------------+",
        ];
        check_datetime!(Date32Array, 1234, expected);
    }

    #[test]
    fn test_pretty_format_date_64() {
        let expected = vec![
            "+------------+",
            "| f          |",
            "+------------+",
            "| 2005-03-18 |",
            "|            |",
            "+------------+",
        ];
        check_datetime!(Date64Array, 1111111100000, expected);
    }

    #[test]
    fn test_pretty_format_time_32_second() {
        let expected = vec![
            "+----------+",
            "| f        |",
            "+----------+",
            "| 00:18:31 |",
            "|          |",
            "+----------+",
        ];
        check_datetime!(Time32SecondArray, 1111, expected);
    }

    #[test]
    fn test_pretty_format_time_32_millisecond() {
        let expected = vec![
            "+--------------+",
            "| f            |",
            "+--------------+",
            "| 03:05:11.111 |",
            "|              |",
            "+--------------+",
        ];
        check_datetime!(Time32MillisecondArray, 11111111, expected);
    }

    #[test]
    fn test_pretty_format_time_64_microsecond() {
        let expected = vec![
            "+-----------------+",
            "| f               |",
            "+-----------------+",
            "| 00:00:11.111111 |",
            "|                 |",
            "+-----------------+",
        ];
        check_datetime!(Time64MicrosecondArray, 11111111, expected);
    }

    #[test]
    fn test_pretty_format_time_64_nanosecond() {
        let expected = vec![
            "+--------------------+",
            "| f                  |",
            "+--------------------+",
            "| 00:00:00.011111111 |",
            "|                    |",
            "+--------------------+",
        ];
        check_datetime!(Time64NanosecondArray, 11111111, expected);
    }
}
<|endoftext|>


<commit_before>
use std::io::{self, Write};

use html5ever;
use html5ever::driver::{parse_document, ParseOpts};
use html5ever::tree_builder::TreeSink;
use html5ever::tendril::TendrilSink;
use html5ever::tendril::StrTendril;
use html5ever::serialize::{Serializable, Serializer, TraversalScope};

use string_cache::QualName;

use super::Document;
use dom;

#[derive(Clone, Debug, PartialEq)]
pub enum Node {
    Comment(CommentNode),
    Element(ElementNode),
    Text(TextNode),
}

impl Node {
    pub fn expect_text(&self) -> &TextNode {
        if let &Node::Text(ref node) = self {
            node
        } else {
            panic!("Expected text node, got: {:?}", self);
        }
    }

    pub fn expect_comment(&self) -> &CommentNode {
        if let &Node::Comment(ref node) = self {
            node
        } else {
            panic!("Expected comment node, got: {:?}", self);
        }
    }

    pub fn expect_element(&self) -> &ElementNode {
        if let &Node::Element(ref node) = self {
            node
        } else {
            panic!("Expected element node, got: {:?}", self);
        }
    }

    pub fn expect_element_mut(&mut self) -> &mut ElementNode {
        if let &mut Node::Element(ref mut node) = self {
            node
        } else {
            panic!("Expected element node, got: {:?}", self);
        }
    }

    pub fn parse_str(string: &str) -> Node {
        let parser = parse_document(dom::Dom::new(), ParseOpts::default()).from_utf8();
        let dom = parser.one(string.as_bytes());

        (&dom.fragment()).into()
    }
}

impl<'a> From<&'a dom::Handle> for Node {
    fn from(handle: &'a dom::Handle) -> Node {
        match *handle.borrow() {
            (dom::Node::Comment(ref text), _) => CommentNode::new(text.clone()).into(),
            (dom::Node::Element(ref name, ref attributes, ref children),
             _) => {
                let mut children = children.iter().map(|c| c.into());
                let element_type = match *name {
                    qualname!(html, "template") => {
                        let document = Document::new(None, children.next());
                        ElementType::Template(document)
                    }
                    _ => ElementType::Normal(children.collect()),
                };

                ElementNode::new(name.clone(), attributes.clone(), element_type).into()
            }
            (dom::Node::Text(ref text), _) => TextNode::new(text.clone()).into(),
            _ => panic!("expected comment, element or text, got: {:?}", handle),
        }
    }
}

impl From<TextNode> for Node {
    fn from(node: TextNode) -> Node {
        Node::Text(node)
    }
}

impl From<CommentNode> for Node {
    fn from(node: CommentNode) -> Node {
        Node::Comment(node)
    }
}

impl From<ElementNode> for Node {
    fn from(node: ElementNode) -> Node {
        Node::Element(node)
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct Attribute {
    name: QualName,
    value: StrTendril,
}

impl Attribute {
    pub fn new(name: QualName, value: StrTendril) -> Attribute {
        Attribute {
            name: name,
            value: value,
        }
    }

    pub fn new_string(name: String, value: String) -> Attribute {
        Attribute::new(QualName::new(ns!(), name.into()), value.into())
    }

    pub fn new_str(name: &str, value: &str) -> Attribute {
        Attribute::new_string(name.to_owned(), value.to_owned())
    }

    pub fn name(&self) -> &QualName {
        &self.name
    }

    pub fn value(&self) -> &StrTendril {
        &self.value
    }
}

impl From<html5ever::Attribute> for Attribute {
    fn from(attr: html5ever::Attribute) -> Attribute {
        Attribute {
            name: attr.name,
            value: attr.value,
        }
    }
}

impl Into<html5ever::Attribute> for Attribute {
    fn into(self) -> html5ever::Attribute {
        html5ever::Attribute {
            name: self.name,
            value: self.value,
        }
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct TextNode(StrTendril);

impl TextNode {
    pub fn new(text: StrTendril) -> TextNode {
        TextNode(text)
    }

    pub fn new_string(text: String) -> TextNode {
        TextNode::new(text.into())
    }

    pub fn new_str(text: &str) -> TextNode {
        TextNode::new_string(text.to_owned())
    }

    pub fn text(&self) -> &StrTendril {
        &self.0
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct CommentNode(StrTendril);

impl CommentNode {
    pub fn new(comment: StrTendril) -> CommentNode {
        CommentNode(comment)
    }

    pub fn text(&self) -> &StrTendril {
        &self.0
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum ElementType {
    Normal(Vec<Node>),
    Template(Document),
}

impl ElementType {
    pub fn new_normal() -> ElementType {
        ElementType::Normal(Vec::new())
    }

    pub fn new_template() -> ElementType {
        ElementType::Template(Document::new(None, None))
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct ElementNode {
    name: QualName,
    element_type: ElementType,
    attributes: Vec<Attribute>,
}

impl ElementNode {
    pub fn new(name: QualName,
               attributes: Vec<Attribute>,
               element_type: ElementType)
               -> ElementNode {
        ElementNode {
            name: name,
            element_type: element_type,
            attributes: attributes,
        }
    }

    pub fn expect_normal(&self) -> &[Node] {
        if let ElementType::Normal(ref children) = self.element_type {
            children
        } else {
            panic!("Expected normal element, got: {:?}", self);
        }
    }

    pub fn expect_normal_mut(&mut self) -> &mut Vec<Node> {
        if let ElementType::Normal(ref mut children) = self.element_type {
            children
        } else {
            panic!("Expected normal element, got: {:?}", self);
        }
    }

    pub fn expect_template(&self) -> &Document {
        if let ElementType::Template(ref document) = self.element_type {
            document
        } else {
            panic!("Expected template element, got: {:?}", self);
        }
    }

    pub fn name(&self) -> &QualName {
        &self.name
    }

    pub fn element_type(&self) -> &ElementType {
        &self.element_type
    }

    pub fn element_type_mut(&mut self) -> &mut ElementType {
        &mut self.element_type
    }

    pub fn attributes(&self) -> &[Attribute] {
        &self.attributes
    }

    pub fn attributes_mut(&mut self) -> &mut Vec<Attribute> {
        &mut self.attributes
    }
}

impl Serializable for Node {
    fn serialize<'wr, Wr: Write>(&self,
                                 serializer: &mut Serializer<'wr, Wr>,
                                 traversal_scope: TraversalScope)
                                 -> io::Result<()> {
        match (traversal_scope, self) {
            (_, &Node::Element(ref node)) => node.clone().serialize(serializer, traversal_scope),
            (TraversalScope::ChildrenOnly, _) => Ok(()),
            (TraversalScope::IncludeNode, &Node::Text(ref node)) => serializer.write_text(&node.0),
            (TraversalScope::IncludeNode, &Node::Comment(ref node)) => {
                serializer.write_comment(&node.0)
            }
        }
    }
}

impl Serializable for ElementNode {
    fn serialize<'wr, Wr: Write>(&self,
                                 serializer: &mut Serializer<'wr, Wr>,
                                 traversal_scope: TraversalScope)
                                 -> io::Result<()> {
        if traversal_scope == TraversalScope::IncludeNode {
            try!(serializer.start_elem(self.name.clone(),
                                       self.attributes.iter().map(|a| (&a.name, &a.value[..]))));
        }

        match self.element_type {
            ElementType::Normal(ref children) => {
                for child in children.iter() {
                    try!(child.clone().serialize(serializer, TraversalScope::IncludeNode));
                }
            }
            ElementType::Template(ref document) => {
                try!(document.clone().serialize(serializer, traversal_scope));
            }
        }

        if traversal_scope == TraversalScope::IncludeNode {
            try!(serializer.end_elem(self.name.clone()));
        }

        Ok(())
    }
}

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

    #[rustfmt_skip]
    const FRAGMENT: &'static str =
        "
Hello!
";

    #[test]
    fn test_parse_str() {
        let node = Node::parse_str(FRAGMENT);
        assert_eq!(node,
                   ElementNode::new(qualname!(html, "div"),
                                    vec![Attribute::new_str("id", "test")],
                                    ElementType::Normal(vec![TextNode::new_str("Hello!").into()]))
                       .into());
    }
}
<commit_msg>Removed expect_* and *_mut from node.rs<commit_after>
use std::io::{self, Write};

use html5ever;
use html5ever::driver::{parse_document, ParseOpts};
use html5ever::tree_builder::TreeSink;
use html5ever::tendril::TendrilSink;
use html5ever::tendril::StrTendril;
use html5ever::serialize::{Serializable, Serializer, TraversalScope};

use string_cache::QualName;

use super::Document;
use dom;

#[derive(Clone, Debug, PartialEq)]
pub enum Node {
    Comment(CommentNode),
    Element(ElementNode),
    Text(TextNode),
}

impl Node {
    pub fn parse_str(string: &str) -> Node {
        let parser = parse_document(dom::Dom::new(), ParseOpts::default()).from_utf8();
        let dom = parser.one(string.as_bytes());

        (&dom.fragment()).into()
    }
}

impl<'a> From<&'a dom::Handle> for Node {
    fn from(handle: &'a dom::Handle) -> Node {
        match *handle.borrow() {
            (dom::Node::Comment(ref text), _) => CommentNode::new(text.clone()).into(),
            (dom::Node::Element(ref name, ref attributes, ref children),
             _) => {
                let mut children = children.iter().map(|c| c.into());
                let element_type = match *name {
                    qualname!(html, "template") => {
                        let document = Document::new(None, children.next());
                        ElementType::Template(document)
                    }
                    _ => ElementType::Normal(children.collect()),
                };

                ElementNode::new(name.clone(), attributes.clone(), element_type).into()
            }
            (dom::Node::Text(ref text), _) => TextNode::new(text.clone()).into(),
            _ => panic!("expected comment, element or text, got: {:?}", handle),
        }
    }
}

impl From<TextNode> for Node {
    fn from(node: TextNode) -> Node {
        Node::Text(node)
    }
}

impl From<CommentNode> for Node {
    fn from(node: CommentNode) -> Node {
        Node::Comment(node)
    }
}

impl From<ElementNode> for Node {
    fn from(node: ElementNode) -> Node {
        Node::Element(node)
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct Attribute {
    name: QualName,
    value: StrTendril,
}

impl Attribute {
    pub fn new(name: QualName, value: StrTendril) -> Attribute {
        Attribute {
            name: name,
            value: value,
        }
    }

    pub fn new_string(name: String, value: String) -> Attribute {
        Attribute::new(QualName::new(ns!(), name.into()), value.into())
    }

    pub fn new_str(name: &str, value: &str) -> Attribute {
        Attribute::new_string(name.to_owned(), value.to_owned())
    }

    pub fn name(&self) -> &QualName {
        &self.name
    }

    pub fn value(&self) -> &StrTendril {
        &self.value
    }
}

impl From<html5ever::Attribute> for Attribute {
    fn from(attr: html5ever::Attribute) -> Attribute {
        Attribute {
            name: attr.name,
            value: attr.value,
        }
    }
}

impl Into<html5ever::Attribute> for Attribute {
    fn into(self) -> html5ever::Attribute {
        html5ever::Attribute {
            name: self.name,
            value: self.value,
        }
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct TextNode(StrTendril);

impl TextNode {
    pub fn new(text: StrTendril) -> TextNode {
        TextNode(text)
    }

    pub fn new_string(text: String) -> TextNode {
        TextNode::new(text.into())
    }

    pub fn new_str(text: &str) -> TextNode {
        TextNode::new_string(text.to_owned())
    }

    pub fn text(&self) -> &StrTendril {
        &self.0
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct CommentNode(StrTendril);

impl CommentNode {
    pub fn new(comment: StrTendril) -> CommentNode {
        CommentNode(comment)
    }

    pub fn text(&self) -> &StrTendril {
        &self.0
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum ElementType {
    Normal(Vec<Node>),
    Template(Document),
}

impl ElementType {
    pub fn new_normal() -> ElementType {
        ElementType::Normal(Vec::new())
    }

    pub fn new_template() -> ElementType {
        ElementType::Template(Document::new(None, None))
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct ElementNode {
    name: QualName,
    element_type: ElementType,
    attributes: Vec<Attribute>,
}

impl ElementNode {
    pub fn new(name: QualName,
               attributes: Vec<Attribute>,
               element_type: ElementType)
               -> ElementNode {
        ElementNode {
            name: name,
            element_type: element_type,
            attributes: attributes,
        }
    }

    pub fn name(&self) -> &QualName {
        &self.name
    }

    pub fn element_type(&self) -> &ElementType {
        &self.element_type
    }

    pub fn attributes(&self) -> &[Attribute] {
        &self.attributes
    }
}

impl Serializable for Node {
    fn serialize<'wr, Wr: Write>(&self,
                                 serializer: &mut Serializer<'wr, Wr>,
                                 traversal_scope: TraversalScope)
                                 -> io::Result<()> {
        match (traversal_scope, self) {
            (_, &Node::Element(ref node)) => node.clone().serialize(serializer, traversal_scope),
            (TraversalScope::ChildrenOnly, _) => Ok(()),
            (TraversalScope::IncludeNode, &Node::Text(ref node)) => serializer.write_text(&node.0),
            (TraversalScope::IncludeNode, &Node::Comment(ref node)) => {
                serializer.write_comment(&node.0)
            }
        }
    }
}

impl Serializable for ElementNode {
    fn serialize<'wr, Wr: Write>(&self,
                                 serializer: &mut Serializer<'wr, Wr>,
                                 traversal_scope: TraversalScope)
                                 -> io::Result<()> {
        if traversal_scope == TraversalScope::IncludeNode {
            try!(serializer.start_elem(self.name.clone(),
                                       self.attributes.iter().map(|a| (&a.name, &a.value[..]))));
        }

        match self.element_type {
            ElementType::Normal(ref children) => {
                for child in children.iter() {
                    try!(child.clone().serialize(serializer, TraversalScope::IncludeNode));
                }
            }
            ElementType::Template(ref document) => {
                try!(document.clone().serialize(serializer, traversal_scope));
            }
        }

        if traversal_scope == TraversalScope::IncludeNode {
            try!(serializer.end_elem(self.name.clone()));
        }

        Ok(())
    }
}

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

    #[rustfmt_skip]
    const FRAGMENT: &'static str =
        "
Hello!
";

    #[test]
    fn test_parse_str() {
        let node = Node::parse_str(FRAGMENT);
        assert_eq!(node,
                   ElementNode::new(qualname!(html, "div"),
                                    vec![Attribute::new_str("id", "test")],
                                    ElementType::Normal(vec![TextNode::new_str("Hello!").into()]))
                       .into());
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::hash;
use std::mem;

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

pub struct Owned;
pub struct Shared;

pub trait Ownership { }
impl Ownership for Owned { }
impl Ownership for Shared { }

#[unsafe_no_drop_flag]
pub struct Id<T: Message, O: Ownership = Owned> {
	ptr: *mut T,
}

impl<T: Message, O: Ownership> Id<T, O> {
	pub unsafe fn from_ptr(ptr: *mut T) -> Id<T, O> {
		match Id::maybe_from_ptr(ptr) {
			Some(id) => id,
			None => fail!("Attempted to construct an Id from a null pointer"),
		}
	}

	pub unsafe fn from_retained_ptr(ptr: *mut T) -> Id<T, O> {
		match Id::maybe_from_retained_ptr(ptr) {
			Some(id) => id,
			None => fail!("Attempted to construct an Id from a null pointer"),
		}
	}

	pub unsafe fn maybe_from_ptr(ptr: *mut T) -> Option<Id<T, O>> {
		// objc_msgSend is a no-op on null pointers
		msg_send![ptr retain];
		Id::maybe_from_retained_ptr(ptr)
	}

	pub unsafe fn maybe_from_retained_ptr(ptr: *mut T) -> Option<Id<T, O>> {
		if ptr.is_null() {
			None
		} else {
			Some(Id { ptr: ptr })
		}
	}
}

impl<T: Message> Id<T, Owned> {
	pub fn share(self) -> ShareId<T> {
		unsafe {
			mem::transmute(self)
		}
	}
}

impl<T: Message, O: Ownership> ToMessage for Id<T, O> {
	fn as_ptr(&self) -> *mut Object {
		self.ptr.as_ptr()
	}
}

#[unsafe_destructor]
impl<T: Message, O: Ownership> Drop for Id<T, O> {
	fn drop(&mut self) {
		if !self.ptr.is_null() {
			let ptr = mem::replace(&mut self.ptr, RawPtr::null());
			unsafe {
				msg_send![ptr release];
			}
		}
	}
}

impl<T: Message, O: Ownership> Deref<T> for Id<T, O> {
	fn deref(&self) -> &T {
		unsafe { &*self.ptr }
	}
}

impl<T: Message + PartialEq, O: Ownership> PartialEq for Id<T, O> {
	fn eq(&self, other: &Id<T, O>) -> bool {
		self.deref() == other.deref()
	}

	fn ne(&self, other: &Id<T, O>) -> bool {
		self.deref() != other.deref()
	}
}

impl<T: Message + Eq, O: Ownership> Eq for Id<T, O> { }

impl<T: Message + hash::Hash, O: Ownership> hash::Hash for Id<T, O> {
	fn hash(&self, state: &mut hash::sip::SipState) {
		self.deref().hash(state)
	}
}

impl<T: Message + fmt::Show, O: Ownership> fmt::Show for Id<T, O> {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		self.deref().fmt(f)
	}
}

pub type ShareId<T> = Id<T, Shared>;

pub trait IdVector<T> {
	fn as_refs_slice(&self) -> &[&T];
}

impl<T: Message, V: Slice<Id<T>>> IdVector<T> for V {
	fn as_refs_slice(&self) -> &[&T] {
		unsafe {
			mem::transmute(self.as_slice())
		}
	}
}

pub trait IntoIdVector<T> {
	unsafe fn into_id_vec(self) -> Vec<Id<T>>;
}

impl<T: Message> IntoIdVector<T> for Vec<*mut T> {
	unsafe fn into_id_vec(self) -> Vec<Id<T>> {
		for &ptr in self.iter() {
			msg_send![ptr retain];
		}
		mem::transmute(self)
	}
}

impl<'a, T: Message> IntoIdVector<T> for Vec<&'a T> {
	unsafe fn into_id_vec(self) -> Vec<Id<T>> {
		for &obj in self.iter() {
			msg_send![obj retain];
		}
		mem::transmute(self)
	}
}
<commit_msg>Made IdVector traits generic over ownership.<commit_after>use std::fmt;
use std::hash;
use std::mem;

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

pub struct Owned;
pub struct Shared;

pub trait Ownership { }
impl Ownership for Owned { }
impl Ownership for Shared { }

#[unsafe_no_drop_flag]
pub struct Id<T: Message, O: Ownership = Owned> {
	ptr: *mut T,
}

impl<T: Message, O: Ownership> Id<T, O> {
	pub unsafe fn from_ptr(ptr: *mut T) -> Id<T, O> {
		match Id::maybe_from_ptr(ptr) {
			Some(id) => id,
			None => fail!("Attempted to construct an Id from a null pointer"),
		}
	}

	pub unsafe fn from_retained_ptr(ptr: *mut T) -> Id<T, O> {
		match Id::maybe_from_retained_ptr(ptr) {
			Some(id) => id,
			None => fail!("Attempted to construct an Id from a null pointer"),
		}
	}

	pub unsafe fn maybe_from_ptr(ptr: *mut T) -> Option<Id<T, O>> {
		// objc_msgSend is a no-op on null pointers
		msg_send![ptr retain];
		Id::maybe_from_retained_ptr(ptr)
	}

	pub unsafe fn maybe_from_retained_ptr(ptr: *mut T) -> Option<Id<T, O>> {
		if ptr.is_null() {
			None
		} else {
			Some(Id { ptr: ptr })
		}
	}
}

impl<T: Message> Id<T, Owned> {
	pub fn share(self) -> ShareId<T> {
		unsafe {
			mem::transmute(self)
		}
	}
}

impl<T: Message, O: Ownership> ToMessage for Id<T, O> {
	fn as_ptr(&self) -> *mut Object {
		self.ptr.as_ptr()
	}
}

#[unsafe_destructor]
impl<T: Message, O: Ownership> Drop for Id<T, O> {
	fn drop(&mut self) {
		if !self.ptr.is_null() {
			let ptr = mem::replace(&mut self.ptr, RawPtr::null());
			unsafe {
				msg_send![ptr release];
			}
		}
	}
}

impl<T: Message, O: Ownership> Deref<T> for Id<T, O> {
	fn deref(&self) -> &T {
		unsafe { &*self.ptr }
	}
}

impl<T: Message + PartialEq, O: Ownership> PartialEq for Id<T, O> {
	fn eq(&self, other: &Id<T, O>) -> bool {
		self.deref() == other.deref()
	}

	fn ne(&self, other: &Id<T, O>) -> bool {
		self.deref() != other.deref()
	}
}

impl<T: Message + Eq, O: Ownership> Eq for Id<T, O> { }

impl<T: Message + hash::Hash, O: Ownership> hash::Hash for Id<T, O> {
	fn hash(&self, state: &mut hash::sip::SipState) {
		self.deref().hash(state)
	}
}

impl<T: Message + fmt::Show, O: Ownership> fmt::Show for Id<T, O> {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		self.deref().fmt(f)
	}
}

pub type ShareId<T> = Id<T, Shared>;

pub trait IdVector<T> {
	fn as_refs_slice(&self) -> &[&T];
}

impl<T: Message, O: Ownership, V: Slice<Id<T, O>>> IdVector<T> for V {
	fn as_refs_slice(&self) -> &[&T] {
		unsafe {
			mem::transmute(self.as_slice())
		}
	}
}

pub trait IntoIdVector<T> {
	unsafe fn into_id_vec<O: Ownership>(self) -> Vec<Id<T, O>>;
}

impl<T: Message> IntoIdVector<T> for Vec<*mut T> {
	unsafe fn into_id_vec<O: Ownership>(self) -> Vec<Id<T, O>> {
		for &ptr in self.iter() {
			msg_send![ptr retain];
		}
		mem::transmute(self)
	}
}

impl<'a, T: Message> IntoIdVector<T> for Vec<&'a T> {
	unsafe fn into_id_vec<O: Ownership>(self) -> Vec<Id<T, O>> {
		for &obj in self.iter() {
			msg_send![obj retain];
		}
		mem::transmute(self)
	}
}
<|endoftext|>