<commit_before>use util::{ZOPFLI_WINDOW_MASK, ZOPFLI_MIN_MATCH};

const HASH_SHIFT: i32 = 5;
const HASH_MASK: i32 = 32767;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Which {
    Hash1,
    Hash2,
}

pub struct HashThing {
    head: Vec<i32>,  /* Hash value to index of its most recent occurrence. */
    prev: Vec<u16>,  /* Index to index of prev. occurrence of same hash. */
    hashval: Vec<i32>,  /* Index to hash value at this index. */
    val: i32,  /* Current hash value. */
}

impl HashThing {
    fn new(window_size: usize) -> HashThing {
        HashThing {
            head: vec![-1; 65536],
            prev: (0..window_size as u16).collect(),
            hashval: vec![-1; window_size],
            val: 0,
        }
    }

    fn reset(&mut self, window_size: usize) {
        self.val = 0;
        self.head = vec![-1; 65536];
        self.prev = (0..window_size as u16).collect();
        self.hashval = vec![-1; window_size];
    }

    fn update(&mut self, hpos: usize) {
        self.hashval[hpos] = self.val;

        let index = self.val as usize;
        let head_index = self.head[index];
        if head_index != -1 && self.hashval[head_index as usize] == self.val {
            self.prev[hpos] = head_index as u16;
        } else {
            self.prev[hpos] = hpos as u16;
        }
        self.head[index] = hpos as i32;
    }
}

pub struct ZopfliHash {
    hash1: HashThing,
    hash2: HashThing,
    pub same: Vec<u16>,  /* Amount of repetitions of same byte after this .*/
}

impl ZopfliHash {
    pub fn new(window_size: usize) -> ZopfliHash {
        ZopfliHash {
            hash1: HashThing::new(window_size),
            hash2: HashThing::new(window_size),
            same: vec![0; window_size],
        }
    }

    pub fn reset(&mut self, window_size: usize) {
        self.hash1.reset(window_size);
        self.hash2.reset(window_size);
        self.same = vec![0; window_size];
    }

    pub fn warmup(&mut self, arr: &[u8], pos: usize, end: usize) {
        let c = arr[pos];
        self.update_val(c);

        if pos + 1 < end {
            let c = arr[pos + 1];
            self.update_val(c);
        }
    }

    /// Update the sliding hash value with the given byte. All calls to this function
    /// must be made on consecutive input characters. Since the hash value exists out
    /// of multiple input bytes, a few warmups with this function are needed initially.
    fn update_val(&mut self, c: u8) {
        self.hash1.val = ((self.hash1.val << HASH_SHIFT) ^ c as i32) & HASH_MASK;
    }

    pub fn update(&mut self, array: &[u8], pos: usize) {
        let hash_value = array.get(pos + ZOPFLI_MIN_MATCH - 1).cloned().unwrap_or(0);
        self.update_val(hash_value);

        let hpos = pos & ZOPFLI_WINDOW_MASK;

        self.hash1.update(hpos);

        // Update "same".
        let mut amount = 0;
        let same_index = pos.wrapping_sub(1) & ZOPFLI_WINDOW_MASK;
        let same = self.same[same_index];
        if same > 1 {
            amount = same as i32 - 1;
        }

        let mut another_index = pos + amount as usize + 1;
        let array_pos = array[pos];
        while another_index < array.len() && array_pos == array[another_index] && amount < -1 {
            amount += 1;
            another_index += 1;
        }
        let amount_u16 = amount as u16;
        self.same[hpos] = amount_u16;

        self.hash2.val = ((amount_u16.wrapping_sub(ZOPFLI_MIN_MATCH as u16) & 255) ^ self.hash1.val as u16) as i32;

        self.hash2.update(hpos);
    }

    pub fn head_at(&self, index: usize, which: Which) -> i32 {
        match which {
            Which::Hash1 => self.hash1.head[index],
            Which::Hash2 => self.hash2.head[index],
        }
    }

    pub fn prev_at(&self, index: usize, which: Which) -> u16 {
        match which {
            Which::Hash1 => self.hash1.prev[index],
            Which::Hash2 => self.hash2.prev[index],
        }
    }

    pub fn hash_val_at(&self, index: usize, which: Which) -> i32 {
        match which {
            Which::Hash1 => self.hash1.hashval[index],
            Which::Hash2 => self.hash2.hashval[index],
        }
    }

    pub fn val(&self, which: Which) -> i32 {
        match which {
            Which::Hash1 => self.hash1.val,
            Which::Hash2 => self.hash2.val,
        }
    }
}
<commit_msg>Extract what we're assigning to outside the conditional<commit_after>use util::{ZOPFLI_WINDOW_MASK, ZOPFLI_MIN_MATCH};

const HASH_SHIFT: i32 = 5;
const HASH_MASK: i32 = 32767;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Which {
    Hash1,
    Hash2,
}

pub struct HashThing {
    head: Vec<i32>,  /* Hash value to index of its most recent occurrence. */
    prev: Vec<u16>,  /* Index to index of prev. occurrence of same hash. */
    hashval: Vec<i32>,  /* Index to hash value at this index. */
    val: i32,  /* Current hash value. */
}

impl HashThing {
    fn new(window_size: usize) -> HashThing {
        HashThing {
            head: vec![-1; 65536],
            prev: (0..window_size as u16).collect(),
            hashval: vec![-1; window_size],
            val: 0,
        }
    }

    fn reset(&mut self, window_size: usize) {
        self.val = 0;
        self.head = vec![-1; 65536];
        self.prev = (0..window_size as u16).collect();
        self.hashval = vec![-1; window_size];
    }

    fn update(&mut self, hpos: usize) {
        self.hashval[hpos] = self.val;

        let index = self.val as usize;
        let head_index = self.head[index];
        self.prev[hpos] = if head_index != -1 && self.hashval[head_index as usize] == self.val {
            head_index as u16
        } else {
            hpos as u16
        };
        self.head[index] = hpos as i32;
    }
}

pub struct ZopfliHash {
    hash1: HashThing,
    hash2: HashThing,
    pub same: Vec<u16>,  /* Amount of repetitions of same byte after this .*/
}

impl ZopfliHash {
    pub fn new(window_size: usize) -> ZopfliHash {
        ZopfliHash {
            hash1: HashThing::new(window_size),
            hash2: HashThing::new(window_size),
            same: vec![0; window_size],
        }
    }

    pub fn reset(&mut self, window_size: usize) {
        self.hash1.reset(window_size);
        self.hash2.reset(window_size);
        self.same = vec![0; window_size];
    }

    pub fn warmup(&mut self, arr: &[u8], pos: usize, end: usize) {
        let c = arr[pos];
        self.update_val(c);

        if pos + 1 < end {
            let c = arr[pos + 1];
            self.update_val(c);
        }
    }

    /// Update the sliding hash value with the given byte. All calls to this function
    /// must be made on consecutive input characters. Since the hash value exists out
    /// of multiple input bytes, a few warmups with this function are needed initially.
    fn update_val(&mut self, c: u8) {
        self.hash1.val = ((self.hash1.val << HASH_SHIFT) ^ c as i32) & HASH_MASK;
    }

    pub fn update(&mut self, array: &[u8], pos: usize) {
        let hash_value = array.get(pos + ZOPFLI_MIN_MATCH - 1).cloned().unwrap_or(0);
        self.update_val(hash_value);

        let hpos = pos & ZOPFLI_WINDOW_MASK;

        self.hash1.update(hpos);

        // Update "same".
        let mut amount = 0;
        let same_index = pos.wrapping_sub(1) & ZOPFLI_WINDOW_MASK;
        let same = self.same[same_index];
        if same > 1 {
            amount = same as i32 - 1;
        }

        let mut another_index = pos + amount as usize + 1;
        let array_pos = array[pos];
        while another_index < array.len() && array_pos == array[another_index] && amount < -1 {
            amount += 1;
            another_index += 1;
        }
        let amount_u16 = amount as u16;
        self.same[hpos] = amount_u16;

        self.hash2.val = ((amount_u16.wrapping_sub(ZOPFLI_MIN_MATCH as u16) & 255) ^ self.hash1.val as u16) as i32;

        self.hash2.update(hpos);
    }

    pub fn head_at(&self, index: usize, which: Which) -> i32 {
        match which {
            Which::Hash1 => self.hash1.head[index],
            Which::Hash2 => self.hash2.head[index],
        }
    }

    pub fn prev_at(&self, index: usize, which: Which) -> u16 {
        match which {
            Which::Hash1 => self.hash1.prev[index],
            Which::Hash2 => self.hash2.prev[index],
        }
    }

    pub fn hash_val_at(&self, index: usize, which: Which) -> i32 {
        match which {
            Which::Hash1 => self.hash1.hashval[index],
            Which::Hash2 => self.hash2.hashval[index],
        }
    }

    pub fn val(&self, which: Which) -> i32 {
        match which {
            Which::Hash1 => self.hash1.val,
            Which::Hash2 => self.hash2.val,
        }
    }
}
<|endoftext|>


<commit_before>// heap.rs

//! Utility functions and algorithms for minimun heaps.

/// I implemented this as a trait.
///
/// If I was only interested in heap_sort, I'd write something like
/// fn heap_sort<T: Ord>(&mut Vec<T>) {
///      fn min_heapify<T: Ord>(&mut Vec<T>) { ...
///      }
///      ...
/// }

use std::ptr::{swap};
use std::vec::{Vec};

pub trait Heap<T> {
    fn heap_sort(&mut self);
    fn heap_min<'a>(&'a self) -> &'a T;
    fn heap_extract_min(&mut self) -> T;
    fn min_heap_insert(&mut self, T);
    fn min_heapify(&mut self, uint, uint);
    fn build_min_heap(&mut self);
    fn left(&self, uint) -> uint;
    fn right(&self, uint) -> uint;
    fn parent(&self, uint) -> uint;
    fn swap(&mut self, uint, uint);
}

impl <T: Ord> Heap<T> for Vec<T> {
    /// In-place sorting in O(n lg n).
    fn heap_sort(&mut self) {
        self.build_min_heap();
        let self_len = self.len();
        for i in range(1, self.len()).rev()  {
            self.swap(0, i);
            self.min_heapify(0, i);
        }
    }

    /// Obtain the minimum value of the heap.
    fn heap_min<'a>(&'a self) -> &'a T {
        self.get(0)
    }

    /// Obtain the minimum value of the heap and remove it, while maintaining
    /// the max heap property.
    fn heap_extract_min(&mut self) -> T {
        let o = self.swap_remove(0);
        let self_len = self.len();
        self.min_heapify(0, self_len);
        return o.unwrap()
    }

    fn min_heap_insert(&mut self, i: T) {
        self.push(i);
        let self_len = self.len();
        let mut cur = self_len - 1;
        loop {
            if cur == 0 {
                break;
            } else {
                let up = self.parent(cur);
                if self.get(cur) >= self.get(up) {
                    break;
                } else {
                    self.swap(up, cur);
                    cur = up;
                }
            }
        }
    }

    /// Min heapify function, takes the indices of a target and the bottom.
    /// it will swap the target downward while maintaining the min heap
    /// property.
    fn min_heapify(&mut self, i: uint, j: uint) {
        let l = self.left(i);
        let r = self.right(i);
        let mut smallest = i;
        if l < j && self.get(l) < self.get(smallest) {
            smallest = l;
        }
        if r < j && self.get(r) < self.get(smallest) {
            smallest = r;
        }
        if smallest != i {
            self.swap(i, smallest);
            self.min_heapify(smallest, j);
        }
    }
    /// Make Vec<T> observes the min heap property.
    /// A better API would be Heap::from_vec
    fn build_min_heap(&mut self) {
        let self_len = self.len();
        for i in range(0, self_len / 2 + 1).rev() {
            self.min_heapify(i, self_len);
        }
    }

    fn left(&self, i: uint) -> uint {
        2 * i + 1
    }

    fn right(&self, i: uint) -> uint {
        2 * i + 2
    }

    fn parent(&self, i: uint) -> uint {
        (i - 1) / 2
    }

    /// TODO: Verify the correctness of this pointer cast.
    fn swap(&mut self, i: uint, j: uint) {
        unsafe{
            let ptr_to_i: *mut T = self.get_mut(i);
            let ptr_to_j: *mut T = self.get_mut(j);
            swap(ptr_to_i, ptr_to_j);
        }
    }

}
<commit_msg>unused var<commit_after>// heap.rs

//! Utility functions and algorithms for minimun heaps.

/// I implemented this as a trait.
///
/// If I was only interested in heap_sort, I'd write something like
/// fn heap_sort<T: Ord>(&mut Vec<T>) {
///      fn min_heapify<T: Ord>(&mut Vec<T>) { ...
///      }
///      ...
/// }

use std::ptr::{swap};
use std::vec::{Vec};

pub trait Heap<T> {
    fn heap_sort(&mut self);
    fn heap_min<'a>(&'a self) -> &'a T;
    fn heap_extract_min(&mut self) -> T;
    fn min_heap_insert(&mut self, T);
    fn min_heapify(&mut self, uint, uint);
    fn build_min_heap(&mut self);
    fn left(&self, uint) -> uint;
    fn right(&self, uint) -> uint;
    fn parent(&self, uint) -> uint;
    fn swap(&mut self, uint, uint);
}

impl <T: Ord> Heap<T> for Vec<T> {
    /// In-place sorting in O(n lg n).
    fn heap_sort(&mut self) {
        self.build_min_heap();
        for i in range(1, self.len()).rev()  {
            self.swap(0, i);
            self.min_heapify(0, i);
        }
    }

    /// Obtain the minimum value of the heap.
    fn heap_min<'a>(&'a self) -> &'a T {
        self.get(0)
    }

    /// Obtain the minimum value of the heap and remove it, while maintaining
    /// the max heap property.
    fn heap_extract_min(&mut self) -> T {
        let o = self.swap_remove(0);
        let self_len = self.len();
        self.min_heapify(0, self_len);
        return o.unwrap()
    }

    fn min_heap_insert(&mut self, i: T) {
        self.push(i);
        let self_len = self.len();
        let mut cur = self_len - 1;
        loop {
            if cur == 0 {
                break;
            } else {
                let up = self.parent(cur);
                if self.get(cur) >= self.get(up) {
                    break;
                } else {
                    self.swap(up, cur);
                    cur = up;
                }
            }
        }
    }

    /// Min heapify function, takes the indices of a target and the bottom.
    /// it will swap the target downward while maintaining the min heap
    /// property.
    fn min_heapify(&mut self, i: uint, j: uint) {
        let l = self.left(i);
        let r = self.right(i);
        let mut smallest = i;
        if l < j && self.get(l) < self.get(smallest) {
            smallest = l;
        }
        if r < j && self.get(r) < self.get(smallest) {
            smallest = r;
        }
        if smallest != i {
            self.swap(i, smallest);
            self.min_heapify(smallest, j);
        }
    }
    /// Make Vec<T> observes the min heap property.
    /// A better API would be Heap::from_vec
    fn build_min_heap(&mut self) {
        let self_len = self.len();
        for i in range(0, self_len / 2 + 1).rev() {
            self.min_heapify(i, self_len);
        }
    }

    fn left(&self, i: uint) -> uint {
        2 * i + 1
    }

    fn right(&self, i: uint) -> uint {
        2 * i + 2
    }

    fn parent(&self, i: uint) -> uint {
        (i - 1) / 2
    }

    /// TODO: Verify the correctness of this pointer cast.
    fn swap(&mut self, i: uint, j: uint) {
        unsafe{
            let ptr_to_i: *mut T = self.get_mut(i);
            let ptr_to_j: *mut T = self.get_mut(j);
            swap(ptr_to_i, ptr_to_j);
        }
    }

}
<|endoftext|>


<commit_before>extern crate irc;

use std::thread;

fn main() {
    let (writer, reader) = irc::connect("irc.freenode.net:6667").unwrap();
    writer.user("scarlet", "scarlet");
    writer.nick("scarlet-irc");

    let pinger = writer.clone();
    thread::spawn(move || {
        thread::sleep_ms(15 * 1000);
        pinger.raw("PING irc.freenode.net\n".into());
        println!("sent ping");
    });

    for event in reader.iter() {
        println!("{:?}", event);
        match event {
            irc::Event::Message(msg) => {
                if msg.code == irc::Code::RplWelcome {
                    writer.close();
                }
                //println!("{:?}", msg);
            }
            irc::Event::ParseError(err) => {
                println!("{:?}", err);
            }
            _ => {}
        }
    }
    println!("we done heere");
}
<commit_msg>Refresh example<commit_after>extern crate irc;

use std::thread;

fn main() {
    // Connect to freenode and use default reconnection settings.
    let (writer, reader) = irc::connect("irc.freenode.net:6667", None).unwrap();
    writer.user("myuser", "my real name");
    writer.nick("mynick");

    // Receive events.
    for event in reader.iter() {
        println!("{:?}", event);
        match event {
            irc::Event::Message(msg) => {
                if msg.code == irc::Code::RplWelcome {
                    // join #mychannel, no password
                    writer.join("#mychannel", None);
                }
            }
            _ => {}
        }
    }
}
<|endoftext|>


<commit_before>//! A simple parser for a tiny subset of HTML.
//!
//! Can parse basic opening and closing tags, and text nodes.
//!
//! Not yet supported:
//!
//! * Attributes
//! * Comments
//! * Doctypes and processing instructions
//! * Self-closing tags
//! * Non-well-formed markup
//! * Character entities

use dom;
use std::collections::hashmap::HashMap;

pub fn parse(source: String) -> dom::Node {
    let mut parser = Parser {
        pos: 0u,
        input: source,
    };
    parser.parse_root()
}

struct Parser {
    pos: uint,
    input: String,
}

impl Parser {
    /// Parse a document and return the root element.
    fn parse_root(&mut self) -> dom::Node {
        // TODO: Don't create a root <html> element if the input already contains one.
        let mut root = dom::elem("html".to_string(), HashMap::new());
        self.parse_nodes(&mut root);
        root
    }

    /// Parse a sequence of sibling nodes.
    fn parse_nodes(&mut self, parent: &mut dom::Node) {
        loop {
            match self.parse_node() {
                Some(node) => parent.children.push(node),
                None => break
            }
        }
    }

    /// Parse a single node. Returns None if there is no node at the current position.
    fn parse_node(&mut self) -> Option<dom::Node> {
        self.consume_whitespace();
        match (self.curr_char(), self.next_char()) {
            (Some('<'), Some('/')) => None, // Unexpected end tag. Stop parsing nodes.
            (Some('<'), Some(_))   => self.parse_element(),
            (_, _)                 => self.parse_text()
        }
    }

    /// Parse a single element, including its open tag, contents, and closing tag.
    fn parse_element(&mut self) -> Option<dom::Node> {
        let mut elem = self.parse_open_tag();
        self.parse_nodes(&mut elem);
        self.consume_close_tag();
        Some(elem)
    }

    // Helper functions for parse_element:

    fn parse_open_tag(&mut self) -> dom::Node {
        assert!(self.consume_char() == '<');
        let name = self.parse_tag_name();
        let mut attributes = HashMap::new();
        loop {
            self.consume_whitespace();
            match self.curr_char().unwrap() {
                '>' => {
                    self.consume_char();
                    break;
                }
                _   => {
                    let (name, value) = self.parse_attr();
                    attributes.insert(name, value);
                }
            }
        }
        dom::elem(name, attributes)
    }

    fn parse_attr(&mut self) -> (String, String) {
        let name = self.parse_tag_name();
        self.consume_whitespace();
        assert!(self.consume_char() == '=');
        self.consume_whitespace();
        let value = self.parse_attr_value();
        (name, value)
    }

    fn parse_attr_value(&mut self) -> String {
        let open_quote = self.consume_char();
        assert!(open_quote == '"' || open_quote == '\'');
        let mut value = String::new();
        loop {
            let c = self.consume_char();
            if c == open_quote {
                break;
            }
            value.push_char(c);
        }
        value
    }

    fn parse_tag_name(&mut self) -> String {
        let mut name = String::new();
        loop {
            let c = self.curr_char();
            if c.is_none() {
                break;
            }
            match c.unwrap() {
                'a'..'z' | 'A'..'Z' | '0'..'9' => name.push_char(self.consume_char()),
                _ => break,
            }
        }
        name
    }

    fn consume_close_tag(&mut self) {
        assert!(self.consume_char() == '<');
        assert!(self.consume_char() == '/');
        loop {
            match self.consume_char() {
                '>' => break,
                _   => continue,
            }
        }
    }

    /// Parse a text node.
    fn parse_text(&mut self) -> Option<dom::Node> {
        if self.eof() {
            return None;
        }
        let mut data = String::new();
        loop {
            match self.curr_char() {
                None      => break,
                Some('<') => break,
                _         => data.push_char(self.consume_char())
            }
        }
        Some(dom::text(data))
    }

    /// Consume and discard zero or more whitespace characters.
    fn consume_whitespace(&mut self) {
        loop {
            match self.curr_char() {
                Some(c) if c.is_whitespace() => self.consume_char(),
                _ => break,
            };
        }
    }

    /// Return the current character, and advance self.pos to the next character.
    fn consume_char(&mut self) -> char {
        let range = self.input.as_slice().char_range_at(self.pos);
        self.pos = range.next;
        range.ch
    }

    /// Read a character without consuming it.
    fn char_at(&self, i: uint) -> Option<char> {
        if i < self.input.len() {
            Some(self.input.as_slice().char_at(i))
        } else {
            None
        }
    }

    // Convenience functions for reading ahead 0 or 1 characters.
    fn curr_char(&self) -> Option<char> { self.char_at(self.pos)     }
    fn next_char(&self) -> Option<char> { self.char_at(self.pos + 1) }

    /// Return true if all input is consumed.
    fn eof(&self) -> bool {
        self.pos >= self.input.len()
    }
}
<commit_msg>Simplify HTML parser<commit_after>//! A simple parser for a tiny subset of HTML.
//!
//! Can parse basic opening and closing tags, and text nodes.
//!
//! Not yet supported:
//!
//! * Attributes
//! * Comments
//! * Doctypes and processing instructions
//! * Self-closing tags
//! * Non-well-formed markup
//! * Character entities

use dom;
use std::collections::hashmap::HashMap;

pub fn parse(source: String) -> dom::Node {
    let mut parser = Parser {
        pos: 0u,
        input: source,
    };
    parser.parse_root()
}

struct Parser {
    pos: uint,
    input: String,
}

impl Parser {
    /// Parse a document and return the root element.
    fn parse_root(&mut self) -> dom::Node {
        let mut nodes = vec!();
        self.parse_nodes(&mut nodes);

        // If the document contains a root `<html>` element, just return it.
        let has_root = nodes.len() == 1 && match nodes[0].node_type {
            dom::Element(ref elem) if elem.tag_name.as_slice() == "html" => true,
            _ => false
        };
        if has_root {
            nodes.swap_remove(0).unwrap()
        } else {
            // If the root `<html>` element is missing, create one.
            let mut root = dom::elem("html".to_string(), HashMap::new());
            root.children.push_all_move(nodes);
            root
        }
    }

    /// Parse a sequence of sibling nodes.
    fn parse_nodes(&mut self, nodes: &mut Vec<dom::Node>) {
        loop {
            self.consume_whitespace();
            if self.eof() || self.starts_with("</") {
                break;
            }
            nodes.push(self.parse_node());
        }
    }

    /// Parse a single node. Returns None if there is no node at the current position.
    fn parse_node(&mut self) -> dom::Node {
        match self.curr_char() {
            '<' => self.parse_element(),
            _   => self.parse_text()
        }
    }

    /// Parse a single element, including its open tag, contents, and closing tag.
    fn parse_element(&mut self) -> dom::Node {
        let mut elem = self.parse_open_tag();
        self.parse_nodes(&mut elem.children);
        self.consume_close_tag();
        elem
    }

    // Helper functions for parse_element:

    fn parse_open_tag(&mut self) -> dom::Node {
        assert!(self.consume_char() == '<');
        let name = self.parse_tag_name();
        let attrs = self.parse_attributes();
        assert!(self.consume_char() == '>');

        dom::elem(name, attrs)
    }

    fn parse_tag_name(&mut self) -> String {
        self.consume_while(|c| match c {
            'a'..'z' | 'A'..'Z' | '0'..'9' => true,
            _ => false
        })
    }

    fn parse_attributes(&mut self) -> dom::AttrMap {
        let mut attributes = HashMap::new();
        loop {
            self.consume_whitespace();
            match self.curr_char() {
                '>' => {
                    break;
                }
                _ => {
                    let (name, value) = self.parse_attr();
                    attributes.insert(name, value);
                }
            }
        }
        attributes
    }

    // name="value"
    fn parse_attr(&mut self) -> (String, String) {
        let name = self.parse_tag_name();
        assert!(self.consume_char() == '=');
        let value = self.parse_attr_value();
        (name, value)
    }

    fn parse_attr_value(&mut self) -> String {
        let open_quote = self.consume_char();
        assert!(open_quote == '"' || open_quote == '\'');
        let mut value = self.consume_while(|c| c != open_quote);
        assert!(!self.eof() && self.consume_char() == open_quote);
        value
    }

    fn consume_close_tag(&mut self) {
        assert!(self.consume_char() == '<');
        assert!(self.consume_char() == '/');
        loop {
            match self.consume_char() {
                '>' => break,
                _   => continue,
            }
        }
    }

    /// Parse a text node.
    fn parse_text(&mut self) -> dom::Node {
        dom::text(self.consume_while(|c| c != '<'))
    }

    /// Consume and discard zero or more whitespace characters.
    fn consume_whitespace(&mut self) {
        self.consume_while(|c| c.is_whitespace());
    }

    /// Consume characters until `test` returns false.
    fn consume_while(&mut self, test: |char| -> bool) -> String {
        let mut result = String::new();
        while !self.eof() && test(self.curr_char()) {
            result.push_char(self.consume_char());
        }
        result
    }

    /// Return the current character, and advance self.pos to the next character.
    fn consume_char(&mut self) -> char {
        let range = self.input.as_slice().char_range_at(self.pos);
        self.pos = range.next;
        range.ch
    }

    /// Read the current character without consuming it.
    fn curr_char(&self) -> char {
        self.input.as_slice().char_at(self.pos)
    }

    /// Does the current input start with the given string?
    fn starts_with(&self, s: &str) -> bool {
        self.input.as_slice().slice_from(self.pos).starts_with(s)
    }

    /// Return true if all input is consumed.
    fn eof(&self) -> bool {
        self.pos >= self.input.len()
    }
}
<|endoftext|>


<commit_before>//! Thread-safe connections on IrcStreams.
#![experimental]
use std::sync::{Mutex, MutexGuard};
use std::io::{BufferedStream, IoResult, MemWriter, TcpStream};
#[cfg(feature = "ssl")] use std::io::{IoError, OtherIoError};
use data::kinds::{IrcReader, IrcStream, IrcWriter};
use data::message::Message;
#[cfg(feature = "ssl")] use openssl::ssl::{SslContext, SslStream, Tlsv1};
#[cfg(feature = "ssl")] use openssl::ssl::error::SslError;

/// A thread-safe connection.
#[experimental]
pub struct Connection<T> where T: IrcStream {
    stream: Mutex<T>
}

impl Connection<BufferedStream<TcpStream>> {
    /// Creates a thread-safe TCP connection to the specified server.
    #[experimental]
    pub fn connect(host: &str, port: u16) -> IoResult<Connection<BufferedStream<NetStream>>> {
        Connection::connect_internal(host, port, None)
    }

    /// Creates a thread-safe TCP connection to the specified server with a given timeout in
    /// milliseconds.
    #[experimental]
    pub fn connect_with_timeout(host: &str, port: u16, timeout_ms: u64)
        -> IoResult<Connection<BufferedStream<NetStream>>> {
        Connection::connect_internal(host, port, Some(timeout_ms))
    }

    /// Creates a thread-safe TCP connection with an optional timeout.
    #[experimental]
    fn connect_internal(host: &str, port: u16, timeout_ms: Option<u64>)
    -> IoResult<Connection<BufferedStream<NetStream>>> {
        let mut socket = try!(TcpStream::connect(format!("{}:{}", host, port)[]));
        socket.set_timeout(timeout_ms);
        Ok(Connection::new(BufferedStream::new(NetStream::UnsecuredTcpStream(socket))))
    }

    /// Creates a thread-safe TCP connection to the specified server over SSL.
    /// If the library is compiled without SSL support, this method panics.
    #[experimental]
    pub fn connect_ssl(host: &str, port: u16) -> IoResult<Connection<BufferedStream<NetStream>>> {
        Connection::connect_ssl_internal(host, port, None)
    }

    /// Creates a thread-safe TCP connection to the specificed server over SSL with a given timeout
    /// in milliseconds. If the library is compiled without SSL support, this method panics.
    #[experimental]
    pub fn connect_ssl_with_timeout(host: &str, port: u16, timeout_ms: u64)
        -> IoResult<Connection<BufferedStream<NetStream>>> {
        Connection::connect_ssl_internal(host, port, Some(timeout_ms))
    }

    /// Panics because SSL support was not included at compilation.
    #[experimental]
    #[cfg(not(feature = "ssl"))]
    fn connect_ssl_internal(host: &str, port: u16, timeout_ms: Option<u64>)
    -> IoResult<Connection<BufferedStream<NetStream>>> {
        panic!("Cannot connect to {}:{} over SSL without compiling with SSL support.", host, port)
    }

    /// Creates a thread-safe TCP connection over SSL with an optional timeout.
    #[experimental]
    #[cfg(feature = "ssl")]
    fn connect_ssl_internal(host: &str, port: u16, timeout_ms: Option<u64>)
    -> IoResult<Connection<BufferedStream<NetStream>>> {
        let mut socket = try!(TcpStream::connect(format!("{}:{}", host, port)[]));
        socket.set_timeout(timeout_ms);
        let ssl = try!(ssl_to_io(SslContext::new(Tlsv1)));
        let ssl_socket = try!(ssl_to_io(SslStream::new(&ssl, socket)));
        Ok(Connection::new(BufferedStream::new(NetStream::SslTcpStream(ssl_socket))))
    }
}

/// Converts a Result<T, SslError> into an IoResult<T>.
#[cfg(feature = "ssl")]
fn ssl_to_io<T>(res: Result<T, SslError>) -> IoResult<T> {
    match res {
        Ok(x) => Ok(x),
        Err(e) => Err(IoError {
            kind: OtherIoError,
            desc: "An SSL error occurred.",
            detail: Some(format!("{}", e)),
        }),
    }
}

/// An abstraction over different networked streams.
#[experimental]
pub enum NetStream {
    /// An unsecured TcpStream.
    UnsecuredTcpStream(TcpStream),
    /// An SSL-secured TcpStream.
    /// This is only available when compiled with SSL support.
    #[cfg(feature = "ssl")]
    SslTcpStream(SslStream<TcpStream>),
}

impl Reader for NetStream {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        match self {
            &NetStream::UnsecuredTcpStream(ref mut stream) => stream.read(buf),
            #[cfg(feature = "ssl")]
            &NetStream::SslTcpStream(ref mut stream) => stream.read(buf),
        }
    }
}

impl Writer for NetStream {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        match self {
            &NetStream::UnsecuredTcpStream(ref mut stream) => stream.write(buf),
            #[cfg(feature = "ssl")]
            &NetStream::SslTcpStream(ref mut stream) => stream.write(buf),
        }
    }
}

impl<T: IrcStream> Connection<T> {
    /// Creates a new connection from any arbitrary IrcStream.
    #[experimental]
    pub fn new(stream: T) -> Connection<T> {
        Connection {
            stream: Mutex::new(stream),
        }
    }

    /// Sends a Message over this connection.
    #[experimental]
    pub fn send(&self, message: Message) -> IoResult<()> {
        let mut stream = self.stream.lock();
        try!(stream.write_str(message.into_string()[]));
        stream.flush()
    }

    /// Receives a single line from this connection.
    #[experimental]
    pub fn recv(&self) -> IoResult<String> {
        self.stream.lock().read_line()
    }

    /// Acquires the Stream lock.
    #[experimental]
    pub fn stream<'a>(&'a self) -> MutexGuard<'a, T> {
        self.stream.lock()
    }
}

/// An IrcStream built from an IrcWriter and an IrcReader.
#[experimental]
pub struct IoStream<T: IrcWriter, U: IrcReader> {
    writer: T,
    reader: U,
}

impl<T: IrcWriter, U: IrcReader> IoStream<T, U> {
    /// Creates a new IoStream from the given IrcWriter and IrcReader.
    #[experimental]
    pub fn new(writer: T, reader: U) -> IoStream<T, U> {
        IoStream { writer: writer, reader: reader }
    }
}

impl<U: IrcReader> IoStream<MemWriter, U> {
    pub fn value(&self) -> Vec<u8> {
        self.writer.get_ref().to_vec()
    }
}

impl<T: IrcWriter, U: IrcReader> Buffer for IoStream<T, U> {
    fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]> {
        self.reader.fill_buf()
    }

    fn consume(&mut self, amt: uint) {
        self.reader.consume(amt)
    }
}

impl<T: IrcWriter, U: IrcReader> Reader for IoStream<T, U> {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        self.reader.read(buf)
    }
}

impl<T: IrcWriter, U: IrcReader> Writer for IoStream<T, U> {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        self.writer.write(buf)
    }
}

#[cfg(test)]
mod test {
    use super::{Connection, IoStream};
    use std::io::{MemReader, MemWriter};
    use std::io::util::{NullReader, NullWriter};
    use data::message::Message;

    #[test]
    fn send() {
        let conn = Connection::new(IoStream::new(MemWriter::new(), NullReader));
        assert!(conn.send(
            Message::new(None, "PRIVMSG", Some(vec!["test"]), Some("Testing!"))
        ).is_ok());
        let data = String::from_utf8(conn.stream().value()).unwrap();
        assert_eq!(data[], "PRIVMSG test :Testing!\r\n");
    }

    #[test]
    fn recv() {
        let conn = Connection::new(IoStream::new(
            NullWriter, MemReader::new("PRIVMSG test :Testing!\r\n".as_bytes().to_vec())
        ));
        assert_eq!(conn.recv().unwrap()[], "PRIVMSG test :Testing!\r\n");
    }
}
<commit_msg>Unused timeout variable is now unbound in connect_ssl_internal when compiled without SSL support.<commit_after>//! Thread-safe connections on IrcStreams.
#![experimental]
use std::sync::{Mutex, MutexGuard};
use std::io::{BufferedStream, IoResult, MemWriter, TcpStream};
#[cfg(feature = "ssl")] use std::io::{IoError, OtherIoError};
use data::kinds::{IrcReader, IrcStream, IrcWriter};
use data::message::Message;
#[cfg(feature = "ssl")] use openssl::ssl::{SslContext, SslStream, Tlsv1};
#[cfg(feature = "ssl")] use openssl::ssl::error::SslError;

/// A thread-safe connection.
#[experimental]
pub struct Connection<T> where T: IrcStream {
    stream: Mutex<T>
}

impl Connection<BufferedStream<TcpStream>> {
    /// Creates a thread-safe TCP connection to the specified server.
    #[experimental]
    pub fn connect(host: &str, port: u16) -> IoResult<Connection<BufferedStream<NetStream>>> {
        Connection::connect_internal(host, port, None)
    }

    /// Creates a thread-safe TCP connection to the specified server with a given timeout in
    /// milliseconds.
    #[experimental]
    pub fn connect_with_timeout(host: &str, port: u16, timeout_ms: u64)
        -> IoResult<Connection<BufferedStream<NetStream>>> {
        Connection::connect_internal(host, port, Some(timeout_ms))
    }

    /// Creates a thread-safe TCP connection with an optional timeout.
    #[experimental]
    fn connect_internal(host: &str, port: u16, timeout_ms: Option<u64>)
    -> IoResult<Connection<BufferedStream<NetStream>>> {
        let mut socket = try!(TcpStream::connect(format!("{}:{}", host, port)[]));
        socket.set_timeout(timeout_ms);
        Ok(Connection::new(BufferedStream::new(NetStream::UnsecuredTcpStream(socket))))
    }

    /// Creates a thread-safe TCP connection to the specified server over SSL.
    /// If the library is compiled without SSL support, this method panics.
    #[experimental]
    pub fn connect_ssl(host: &str, port: u16) -> IoResult<Connection<BufferedStream<NetStream>>> {
        Connection::connect_ssl_internal(host, port, None)
    }

    /// Creates a thread-safe TCP connection to the specificed server over SSL with a given timeout
    /// in milliseconds. If the library is compiled without SSL support, this method panics.
    #[experimental]
    pub fn connect_ssl_with_timeout(host: &str, port: u16, timeout_ms: u64)
        -> IoResult<Connection<BufferedStream<NetStream>>> {
        Connection::connect_ssl_internal(host, port, Some(timeout_ms))
    }

    /// Panics because SSL support was not included at compilation.
    #[experimental]
    #[cfg(not(feature = "ssl"))]
    fn connect_ssl_internal(host: &str, port: u16, _: Option<u64>)
    -> IoResult<Connection<BufferedStream<NetStream>>> {
        panic!("Cannot connect to {}:{} over SSL without compiling with SSL support.", host, port)
    }

    /// Creates a thread-safe TCP connection over SSL with an optional timeout.
    #[experimental]
    #[cfg(feature = "ssl")]
    fn connect_ssl_internal(host: &str, port: u16, timeout_ms: Option<u64>)
    -> IoResult<Connection<BufferedStream<NetStream>>> {
        let mut socket = try!(TcpStream::connect(format!("{}:{}", host, port)[]));
        socket.set_timeout(timeout_ms);
        let ssl = try!(ssl_to_io(SslContext::new(Tlsv1)));
        let ssl_socket = try!(ssl_to_io(SslStream::new(&ssl, socket)));
        Ok(Connection::new(BufferedStream::new(NetStream::SslTcpStream(ssl_socket))))
    }
}

/// Converts a Result<T, SslError> into an IoResult<T>.
#[cfg(feature = "ssl")]
fn ssl_to_io<T>(res: Result<T, SslError>) -> IoResult<T> {
    match res {
        Ok(x) => Ok(x),
        Err(e) => Err(IoError {
            kind: OtherIoError,
            desc: "An SSL error occurred.",
            detail: Some(format!("{}", e)),
        }),
    }
}

/// An abstraction over different networked streams.
#[experimental]
pub enum NetStream {
    /// An unsecured TcpStream.
    UnsecuredTcpStream(TcpStream),
    /// An SSL-secured TcpStream.
    /// This is only available when compiled with SSL support.
    #[cfg(feature = "ssl")]
    SslTcpStream(SslStream<TcpStream>),
}

impl Reader for NetStream {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        match self {
            &NetStream::UnsecuredTcpStream(ref mut stream) => stream.read(buf),
            #[cfg(feature = "ssl")]
            &NetStream::SslTcpStream(ref mut stream) => stream.read(buf),
        }
    }
}

impl Writer for NetStream {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        match self {
            &NetStream::UnsecuredTcpStream(ref mut stream) => stream.write(buf),
            #[cfg(feature = "ssl")]
            &NetStream::SslTcpStream(ref mut stream) => stream.write(buf),
        }
    }
}

impl<T: IrcStream> Connection<T> {
    /// Creates a new connection from any arbitrary IrcStream.
    #[experimental]
    pub fn new(stream: T) -> Connection<T> {
        Connection {
            stream: Mutex::new(stream),
        }
    }

    /// Sends a Message over this connection.
    #[experimental]
    pub fn send(&self, message: Message) -> IoResult<()> {
        let mut stream = self.stream.lock();
        try!(stream.write_str(message.into_string()[]));
        stream.flush()
    }

    /// Receives a single line from this connection.
    #[experimental]
    pub fn recv(&self) -> IoResult<String> {
        self.stream.lock().read_line()
    }

    /// Acquires the Stream lock.
    #[experimental]
    pub fn stream<'a>(&'a self) -> MutexGuard<'a, T> {
        self.stream.lock()
    }
}

/// An IrcStream built from an IrcWriter and an IrcReader.
#[experimental]
pub struct IoStream<T: IrcWriter, U: IrcReader> {
    writer: T,
    reader: U,
}

impl<T: IrcWriter, U: IrcReader> IoStream<T, U> {
    /// Creates a new IoStream from the given IrcWriter and IrcReader.
    #[experimental]
    pub fn new(writer: T, reader: U) -> IoStream<T, U> {
        IoStream { writer: writer, reader: reader }
    }
}

impl<U: IrcReader> IoStream<MemWriter, U> {
    pub fn value(&self) -> Vec<u8> {
        self.writer.get_ref().to_vec()
    }
}

impl<T: IrcWriter, U: IrcReader> Buffer for IoStream<T, U> {
    fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]> {
        self.reader.fill_buf()
    }

    fn consume(&mut self, amt: uint) {
        self.reader.consume(amt)
    }
}

impl<T: IrcWriter, U: IrcReader> Reader for IoStream<T, U> {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        self.reader.read(buf)
    }
}

impl<T: IrcWriter, U: IrcReader> Writer for IoStream<T, U> {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        self.writer.write(buf)
    }
}

#[cfg(test)]
mod test {
    use super::{Connection, IoStream};
    use std::io::{MemReader, MemWriter};
    use std::io::util::{NullReader, NullWriter};
    use data::message::Message;

    #[test]
    fn send() {
        let conn = Connection::new(IoStream::new(MemWriter::new(), NullReader));
        assert!(conn.send(
            Message::new(None, "PRIVMSG", Some(vec!["test"]), Some("Testing!"))
        ).is_ok());
        let data = String::from_utf8(conn.stream().value()).unwrap();
        assert_eq!(data[], "PRIVMSG test :Testing!\r\n");
    }

    #[test]
    fn recv() {
        let conn = Connection::new(IoStream::new(
            NullWriter, MemReader::new("PRIVMSG test :Testing!\r\n".as_bytes().to_vec())
        ));
        assert_eq!(conn.recv().unwrap()[], "PRIVMSG test :Testing!\r\n");
    }
}
<|endoftext|>


<commit_before><commit_msg>Add checked_uabs to better control uabs branching<commit_after><|endoftext|>


<commit_before>// Core types.
// Copyright (c) 2015 by Shipeng Feng.
// Licensed under the BSD License, see LICENSE for more details.

use std::os;
use std::path::Path;

use types::{Params, CommandCallback};

/// The command is the basic type of command line applications in cli.  This
/// handles command line parsing.
pub struct Command {
    name: String,  // The name of the command to use
    callback: CommandCallback,  // The callback to execute
    params: Params,  // The parameters to register with this command
    help: String,  // The help message to use for this command
    epilog: String,  // Printed at the end of the help page
    short_help: String,  // The short help to use for this command, this is shown on the command listing of the parent command
    add_help_option: bool,  // Whether this command registers "--help", default to be true
}

impl Command {
    pub fn new(name: &str, callback: CommandCallback) -> Command {
        Command {
            name: name.to_string(),
            callback: callback,
            params: Vec::new(),
            help: String::new(),
            epilog: String::new(),
            short_help: String::new(),
            add_help_option: true,
        }
    }

    pub fn get_usage(&self) -> String {
    }

    pub fn get_help(&self) -> String {
    }

    /// This invokes the command with given arguments.
    pub fn invoke(&self, pragram_name: String, args: Vec<String>) {
    }

    /// Create the parser and parses the arguments.
    fn parse_args(&self, args: Vec<String>) {
    }

    /// This is the way to run one command application.
    pub fn run(&self) {
        let mut args = os::args();
        let program_path = Path::new(args.remove(0).as_slice());
        let program_name = program_path.file_name().unwrap().to_str().unwrap();
        self.invoke(program_name.to_string(), args);
    }
}
<commit_msg>Added more<commit_after>// Core types.
// Copyright (c) 2015 by Shipeng Feng.
// Licensed under the BSD License, see LICENSE for more details.

use std::os;
use std::path::Path;

use types::{Params, CommandCallback};

/// The command is the basic type of command line applications in cli.  This
/// handles command line parsing.
pub struct Command {
    name: String,  // The name of the command to use
    callback: CommandCallback,  // The callback to execute
    params: Params,  // The parameters to register with this command
    help: String,  // The help message to use for this command
    epilog: String,  // Printed at the end of the help page
    short_help: String,  // The short help to use for this command, this is shown on the command listing of the parent command
    add_help_option: bool,  // Whether this command registers "--help", default to be true
}

impl Command {
    pub fn new(name: &str, callback: CommandCallback) -> Command {
        Command {
            name: name.to_string(),
            callback: callback,
            params: Vec::new(),
            help: String::new(),
            epilog: String::new(),
            short_help: String::new(),
            add_help_option: true,
        }
    }

    pub fn get_usage(&self) -> String {
    }

    pub fn get_help(&self) -> String {
    }

    /// This invokes the command with given arguments.
    pub fn invoke(&self, pragram_name: String, args: Vec<String>) {
        let args = self.parse_args(args);
        self.callback(
    }

    /// Create the parser and parses the arguments.
    fn parse_args(&self, args: Vec<String>) {
    }

    /// This is the way to run one command application.
    pub fn run(&self) {
        let mut args = os::args();
        let program_path = Path::new(args.remove(0).as_slice());
        let program_name = program_path.file_name().unwrap().to_str().unwrap();
        self.invoke(program_name.to_string(), args);
    }
}
<|endoftext|>


<commit_before>#![recursion_limit = "1000"]

extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;

use proc_macro::TokenStream;
use syn::Ident;
use quote::Tokens;

#[proc_macro_derive(IntoHeap)]
pub fn derive_into_heap(input: TokenStream) -> TokenStream {
    let source = input.to_string();
    let ast = syn::parse_derive_input(&source).unwrap();
    let expanded = impl_into_heap(&ast);
    println!("{:?}", expanded);
    expanded.parse().unwrap()
}

fn impl_into_heap(ast: &syn::DeriveInput) -> Tokens {
    match ast.body {
        syn::Body::Struct(ref data) => impl_into_heap_for_struct(ast, data),
        syn::Body::Enum(ref variants) => impl_into_heap_for_enum(ast, variants),
    }
}

fn impl_into_heap_for_struct(ast: &syn::DeriveInput, data: &syn::VariantData) -> Tokens {
    let name = &ast.ident;
    let name_str: &str = name.as_ref();
    let storage_type_name: Ident = Ident::from(name_str.to_string() + "Storage");
    let vis = &ast.vis;
    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
    let heap_lifetime = &ast.generics
        .lifetimes
        .first()
        .expect("lifetime parameter required")
        .lifetime;

    match *data {
        syn::VariantData::Struct(ref fields) => {
            let field_vis: &Vec<_> = &fields.iter().map(|f| &f.vis).collect();
            let field_names: &Vec<_> = &fields.iter().map(|f| &f.ident).collect();
            let field_types: &Vec<_> = &fields.iter().map(|f| &f.ty).collect();
            let field_storage_types: Vec<_> = fields
                .iter()
                .map(|f| {
                    let field_ty = &f.ty;
                    quote! {
                    <#field_ty as ::cell_gc::traits::IntoHeap<#heap_lifetime>>::In
                }
                })
                .collect();

            // 1. The in-heap representation of the struct.
            let storage_struct = quote! {
                #vis struct #storage_type_name #impl_generics #where_clause {
                    #( #field_vis #field_names: #field_storage_types ),*
                }
            };

            // 2. IntoHeap implementation.
            // Body of the trace() method.
            let trace_fields: Vec<Tokens> = fields
                .iter()
                .map(|f| {
                    let name = &f.ident;
                    let ty = &f.ty;
                    quote! {
                    <#ty as ::cell_gc::traits::IntoHeap<#heap_lifetime>>
                        ::trace(&storage.#name, tracer);
                }
                })
                .collect();

            // Oddly you can't use the same identifier more than once in the
            // same loop. So create an alias.
            let field_names_1 = field_names;

            let into_heap = quote! {
                unsafe impl #impl_generics ::cell_gc::traits::IntoHeap<#heap_lifetime>
                    for #name #ty_generics
                    #where_clause
                {
                    type In = #storage_type_name #ty_generics;

                    fn into_heap(self) -> Self::In {
                        #storage_type_name {
                            #(
                                #field_names:
                                    ::cell_gc::traits::IntoHeap::into_heap(
                                        self.#field_names_1)
                            ),*
                        }
                    }

                    unsafe fn trace<R>(storage: &Self::In, tracer: &mut R)
                        where R: ::cell_gc::traits::Tracer
                    {
                        #( #trace_fields )*

                        // Quiet unused variable warnings when `$(...)*` expands
                        // to nothing.
                        let _ = tracer;
                    }

                    unsafe fn from_heap(storage: &Self::In) -> Self {
                        #name {
                            #(
                                #field_names:
                                    ::cell_gc::traits::IntoHeap::from_heap(
                                        &storage.#field_names_1)
                            ),*
                        }
                    }
                }
            };

            // 3. IntoHeapAllocation implementation.
            let ref_type_name: Ident = Ident::from(name_str.to_string() + "Ref");
            let into_heap_allocation = quote! {
                impl #impl_generics ::cell_gc::traits::IntoHeapAllocation<#heap_lifetime>
                    for #name #ty_generics
                    #where_clause
                {
                    type Ref = #ref_type_name #ty_generics;

                    fn wrap_gcref(gcref: ::cell_gc::GcRef<#heap_lifetime,
                                                          #name #ty_generics>)
                        -> #ref_type_name #ty_generics
                    {
                        #ref_type_name(gcref)
                    }
                }
            };

            // 4. #ref_type_name: A safe reference to the struct
            let ref_type = quote! {
                #[derive(Clone, Debug, PartialEq, Eq)]
                #vis struct #ref_type_name #impl_generics
                    (::cell_gc::GcRef<#heap_lifetime, #name #ty_generics>)
                    #where_clause;
            };

            // 5. The ref type also gets an IntoHeap impl...
            let ref_type_into_heap = quote! {
                unsafe impl #impl_generics ::cell_gc::traits::IntoHeap<#heap_lifetime>
                    for #ref_type_name #ty_generics
                    #where_clause
                {
                    type In = ::cell_gc::ptr::Pointer<#storage_type_name #ty_generics>;

                    fn into_heap(self) -> Self::In {
                        self.0.ptr()
                    }

                    unsafe fn trace<R>(storage: &Self::In, tracer: &mut R)
                        where R: ::cell_gc::traits::Tracer
                    {
                        if !storage.is_null() {
                            tracer.visit::<#name #ty_generics>(*storage);
                        }
                    }

                    unsafe fn from_heap(storage: &Self::In) -> #ref_type_name #ty_generics {
                        #ref_type_name(::cell_gc::GcRef::<#name #ty_generics>::new(*storage))
                    }
                }
            };

            // 6. Getters and setters.
            let field_setter_names: Vec<_> = fields
                .iter()
                .map(|f| {
                    let field_str: &str = f.ident.as_ref().unwrap().as_ref();
                    Ident::from(format!("set_{}", field_str))
                })
                .collect();
            let accessors = quote! {
                impl #impl_generics #ref_type_name #ty_generics #where_clause {
                    #(
                        #[allow(dead_code)]
                        #field_vis fn #field_names(&self) -> #field_types {
                            let ptr = self.0.as_ptr();
                            unsafe {
                                ::cell_gc::traits::IntoHeap::from_heap(
                                    &(*ptr).#field_names_1)
                            }
                        }
                    )*

                    #(
                        #[allow(dead_code)]
                        #field_vis fn #field_setter_names(&self, v: #field_types) {
                            let ptr = self.0.as_mut_ptr();
                            let u = ::cell_gc::traits::IntoHeap::into_heap(v);
                            unsafe {
                                (*ptr).#field_names = u;
                            }
                        }
                    )*

                    ///// Get all fields at once.
                    //pub fn get(&self) -> #name {
                    //    ::cell_gc::traits::IntoHeap::from_heap(ptr)
                    //}

                    #[allow(dead_code)]
                    pub fn as_mut_ptr(&self) -> *mut #storage_type_name #ty_generics {
                        self.0.as_mut_ptr()
                    }
                }
            };

            quote! {
                #storage_struct
                #into_heap
                #into_heap_allocation
                #ref_type
                #ref_type_into_heap
                #accessors
            }
        }
        syn::VariantData::Tuple(ref _fields) => {
            panic!("#[derive(IntoHeap)] does not support tuple structs");
        }
        syn::VariantData::Unit => {
            panic!("#[derive(IntoHeap)] does not support unit structs");
        }
    }
}

fn impl_into_heap_for_enum(ast: &syn::DeriveInput, variants: &[syn::Variant]) -> Tokens {
    let attrs = &ast.attrs;
    let name = &ast.ident;
    let name_str: &str = name.as_ref();
    let storage_type_name: Ident = Ident::from(name_str.to_string() + "Storage");
    let vis = &ast.vis;
    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
    let heap_lifetime = &ast.generics
        .lifetimes
        .first()
        .expect("lifetime parameter required")
        .lifetime;

    let variant_storage = variants.iter().map(|v| {
        let attrs = &v.attrs;
        let ident = &v.ident;
        if v.discriminant.is_some() {
            panic!("#[derive(IntoHeap)] does not support enum variants with discriminants");
        }
        match v.data {
            syn::VariantData::Struct(ref fields) => {
                let field_decls = fields.iter().map(|f| {
                    let field_attrs = &f.attrs;
                    let field_name = &f.ident;
                    let field_ty = &f.ty;
                    quote! {
                        #( #field_attrs )*
                        #field_name:
                            <#field_ty as ::cell_gc::traits::IntoHeap<#heap_lifetime>>::In
                    }
                });
                quote! {
                    #( #attrs )*
                    #ident { #( #field_decls ),* }
                }
            }
            syn::VariantData::Tuple(ref fields) => {
                let field_decls = fields.iter().map(|f| {
                    let field_ty = &f.ty;
                    let field_attrs = &f.attrs;
                    quote! {
                        #( #field_attrs )*
                        <#field_ty as ::cell_gc::traits::IntoHeap<#heap_lifetime>>::In
                    }
                });
                quote! {
                    #( #attrs )*
                    #ident( #( #field_decls ),* )
                }
            }
            syn::VariantData::Unit => {
                quote! { #( #attrs )* #ident }
            }
        }
    });
    let storage_enum = quote! {
        #( #attrs )*
        #vis enum #storage_type_name #impl_generics
            #where_clause
        {
            #( #variant_storage ),*
        }
    };

    let into_heap_arms = variants.iter().map(|v| {
        let ident = &v.ident;
        match v.data {
            syn::VariantData::Struct(ref fields) => {
                let field_names: &Vec<_> = &fields.iter().map(|f| &f.ident).collect();
                let field_names_1 = field_names;
                let field_types = fields.iter().map(|f| &f.ty);
                quote! {
                    #name::#ident { #(#field_names),* } => {
                        #storage_type_name::#ident {
                            #(
                                #field_names:
                                    <#field_types as ::cell_gc::traits::IntoHeap>
                                    ::into_heap(#field_names_1)
                            ),*
                        }
                    }
                }
            }
            syn::VariantData::Tuple(ref fields) => {
                let field_types = fields.iter().map(|f| &f.ty);
                let bindings: &Vec<Ident> = &(0..fields.len())
                    .map(|n| Ident::from(format!("x{}", n)))
                    .collect();
                quote! {
                    #name::#ident( #(#bindings),* ) => {
                        #storage_type_name::#ident(
                            #(
                                <#field_types as ::cell_gc::traits::IntoHeap>
                                    ::into_heap(#bindings)
                            ),*
                        )
                    }
                }
            }
            syn::VariantData::Unit => {
                quote! {
                    #name::#ident => #storage_type_name::#ident
                }
            }
        }
    });

    let from_heap_arms = variants.iter().map(|v| {
        let ident = &v.ident;
        match v.data {
            syn::VariantData::Struct(ref fields) => {
                let field_names: &Vec<_> = &fields.iter().map(|f| &f.ident).collect();
                let field_names_1 = field_names;
                let field_types = fields.iter().map(|f| &f.ty);
                quote! {
                    #storage_type_name::#ident { #(ref #field_names),* } => {
                        #name::#ident {
                            #(
                                #field_names:
                                    <#field_types as ::cell_gc::traits::IntoHeap>
                                    ::from_heap(#field_names_1)
                            ),*
                        }
                    }
                }
            }
            syn::VariantData::Tuple(ref fields) => {
                let field_types = fields.iter().map(|f| &f.ty);
                let bindings: &Vec<Ident> = &(0..fields.len())
                    .map(|n| Ident::from(format!("x{}", n)))
                    .collect();
                quote! {
                    #storage_type_name::#ident( #(ref #bindings),* ) => {
                        #name::#ident(
                            #(
                                <#field_types as ::cell_gc::traits::IntoHeap>
                                    ::from_heap(#bindings)
                            ),*
                        )
                    }
                }
            }
            syn::VariantData::Unit => {
                quote! {
                    #storage_type_name::#ident => #name::#ident
                }
            }
        }
    });

    let trace_arms = variants.iter().map(|v| {
        let ident = &v.ident;
        match v.data {
            syn::VariantData::Struct(ref fields) => {
                let field_names: &Vec<_> = &fields.iter().map(|f| &f.ident).collect();
                let field_types = fields.iter().map(|f| &f.ty);
                quote! {
                    #storage_type_name::#ident { #(ref #field_names),* } => {
                        #(
                            <#field_types as ::cell_gc::traits::IntoHeap>
                                ::trace(#field_names, tracer);
                        )*
                    }
                }
            }
            syn::VariantData::Tuple(ref fields) => {
                let field_types = fields.iter().map(|f| &f.ty);
                let bindings: &Vec<Ident> = &(0..fields.len())
                    .map(|n| Ident::from(format!("x{}", n)))
                    .collect();
                quote! {
                    #storage_type_name::#ident( #(ref #bindings),* ) => {
                        #(
                            <#field_types as ::cell_gc::traits::IntoHeap>
                                ::trace(#bindings, tracer);
                        )*
                    }
                }
            }
            syn::VariantData::Unit => {
                quote! { #storage_type_name::#ident => () }
            }
        }
    });

    let into_heap = quote! {
        unsafe impl #impl_generics
            ::cell_gc::traits::IntoHeap<#heap_lifetime>
            for #name #ty_generics
            #where_clause
        {
            type In = #storage_type_name #ty_generics;

            fn into_heap(self) -> Self::In {
                match self {
                    #( #into_heap_arms ),*
                }
            }

            unsafe fn from_heap(storage: &Self::In) -> Self {
                match *storage {
                    #( #from_heap_arms ),*
                }
            }

            unsafe fn trace<R>(storage: &Self::In, tracer: &mut R)
                where R: ::cell_gc::traits::Tracer
            {
                match *storage {
                    #( #trace_arms ),*
                }

                // Quiet unused variable warnings when `$(...)*` expands to
                // nothing.
                let _ = tracer;
            }
        }
    };

    quote! {
        #storage_enum
        #into_heap
    }
}
<commit_msg>Disable macro logging by default<commit_after>#![recursion_limit = "1000"]

extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;

use proc_macro::TokenStream;
use syn::Ident;
use quote::Tokens;

#[proc_macro_derive(IntoHeap)]
pub fn derive_into_heap(input: TokenStream) -> TokenStream {
    let source = input.to_string();
    let ast = syn::parse_derive_input(&source).unwrap();
    let expanded = impl_into_heap(&ast);

    // Uncomment to debug the generated code...
    // println!("{:?}", expanded);

    expanded.parse().unwrap()
}

fn impl_into_heap(ast: &syn::DeriveInput) -> Tokens {
    match ast.body {
        syn::Body::Struct(ref data) => impl_into_heap_for_struct(ast, data),
        syn::Body::Enum(ref variants) => impl_into_heap_for_enum(ast, variants),
    }
}

fn impl_into_heap_for_struct(ast: &syn::DeriveInput, data: &syn::VariantData) -> Tokens {
    let name = &ast.ident;
    let name_str: &str = name.as_ref();
    let storage_type_name: Ident = Ident::from(name_str.to_string() + "Storage");
    let vis = &ast.vis;
    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
    let heap_lifetime = &ast.generics
        .lifetimes
        .first()
        .expect("lifetime parameter required")
        .lifetime;

    match *data {
        syn::VariantData::Struct(ref fields) => {
            let field_vis: &Vec<_> = &fields.iter().map(|f| &f.vis).collect();
            let field_names: &Vec<_> = &fields.iter().map(|f| &f.ident).collect();
            let field_types: &Vec<_> = &fields.iter().map(|f| &f.ty).collect();
            let field_storage_types: Vec<_> = fields
                .iter()
                .map(|f| {
                    let field_ty = &f.ty;
                    quote! {
                    <#field_ty as ::cell_gc::traits::IntoHeap<#heap_lifetime>>::In
                }
                })
                .collect();

            // 1. The in-heap representation of the struct.
            let storage_struct = quote! {
                #vis struct #storage_type_name #impl_generics #where_clause {
                    #( #field_vis #field_names: #field_storage_types ),*
                }
            };

            // 2. IntoHeap implementation.
            // Body of the trace() method.
            let trace_fields: Vec<Tokens> = fields
                .iter()
                .map(|f| {
                    let name = &f.ident;
                    let ty = &f.ty;
                    quote! {
                    <#ty as ::cell_gc::traits::IntoHeap<#heap_lifetime>>
                        ::trace(&storage.#name, tracer);
                }
                })
                .collect();

            // Oddly you can't use the same identifier more than once in the
            // same loop. So create an alias.
            let field_names_1 = field_names;

            let into_heap = quote! {
                unsafe impl #impl_generics ::cell_gc::traits::IntoHeap<#heap_lifetime>
                    for #name #ty_generics
                    #where_clause
                {
                    type In = #storage_type_name #ty_generics;

                    fn into_heap(self) -> Self::In {
                        #storage_type_name {
                            #(
                                #field_names:
                                    ::cell_gc::traits::IntoHeap::into_heap(
                                        self.#field_names_1)
                            ),*
                        }
                    }

                    unsafe fn trace<R>(storage: &Self::In, tracer: &mut R)
                        where R: ::cell_gc::traits::Tracer
                    {
                        #( #trace_fields )*

                        // Quiet unused variable warnings when `$(...)*` expands
                        // to nothing.
                        let _ = tracer;
                    }

                    unsafe fn from_heap(storage: &Self::In) -> Self {
                        #name {
                            #(
                                #field_names:
                                    ::cell_gc::traits::IntoHeap::from_heap(
                                        &storage.#field_names_1)
                            ),*
                        }
                    }
                }
            };

            // 3. IntoHeapAllocation implementation.
            let ref_type_name: Ident = Ident::from(name_str.to_string() + "Ref");
            let into_heap_allocation = quote! {
                impl #impl_generics ::cell_gc::traits::IntoHeapAllocation<#heap_lifetime>
                    for #name #ty_generics
                    #where_clause
                {
                    type Ref = #ref_type_name #ty_generics;

                    fn wrap_gcref(gcref: ::cell_gc::GcRef<#heap_lifetime,
                                                          #name #ty_generics>)
                        -> #ref_type_name #ty_generics
                    {
                        #ref_type_name(gcref)
                    }
                }
            };

            // 4. #ref_type_name: A safe reference to the struct
            let ref_type = quote! {
                #[derive(Clone, Debug, PartialEq, Eq)]
                #vis struct #ref_type_name #impl_generics
                    (::cell_gc::GcRef<#heap_lifetime, #name #ty_generics>)
                    #where_clause;
            };

            // 5. The ref type also gets an IntoHeap impl...
            let ref_type_into_heap = quote! {
                unsafe impl #impl_generics ::cell_gc::traits::IntoHeap<#heap_lifetime>
                    for #ref_type_name #ty_generics
                    #where_clause
                {
                    type In = ::cell_gc::ptr::Pointer<#storage_type_name #ty_generics>;

                    fn into_heap(self) -> Self::In {
                        self.0.ptr()
                    }

                    unsafe fn trace<R>(storage: &Self::In, tracer: &mut R)
                        where R: ::cell_gc::traits::Tracer
                    {
                        if !storage.is_null() {
                            tracer.visit::<#name #ty_generics>(*storage);
                        }
                    }

                    unsafe fn from_heap(storage: &Self::In) -> #ref_type_name #ty_generics {
                        #ref_type_name(::cell_gc::GcRef::<#name #ty_generics>::new(*storage))
                    }
                }
            };

            // 6. Getters and setters.
            let field_setter_names: Vec<_> = fields
                .iter()
                .map(|f| {
                    let field_str: &str = f.ident.as_ref().unwrap().as_ref();
                    Ident::from(format!("set_{}", field_str))
                })
                .collect();
            let accessors = quote! {
                impl #impl_generics #ref_type_name #ty_generics #where_clause {
                    #(
                        #[allow(dead_code)]
                        #field_vis fn #field_names(&self) -> #field_types {
                            let ptr = self.0.as_ptr();
                            unsafe {
                                ::cell_gc::traits::IntoHeap::from_heap(
                                    &(*ptr).#field_names_1)
                            }
                        }
                    )*

                    #(
                        #[allow(dead_code)]
                        #field_vis fn #field_setter_names(&self, v: #field_types) {
                            let ptr = self.0.as_mut_ptr();
                            let u = ::cell_gc::traits::IntoHeap::into_heap(v);
                            unsafe {
                                (*ptr).#field_names = u;
                            }
                        }
                    )*

                    ///// Get all fields at once.
                    //pub fn get(&self) -> #name {
                    //    ::cell_gc::traits::IntoHeap::from_heap(ptr)
                    //}

                    #[allow(dead_code)]
                    pub fn as_mut_ptr(&self) -> *mut #storage_type_name #ty_generics {
                        self.0.as_mut_ptr()
                    }
                }
            };

            quote! {
                #storage_struct
                #into_heap
                #into_heap_allocation
                #ref_type
                #ref_type_into_heap
                #accessors
            }
        }
        syn::VariantData::Tuple(ref _fields) => {
            panic!("#[derive(IntoHeap)] does not support tuple structs");
        }
        syn::VariantData::Unit => {
            panic!("#[derive(IntoHeap)] does not support unit structs");
        }
    }
}

fn impl_into_heap_for_enum(ast: &syn::DeriveInput, variants: &[syn::Variant]) -> Tokens {
    let attrs = &ast.attrs;
    let name = &ast.ident;
    let name_str: &str = name.as_ref();
    let storage_type_name: Ident = Ident::from(name_str.to_string() + "Storage");
    let vis = &ast.vis;
    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
    let heap_lifetime = &ast.generics
        .lifetimes
        .first()
        .expect("lifetime parameter required")
        .lifetime;

    let variant_storage = variants.iter().map(|v| {
        let attrs = &v.attrs;
        let ident = &v.ident;
        if v.discriminant.is_some() {
            panic!("#[derive(IntoHeap)] does not support enum variants with discriminants");
        }
        match v.data {
            syn::VariantData::Struct(ref fields) => {
                let field_decls = fields.iter().map(|f| {
                    let field_attrs = &f.attrs;
                    let field_name = &f.ident;
                    let field_ty = &f.ty;
                    quote! {
                        #( #field_attrs )*
                        #field_name:
                            <#field_ty as ::cell_gc::traits::IntoHeap<#heap_lifetime>>::In
                    }
                });
                quote! {
                    #( #attrs )*
                    #ident { #( #field_decls ),* }
                }
            }
            syn::VariantData::Tuple(ref fields) => {
                let field_decls = fields.iter().map(|f| {
                    let field_ty = &f.ty;
                    let field_attrs = &f.attrs;
                    quote! {
                        #( #field_attrs )*
                        <#field_ty as ::cell_gc::traits::IntoHeap<#heap_lifetime>>::In
                    }
                });
                quote! {
                    #( #attrs )*
                    #ident( #( #field_decls ),* )
                }
            }
            syn::VariantData::Unit => {
                quote! { #( #attrs )* #ident }
            }
        }
    });
    let storage_enum = quote! {
        #( #attrs )*
        #vis enum #storage_type_name #impl_generics
            #where_clause
        {
            #( #variant_storage ),*
        }
    };

    let into_heap_arms = variants.iter().map(|v| {
        let ident = &v.ident;
        match v.data {
            syn::VariantData::Struct(ref fields) => {
                let field_names: &Vec<_> = &fields.iter().map(|f| &f.ident).collect();
                let field_names_1 = field_names;
                let field_types = fields.iter().map(|f| &f.ty);
                quote! {
                    #name::#ident { #(#field_names),* } => {
                        #storage_type_name::#ident {
                            #(
                                #field_names:
                                    <#field_types as ::cell_gc::traits::IntoHeap>
                                    ::into_heap(#field_names_1)
                            ),*
                        }
                    }
                }
            }
            syn::VariantData::Tuple(ref fields) => {
                let field_types = fields.iter().map(|f| &f.ty);
                let bindings: &Vec<Ident> = &(0..fields.len())
                    .map(|n| Ident::from(format!("x{}", n)))
                    .collect();
                quote! {
                    #name::#ident( #(#bindings),* ) => {
                        #storage_type_name::#ident(
                            #(
                                <#field_types as ::cell_gc::traits::IntoHeap>
                                    ::into_heap(#bindings)
                            ),*
                        )
                    }
                }
            }
            syn::VariantData::Unit => {
                quote! {
                    #name::#ident => #storage_type_name::#ident
                }
            }
        }
    });

    let from_heap_arms = variants.iter().map(|v| {
        let ident = &v.ident;
        match v.data {
            syn::VariantData::Struct(ref fields) => {
                let field_names: &Vec<_> = &fields.iter().map(|f| &f.ident).collect();
                let field_names_1 = field_names;
                let field_types = fields.iter().map(|f| &f.ty);
                quote! {
                    #storage_type_name::#ident { #(ref #field_names),* } => {
                        #name::#ident {
                            #(
                                #field_names:
                                    <#field_types as ::cell_gc::traits::IntoHeap>
                                    ::from_heap(#field_names_1)
                            ),*
                        }
                    }
                }
            }
            syn::VariantData::Tuple(ref fields) => {
                let field_types = fields.iter().map(|f| &f.ty);
                let bindings: &Vec<Ident> = &(0..fields.len())
                    .map(|n| Ident::from(format!("x{}", n)))
                    .collect();
                quote! {
                    #storage_type_name::#ident( #(ref #bindings),* ) => {
                        #name::#ident(
                            #(
                                <#field_types as ::cell_gc::traits::IntoHeap>
                                    ::from_heap(#bindings)
                            ),*
                        )
                    }
                }
            }
            syn::VariantData::Unit => {
                quote! {
                    #storage_type_name::#ident => #name::#ident
                }
            }
        }
    });

    let trace_arms = variants.iter().map(|v| {
        let ident = &v.ident;
        match v.data {
            syn::VariantData::Struct(ref fields) => {
                let field_names: &Vec<_> = &fields.iter().map(|f| &f.ident).collect();
                let field_types = fields.iter().map(|f| &f.ty);
                quote! {
                    #storage_type_name::#ident { #(ref #field_names),* } => {
                        #(
                            <#field_types as ::cell_gc::traits::IntoHeap>
                                ::trace(#field_names, tracer);
                        )*
                    }
                }
            }
            syn::VariantData::Tuple(ref fields) => {
                let field_types = fields.iter().map(|f| &f.ty);
                let bindings: &Vec<Ident> = &(0..fields.len())
                    .map(|n| Ident::from(format!("x{}", n)))
                    .collect();
                quote! {
                    #storage_type_name::#ident( #(ref #bindings),* ) => {
                        #(
                            <#field_types as ::cell_gc::traits::IntoHeap>
                                ::trace(#bindings, tracer);
                        )*
                    }
                }
            }
            syn::VariantData::Unit => {
                quote! { #storage_type_name::#ident => () }
            }
        }
    });

    let into_heap = quote! {
        unsafe impl #impl_generics
            ::cell_gc::traits::IntoHeap<#heap_lifetime>
            for #name #ty_generics
            #where_clause
        {
            type In = #storage_type_name #ty_generics;

            fn into_heap(self) -> Self::In {
                match self {
                    #( #into_heap_arms ),*
                }
            }

            unsafe fn from_heap(storage: &Self::In) -> Self {
                match *storage {
                    #( #from_heap_arms ),*
                }
            }

            unsafe fn trace<R>(storage: &Self::In, tracer: &mut R)
                where R: ::cell_gc::traits::Tracer
            {
                match *storage {
                    #( #trace_arms ),*
                }

                // Quiet unused variable warnings when `$(...)*` expands to
                // nothing.
                let _ = tracer;
            }
        }
    };

    quote! {
        #storage_enum
        #into_heap
    }
}
<|endoftext|>