<commit_before>/*!
 * Bounded package merge algorithm, based on the paper
 * "A Fast and Space-Economical Algorithm for Length-Limited Coding
 * Jyrki Katajainen, Alistair Moffat, Andrew Turpin".
 */

use std::mem;
use std::ptr::{null, null_mut};

use libc::{c_void, size_t};
use libc::funcs::c95::stdlib::{free, malloc};

/// Nodes forming chains. Also used to represent leaves.
struct Node {
    /// Total weight (symbol count) of this chain.
    weight: usize,
    /// Previous node(s) of this chain, or 0 if none.
    tail: *mut Node,
    /// Leaf symbol index, or number of leaves before this chain.
    count: i32,
    /// Tracking for garbage collection.
    in_use: bool,
}

/// Memory pool for nodes.
struct NodePool {
    /// The pool.
    nodes: *mut Node,
    /// Pointer to a possibly free node in the pool.
    next: *mut Node,
    /// Size of the memory pool.
    size: u32,
}

/// Initializes a chain node with the given values and marks it as in use.
unsafe fn init_node(weight: usize, count: i32, tail: *mut Node, node: *mut Node) {
    (*node).weight = weight;
    (*node).count = count;
    (*node).tail = tail;
    (*node).in_use = true;
}

/**
 * Finds a free location in the memory pool. Performs garbage collection if needed.
 * lists: If given, used to mark in-use nodes during garbage collection.
 * maxbits: Size of lists.
 * pool: Memory pool to get free node from.
 */
unsafe fn get_free_node(lists: *const *mut *mut Node, maxbits: i32, pool: *mut NodePool) -> *mut Node {
    loop {
        if (*pool).next >= (*pool).nodes.offset((*pool).size as isize) {
            // Garbage collection
            for i in 0..(*pool).size {
                (*(*pool).nodes.offset(i as isize)).in_use = false;
            }
            if lists != null_mut() {
                for i in 0..maxbits*2 {
                    let mut node = *(*lists.offset((i / 2) as isize)).offset((i % 2) as isize);
                    while node != null_mut() {
                        (*node).in_use = true;
                        node = (*node).tail;
                    }
                }
            }
            (*pool).next = (*pool).nodes;
        }
        if (*(*pool).next).in_use {
            break;
        }
        (*pool).next = (*pool).next.offset(1);
    }
    let free_node = (*pool).next;
    (*pool).next = (*pool).next.offset(1);
    free_node
}

/**
 * Performs a Boundary Package-Merge step. Puts a new chain in the given list. The
 * new chain is, depending on the weights, a leaf or a combination of two chains
 * from the previous list.
 * lists: The lists of chains.
 * maxbits: Number of lists.
 * leaves: The leaves, one per symbol.
 * numsymbols: Number of leaves.
 * pool: the node memory pool.
 * index: The index of the list in which a new chain or leaf is required.
 * final: Whether this is the last time this function is called. If it is then it
 *   is no more needed to recursively call self.
 */
unsafe fn boundary_pm(lists: *const *mut *mut Node, maxbits: i32, leaves: *const Node, numsymbols: i32, pool: *mut NodePool,
                      index: i32, is_final: bool) {
    let lastcount = (**(*lists.offset(index as isize)).offset(1)).count; // Count of last chain of list.

    if index == 0 && lastcount >= numsymbols {
        return;
    }

    let newchain = get_free_node(lists, maxbits, pool);
    let oldchain = *(*lists.offset(index as isize)).offset(1);

    // These are set up before the recursive calls below, so that there is a list
    // pointing to the new node, to let the garbage collection know it's in use.
    *(*lists.offset(index as isize)).offset(0) = oldchain;
    *(*lists.offset(index as isize)).offset(1) = newchain;

    if index == 0 {
        //New leaf node in list 0.
        init_node((*leaves.offset(lastcount as isize)).weight, lastcount + 1, null_mut(), newchain);
    } else {
        let sum = (**(*lists.offset((index - 1) as isize)).offset(0)).weight + (**(*lists.offset((index - 1) as isize)).offset(0)).weight;
        if lastcount < numsymbols && sum > (*leaves.offset(lastcount as isize)).weight {
            // New leaf inserted in list, so count is incremented.
            init_node((*leaves.offset(lastcount as isize)).weight, lastcount + 1, (*oldchain).tail, newchain);
        } else {
            init_node(sum, lastcount, *(*lists.offset((index - 1) as isize)).offset(1), newchain);
            if !is_final {
                // Two lookahead chains of previous list used up, create new ones.
                boundary_pm(lists, maxbits, leaves, numsymbols, pool, index - 1, false);
                boundary_pm(lists, maxbits, leaves, numsymbols, pool, index - 1, false);
            }
        }
    }
}

/// Initializes each list with as lookahead chains the two leaves with lowest weights.
unsafe fn init_lists(pool: *mut NodePool, leaves: *const Node, maxbits: i32, lists: *const *mut *mut Node) {
    let node0 = get_free_node(null(), maxbits, pool);
    let node1 = get_free_node(null(), maxbits, pool);
    init_node((*leaves.offset(0)).weight, 1, null_mut(), node0);
    init_node((*leaves.offset(1)).weight, 2, null_mut(), node1);
    for i in 0..maxbits {
        *(*lists.offset(i as isize)).offset(0) = node0;
        *(*lists.offset(i as isize)).offset(1) = node1;
    }
}

/**
 * Converts result of boundary package-merge to the bitlengths. The result in the
 * last chain of the last list contains the amount of active leaves in each list.
 * chain: Chain to extract the bit length from (last chain from last list).
 */
unsafe fn extract_bit_lengths(chain: *const Node, leaves: *const Node, bitlengths: *mut u32) {
    let mut node = chain;
    while node != null() {
        for i in 0..(*node).count {
            *bitlengths.offset((*leaves.offset(i as isize)).count as isize) = *bitlengths.offset((*leaves.offset(i as isize)).count as isize) + 1;
        }
        node = (*node).tail;
    }
}

/// Comparator for sorting the leaves. Has the function signature for qsort.
unsafe fn leaf_comparator(a: *const c_void, b: *const c_void) -> i32 {
    let node_a: *const Node = a as *const Node;
    let node_b: *const Node = b as *const Node;
    (*node_a).weight as i32 - (*node_b).weight as i32
}

#[link(name="c")]
extern {
    fn qsort(base: *mut c_void, nmemb: size_t, size: size_t, compar: extern fn(*const c_void, *const c_void, *const c_void) -> i32);
}

pub unsafe fn length_limited_code_lengths(frequencies: *const usize, n: i32, maxbits: i32, bitlengths: *mut u32) -> bool {
    // Amount of symbols with frequency > 0.
    let mut numsymbols = 0;

    // One leaf per symbol. Only numsymbols leaves will be used.
    let leaves: *mut Node = malloc((n as usize * mem::size_of::<Node>()) as size_t) as *mut Node;

    // Initialize all bitlengths at 0.
    for i in 0..n {
        *bitlengths.offset(i as isize) = 0;
    }

    // Count used symbols and place them in the leaves.
    for i in 0..n {
        if *frequencies.offset(i as isize) != 0 {
            (*leaves.offset(numsymbols)).weight = *frequencies.offset(i as isize);
            (*leaves.offset(numsymbols)).count = i;
            numsymbols = numsymbols + 1;
        }
    }

    // Check special cases and error conditions.
    if (1 << maxbits) < numsymbols {
        free(leaves as *mut c_void);
        return true; // Error, too few maxbits to represent symbols.
    }
    if numsymbols == 0 {
        free(leaves as *mut c_void);
        return false; // No symbols at all. OK.
    }
    if numsymbols == 1 {
        *bitlengths.offset((*leaves.offset(0)).count as isize) = 1;
        free(leaves as *mut c_void);
        return false; // Only one symbol, give it bitlength 1, not 0. OK.
    }

    // Sort the leaves from lightest to heaviest.
    qsort(leaves as *mut c_void, numsymbols as size_t, mem::size_of::<Node>() as size_t, mem::transmute(&leaf_comparator));

    // Initialize node memory pool.
    let pool_size = 2 * maxbits * (maxbits + 1);
    let pool_nodes = malloc((pool_size as usize * mem::size_of::<Node>()) as size_t) as *mut Node;
    let mut pool = NodePool { size: pool_size as u32, nodes: pool_nodes, next: pool_nodes };
    for i in 0..pool.size {
        (*pool.nodes.offset(i as isize)).in_use = false;
    }

    // Array of lists of chains. Each list requires only two lookahead chains at
    // a time, so each list is a array of two Node*'s.
    let lists: *const *mut *mut Node = malloc((maxbits as usize * mem::size_of::<*const *const Node>()) as size_t) as *const *mut *mut Node;
    init_lists(&mut pool, leaves, maxbits, lists);

    // In the last list, 2 * numsymbols - 2 active chains need to be created. Two
    // are already created in the initialization. Each BoundaryPM run creates one.
    let num_boundary_pm_runs = 2 * numsymbols - 4;
    for i in 0..num_boundary_pm_runs {
        let is_final = i == num_boundary_pm_runs - 1;
        boundary_pm(lists, maxbits, leaves, numsymbols as i32, &mut pool, maxbits - 1, is_final);
    }

    extract_bit_lengths(*(*lists.offset(maxbits as isize - 1)).offset(1), leaves, bitlengths);

    free(lists as *mut c_void);
    free(leaves as *mut c_void);
    free(pool.nodes as *mut c_void);
    false
}
<commit_msg>Fix qsort usage<commit_after>/*!
 * Bounded package merge algorithm, based on the paper
 * "A Fast and Space-Economical Algorithm for Length-Limited Coding
 * Jyrki Katajainen, Alistair Moffat, Andrew Turpin".
 */

use std::mem;
use std::ptr::{null, null_mut};

use libc::{c_void, size_t};
use libc::funcs::c95::stdlib::{free, malloc};

/// Nodes forming chains. Also used to represent leaves.
struct Node {
    /// Total weight (symbol count) of this chain.
    weight: usize,
    /// Previous node(s) of this chain, or 0 if none.
    tail: *mut Node,
    /// Leaf symbol index, or number of leaves before this chain.
    count: i32,
    /// Tracking for garbage collection.
    in_use: bool,
}

/// Memory pool for nodes.
struct NodePool {
    /// The pool.
    nodes: *mut Node,
    /// Pointer to a possibly free node in the pool.
    next: *mut Node,
    /// Size of the memory pool.
    size: u32,
}

/// Initializes a chain node with the given values and marks it as in use.
unsafe fn init_node(weight: usize, count: i32, tail: *mut Node, node: *mut Node) {
    (*node).weight = weight;
    (*node).count = count;
    (*node).tail = tail;
    (*node).in_use = true;
}

/**
 * Finds a free location in the memory pool. Performs garbage collection if needed.
 * lists: If given, used to mark in-use nodes during garbage collection.
 * maxbits: Size of lists.
 * pool: Memory pool to get free node from.
 */
unsafe fn get_free_node(lists: *const *mut *mut Node, maxbits: i32, pool: *mut NodePool) -> *mut Node {
    loop {
        if (*pool).next >= (*pool).nodes.offset((*pool).size as isize) {
            // Garbage collection
            for i in 0..(*pool).size {
                (*(*pool).nodes.offset(i as isize)).in_use = false;
            }
            if lists != null_mut() {
                for i in 0..maxbits*2 {
                    let mut node = *(*lists.offset((i / 2) as isize)).offset((i % 2) as isize);
                    while node != null_mut() {
                        (*node).in_use = true;
                        node = (*node).tail;
                    }
                }
            }
            (*pool).next = (*pool).nodes;
        }
        if (*(*pool).next).in_use {
            break;
        }
        (*pool).next = (*pool).next.offset(1);
    }
    let free_node = (*pool).next;
    (*pool).next = (*pool).next.offset(1);
    free_node
}

/**
 * Performs a Boundary Package-Merge step. Puts a new chain in the given list. The
 * new chain is, depending on the weights, a leaf or a combination of two chains
 * from the previous list.
 * lists: The lists of chains.
 * maxbits: Number of lists.
 * leaves: The leaves, one per symbol.
 * numsymbols: Number of leaves.
 * pool: the node memory pool.
 * index: The index of the list in which a new chain or leaf is required.
 * final: Whether this is the last time this function is called. If it is then it
 *   is no more needed to recursively call self.
 */
unsafe fn boundary_pm(lists: *const *mut *mut Node, maxbits: i32, leaves: *const Node, numsymbols: i32, pool: *mut NodePool,
                      index: i32, is_final: bool) {
    let lastcount = (**(*lists.offset(index as isize)).offset(1)).count; // Count of last chain of list.

    if index == 0 && lastcount >= numsymbols {
        return;
    }

    let newchain = get_free_node(lists, maxbits, pool);
    let oldchain = *(*lists.offset(index as isize)).offset(1);

    // These are set up before the recursive calls below, so that there is a list
    // pointing to the new node, to let the garbage collection know it's in use.
    *(*lists.offset(index as isize)).offset(0) = oldchain;
    *(*lists.offset(index as isize)).offset(1) = newchain;

    if index == 0 {
        //New leaf node in list 0.
        init_node((*leaves.offset(lastcount as isize)).weight, lastcount + 1, null_mut(), newchain);
    } else {
        let sum = (**(*lists.offset((index - 1) as isize)).offset(0)).weight + (**(*lists.offset((index - 1) as isize)).offset(0)).weight;
        if lastcount < numsymbols && sum > (*leaves.offset(lastcount as isize)).weight {
            // New leaf inserted in list, so count is incremented.
            init_node((*leaves.offset(lastcount as isize)).weight, lastcount + 1, (*oldchain).tail, newchain);
        } else {
            init_node(sum, lastcount, *(*lists.offset((index - 1) as isize)).offset(1), newchain);
            if !is_final {
                // Two lookahead chains of previous list used up, create new ones.
                boundary_pm(lists, maxbits, leaves, numsymbols, pool, index - 1, false);
                boundary_pm(lists, maxbits, leaves, numsymbols, pool, index - 1, false);
            }
        }
    }
}

/// Initializes each list with as lookahead chains the two leaves with lowest weights.
unsafe fn init_lists(pool: *mut NodePool, leaves: *const Node, maxbits: i32, lists: *const *mut *mut Node) {
    let node0 = get_free_node(null(), maxbits, pool);
    let node1 = get_free_node(null(), maxbits, pool);
    init_node((*leaves.offset(0)).weight, 1, null_mut(), node0);
    init_node((*leaves.offset(1)).weight, 2, null_mut(), node1);
    for i in 0..maxbits {
        *(*lists.offset(i as isize)).offset(0) = node0;
        *(*lists.offset(i as isize)).offset(1) = node1;
    }
}

/**
 * Converts result of boundary package-merge to the bitlengths. The result in the
 * last chain of the last list contains the amount of active leaves in each list.
 * chain: Chain to extract the bit length from (last chain from last list).
 */
unsafe fn extract_bit_lengths(chain: *const Node, leaves: *const Node, bitlengths: *mut u32) {
    let mut node = chain;
    while node != null() {
        for i in 0..(*node).count {
            *bitlengths.offset((*leaves.offset(i as isize)).count as isize) = *bitlengths.offset((*leaves.offset(i as isize)).count as isize) + 1;
        }
        node = (*node).tail;
    }
}

/// Comparator for sorting the leaves. Has the function signature for qsort.
extern fn leaf_comparator(a: *const c_void, b: *const c_void) -> i32 {
    unsafe {
        let node_a: *const Node = a as *const Node;
        let node_b: *const Node = b as *const Node;
        (*node_a).weight as i32 - (*node_b).weight as i32
    }
}

#[link(name="c")]
extern {
    fn qsort(base: *mut c_void, nmemb: size_t, size: size_t, compar: extern fn(*const c_void, *const c_void) -> i32);
}

pub unsafe fn length_limited_code_lengths(frequencies: *const usize, n: i32, maxbits: i32, bitlengths: *mut u32) -> bool {
    // Amount of symbols with frequency > 0.
    let mut numsymbols = 0;

    // One leaf per symbol. Only numsymbols leaves will be used.
    let leaves: *mut Node = malloc((n as usize * mem::size_of::<Node>()) as size_t) as *mut Node;

    // Initialize all bitlengths at 0.
    for i in 0..n {
        *bitlengths.offset(i as isize) = 0;
    }

    // Count used symbols and place them in the leaves.
    for i in 0..n {
        if *frequencies.offset(i as isize) != 0 {
            (*leaves.offset(numsymbols)).weight = *frequencies.offset(i as isize);
            (*leaves.offset(numsymbols)).count = i;
            numsymbols = numsymbols + 1;
        }
    }

    // Check special cases and error conditions.
    if (1 << maxbits) < numsymbols {
        free(leaves as *mut c_void);
        return true; // Error, too few maxbits to represent symbols.
    }
    if numsymbols == 0 {
        free(leaves as *mut c_void);
        return false; // No symbols at all. OK.
    }
    if numsymbols == 1 {
        *bitlengths.offset((*leaves.offset(0)).count as isize) = 1;
        free(leaves as *mut c_void);
        return false; // Only one symbol, give it bitlength 1, not 0. OK.
    }

    // Sort the leaves from lightest to heaviest.
    qsort(leaves as *mut c_void, numsymbols as size_t, mem::size_of::<Node>() as size_t, leaf_comparator);

    // Initialize node memory pool.
    let pool_size = 2 * maxbits * (maxbits + 1);
    let pool_nodes = malloc((pool_size as usize * mem::size_of::<Node>()) as size_t) as *mut Node;
    let mut pool = NodePool { size: pool_size as u32, nodes: pool_nodes, next: pool_nodes };
    for i in 0..pool.size {
        (*pool.nodes.offset(i as isize)).in_use = false;
    }

    // Array of lists of chains. Each list requires only two lookahead chains at
    // a time, so each list is a array of two Node*'s.
    let lists: *const *mut *mut Node = malloc((maxbits as usize * mem::size_of::<*const *const Node>()) as size_t) as *const *mut *mut Node;
    init_lists(&mut pool, leaves, maxbits, lists);

    // In the last list, 2 * numsymbols - 2 active chains need to be created. Two
    // are already created in the initialization. Each BoundaryPM run creates one.
    let num_boundary_pm_runs = 2 * numsymbols - 4;
    for i in 0..num_boundary_pm_runs {
        let is_final = i == num_boundary_pm_runs - 1;
        boundary_pm(lists, maxbits, leaves, numsymbols as i32, &mut pool, maxbits - 1, is_final);
    }

    extract_bit_lengths(*(*lists.offset(maxbits as isize - 1)).offset(1), leaves, bitlengths);

    free(lists as *mut c_void);
    free(leaves as *mut c_void);
    free(pool.nodes as *mut c_void);
    false
}

#[cfg(test)]
mod tests {
    use std::mem::size_of;
    use libc::{c_void, size_t};

    use super::qsort;

    extern fn comparator(a: *const c_void, b: *const c_void) -> i32 {
        unsafe {
            *(a as *const i32) - *(b as *const i32)
        }
    }

    #[test]
    fn test_qsort() {
        unsafe {
            let mut a: [i32; 5] = [3, 2, 4, 1, 5];
            qsort(a.as_mut_ptr() as *mut c_void, a.len() as size_t, size_of::<i32>() as size_t, comparator);
            assert_eq!(a, [1, 2, 3, 4, 5]);
        }
    }
}
<|endoftext|>


<commit_before>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # NDFA
//!
//! The acronym NDFA stands for 'Non-Deterministic Finite Automaton'. An NDFA is a state machine where each state can have
//! transitions for more than one target state - this allows it to be in more than one state at once, which is the property
//! that makes it non-deterministic.
//!
//! NDFAs can match patterns conforming to a regular language - that is, they match regular expressions. However, their
//! non-deterministic nature means that they are inconvenient to evaluate. Fortunately, for every NDFA there can be found
//! a DFA - a *Deterministic* Finite Automaton - which can be used to rapidly match strings of symbols against the expression.
//!
//! Every implementation of the `StateMachine` trait represents an NDFA. This particular implementation is useful because it
//! also implements `MutableStateMachine` so can be used as a means to build state machines that can be used to match patterns.
//!
//! An NDFA is created by calling the constructor:
//!
//! ```
//! # use ndfa::*;
//! let mut ndfa: Ndfa<u32, u32> = Ndfa::new();
//! ```
//!

use super::state_machine::*;
use std::collections::HashMap;
use std::collections::HashSet;

///
/// Represents a non-deterministic finite-state automata
///
#[derive(Clone)]
pub struct Ndfa<InputSymbol, OutputSymbol> where InputSymbol : Clone {
    /// Highest known state ID
    max_state: StateId,

    /// Transitions for each state
    transitions: Vec<Vec<(InputSymbol, StateId)>>,

    /// The states that are joined with the state specified by the index
    joined_with: Vec<Vec<StateId>>,

    /// Output symbols for each state
    output_symbols: HashMap<StateId, OutputSymbol>
}

impl<InputSymbol : Clone, OutputSymbol> Ndfa<InputSymbol, OutputSymbol> {
    ///
    /// Creates a new non-deterministic finite Automaton
    ///
    /// The NDFA will initially just consist of the start state 0. The methods in `MutableStateMachine` should be called to
    /// build it into a more useful structure.
    ///
    pub fn new() -> Ndfa<InputSymbol, OutputSymbol> {
        Ndfa { max_state: 0, transitions: vec![], joined_with: vec![], output_symbols: HashMap::new() }
    }

    ///
    /// Retrieves the complete set of states whose transitions should be returned due to joining for a given state
    ///
    #[inline]
    fn get_join_closure(&self, state: StateId) -> HashSet<StateId> {
        // TODO: this is a great use-case for the BitSet collection (available in the nightlies)

        // The result is initially empty. We'll add the initial state in the first pass
        let mut result: HashSet<StateId> = HashSet::new();

        // Add in any joined states
        let mut stack = vec![];
        stack.push(state);

        while let Some(next_state) = stack.pop() {
            if !result.contains(&next_state) {
                // Add to the result
                result.insert(next_state);

                // Process any states that are joined to this one
                if (next_state as usize) < self.joined_with.len() {
                    let ref join_states = self.joined_with[next_state as usize];

                    for join_to in join_states {
                        stack.push(*join_to);
                    }
                }
            }
        }

        result
    }
}

impl<InputSymbol : Clone, OutputSymbol> StateMachine<InputSymbol, OutputSymbol> for Ndfa<InputSymbol, OutputSymbol> {
    ///
    /// Retrieves the number of states in this state machine
    ///
    fn count_states(&self) -> StateId {
        self.max_state + 1
    }

    ///
    /// Retrieves the transitions for a particular state
    ///
    fn get_transitions_for_state(&self, state: StateId) -> Vec<(InputSymbol, StateId)> {
        let empty           = vec![];

        // The transitions are all the transitions for this state, plus all the transitions in the states that are joined to it
        let joined_states   = self.get_join_closure(state);
        let merged          = joined_states.iter().flat_map(|join_state| {
            if (*join_state as usize) < self.transitions.len() {
                self.transitions[*join_state as usize].iter()
            } else {
                empty.iter()
            }
        });

        merged.map(|item| item.clone()).collect()
    }

    ///
    /// Retrieves the output symbol for a particular state
    ///
    fn output_symbol_for_state(&self, state: StateId) -> Option<&OutputSymbol> {
        self.output_symbols.get(&state)
    }
}

impl<InputSymbol : Clone, OutputSymbol> MutableStateMachine<InputSymbol, OutputSymbol> for Ndfa<InputSymbol, OutputSymbol> {
    ///
    /// Creates a new transition in the state machine
    ///
    fn add_transition(&mut self, state: StateId, for_symbol: InputSymbol, new_state: StateId) {
        // Make sure that max_state reflects the highest state added by the user
        if new_state > self.max_state {
            self.max_state = new_state;
        }

        if state > self.max_state {
            self.max_state = state;
        }

        // Expand the transitions vector so that the new state has somewhere to go
        while self.transitions.len() <= state as usize {
            self.transitions.push(vec![]);
        }

        self.transitions[state as usize].push((for_symbol, new_state));
    }

    ///
    /// Ensures that a state with the specified ID exists in this state machine
    ///
    fn create_state(&mut self, state: StateId) {
        if state > self.max_state {
            self.max_state = state;
        }
    }

    ///
    /// Sets the output symbol for a particular state
    ///
    fn set_output_symbol(&mut self, state: StateId, new_output_symbol: OutputSymbol) {
        // Output symbols update the max state too
        if state > self.max_state {
            self.max_state = state;
        }

        self.output_symbols.insert(state, new_output_symbol);
    }

    ///
    /// Joins two states so that the first state has the same transitions as the second state
    ///
    fn join_states(&mut self, first_state: StateId, second_state: StateId) {
        // Joining states updates the overall state count_states
        if first_state > self.max_state {
            self.max_state = first_state;
        }

        if second_state > self.max_state {
            self.max_state = second_state;
        }

        // Expand the join table so we can add the first state
        while self.joined_with.len() <= first_state as usize {
            self.joined_with.push(vec![]);
        }

        // Join the second state to the first state
        self.joined_with[first_state as usize].push(second_state);
    }
}

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

    #[test]
    fn there_is_initially_one_state() {
        let ndfa: Ndfa<u32, u32> = Ndfa::new();

        assert!(ndfa.count_states() == 1);
    }

    #[test]
    fn can_create_state_1() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.create_state(1);

        assert!(ndfa.count_states() == 2);
    }

    #[test]
    fn adding_transition_updates_max_state_to_target() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.add_transition(0, 42, 1);
        assert!(ndfa.count_states() == 2);
    }

    #[test]
    fn adding_output_symbol_updates_max_state() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.set_output_symbol(1, 128);
        assert!(ndfa.count_states() == 2);
    }

    #[test]
    fn adding_transition_updates_max_state_to_source() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.add_transition(1, 42, 0);
        assert!(ndfa.count_states() == 2);
    }

    #[test]
    fn can_retrieve_transition() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.add_transition(1, 42, 0);
        assert!(ndfa.get_transitions_for_state(1).len() == 1);
        assert!(ndfa.get_transitions_for_state(1)[0] == (42, 0));
    }

    #[test]
    fn can_add_multiple_transitions() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.add_transition(1, 42, 0);
        ndfa.add_transition(1, 42, 2);

        assert!(ndfa.get_transitions_for_state(1).len() == 2);
        assert!(ndfa.get_transitions_for_state(1).contains(&(42, 0)));
        assert!(ndfa.get_transitions_for_state(1).contains(&(42, 2)));
    }

    #[test]
    fn output_symbol_is_none_by_default() {
        let ndfa: Ndfa<u32, u32> = Ndfa::new();

        assert!(ndfa.output_symbol_for_state(0) == None);
        assert!(ndfa.output_symbol_for_state(1) == None);
    }

    #[test]
    fn can_set_output_symbol() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.set_output_symbol(0, 64);

        assert!(ndfa.output_symbol_for_state(0) == Some(&64));
        assert!(ndfa.output_symbol_for_state(1) == None);
    }

    #[test]
    fn join_states_attaches_transitions_to_first_state() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.add_transition(0, 42, 1);
        ndfa.add_transition(1, 43, 2);
        ndfa.join_states(0, 1);

        assert!(ndfa.get_transitions_for_state(0).contains(&(42, 1)));
        assert!(ndfa.get_transitions_for_state(0).contains(&(43, 2)));
    }

    #[test]
    fn adding_transition_after_join_updates_target() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.join_states(0, 1);
        ndfa.add_transition(0, 42, 1);
        ndfa.add_transition(1, 43, 2);

        assert!(ndfa.get_transitions_for_state(0).contains(&(42, 1)));
        assert!(ndfa.get_transitions_for_state(0).contains(&(43, 2)));
    }

    #[test]
    fn join_updates_state_count() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.join_states(0, 1);

        assert!(ndfa.count_states() == 2);
    }

    #[test]
    fn join_states_does_not_attach_to_second_state() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.add_transition(0, 42, 1);
        ndfa.add_transition(1, 43, 2);
        ndfa.join_states(0, 1);

        assert!(!ndfa.get_transitions_for_state(1).contains(&(42, 1)));
        assert!(ndfa.get_transitions_for_state(1).contains(&(43, 2)));
    }

    #[test]
    fn join_states_recurses_to_further_states() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.add_transition(0, 42, 1);
        ndfa.add_transition(1, 43, 2);
        ndfa.add_transition(2, 44, 3);
        ndfa.join_states(0, 1);
        ndfa.join_states(1, 2);

        assert!(ndfa.get_transitions_for_state(0).contains(&(42, 1)));
        assert!(ndfa.get_transitions_for_state(0).contains(&(43, 2)));
        assert!(ndfa.get_transitions_for_state(0).contains(&(44, 3)));
    }

    #[test]
    fn join_loop_attaches_to_both_states() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.add_transition(0, 42, 1);
        ndfa.add_transition(1, 43, 2);
        ndfa.join_states(0, 1);
        ndfa.join_states(1, 0);

        assert!(ndfa.get_transitions_for_state(0).contains(&(42, 1)));
        assert!(ndfa.get_transitions_for_state(0).contains(&(43, 2)));

        assert!(ndfa.get_transitions_for_state(1).contains(&(42, 1)));
        assert!(ndfa.get_transitions_for_state(1).contains(&(43, 2)));
    }
}
<commit_msg>If a state is joined with other states and doesn’t have an output symbol set, pick one from the joined states<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # NDFA
//!
//! The acronym NDFA stands for 'Non-Deterministic Finite Automaton'. An NDFA is a state machine where each state can have
//! transitions for more than one target state - this allows it to be in more than one state at once, which is the property
//! that makes it non-deterministic.
//!
//! NDFAs can match patterns conforming to a regular language - that is, they match regular expressions. However, their
//! non-deterministic nature means that they are inconvenient to evaluate. Fortunately, for every NDFA there can be found
//! a DFA - a *Deterministic* Finite Automaton - which can be used to rapidly match strings of symbols against the expression.
//!
//! Every implementation of the `StateMachine` trait represents an NDFA. This particular implementation is useful because it
//! also implements `MutableStateMachine` so can be used as a means to build state machines that can be used to match patterns.
//!
//! An NDFA is created by calling the constructor:
//!
//! ```
//! # use ndfa::*;
//! let mut ndfa: Ndfa<u32, u32> = Ndfa::new();
//! ```
//!

use super::state_machine::*;
use std::collections::HashMap;
use std::collections::HashSet;

///
/// Represents a non-deterministic finite-state automata
///
#[derive(Clone)]
pub struct Ndfa<InputSymbol, OutputSymbol> where InputSymbol : Clone {
    /// Highest known state ID
    max_state: StateId,

    /// Transitions for each state
    transitions: Vec<Vec<(InputSymbol, StateId)>>,

    /// The states that are joined with the state specified by the index
    joined_with: Vec<Vec<StateId>>,

    /// Output symbols for each state
    output_symbols: HashMap<StateId, OutputSymbol>
}

impl<InputSymbol : Clone, OutputSymbol> Ndfa<InputSymbol, OutputSymbol> {
    ///
    /// Creates a new non-deterministic finite Automaton
    ///
    /// The NDFA will initially just consist of the start state 0. The methods in `MutableStateMachine` should be called to
    /// build it into a more useful structure.
    ///
    pub fn new() -> Ndfa<InputSymbol, OutputSymbol> {
        Ndfa { max_state: 0, transitions: vec![], joined_with: vec![], output_symbols: HashMap::new() }
    }

    ///
    /// Retrieves the complete set of states whose transitions should be returned due to joining for a given state
    ///
    #[inline]
    fn get_join_closure(&self, state: StateId) -> HashSet<StateId> {
        // TODO: this is a great use-case for the BitSet collection (available in the nightlies)

        // The result is initially empty. We'll add the initial state in the first pass
        let mut result: HashSet<StateId> = HashSet::new();

        // Add in any joined states
        let mut stack = vec![];
        stack.push(state);

        while let Some(next_state) = stack.pop() {
            if !result.contains(&next_state) {
                // Add to the result
                result.insert(next_state);

                // Process any states that are joined to this one
                if (next_state as usize) < self.joined_with.len() {
                    let ref join_states = self.joined_with[next_state as usize];

                    for join_to in join_states {
                        stack.push(*join_to);
                    }
                }
            }
        }

        result
    }
}

impl<InputSymbol : Clone, OutputSymbol> StateMachine<InputSymbol, OutputSymbol> for Ndfa<InputSymbol, OutputSymbol> {
    ///
    /// Retrieves the number of states in this state machine
    ///
    fn count_states(&self) -> StateId {
        self.max_state + 1
    }

    ///
    /// Retrieves the transitions for a particular state
    ///
    fn get_transitions_for_state(&self, state: StateId) -> Vec<(InputSymbol, StateId)> {
        let empty           = vec![];

        // The transitions are all the transitions for this state, plus all the transitions in the states that are joined to it
        let joined_states   = self.get_join_closure(state);
        let merged          = joined_states.iter().flat_map(|join_state| {
            if (*join_state as usize) < self.transitions.len() {
                self.transitions[*join_state as usize].iter()
            } else {
                empty.iter()
            }
        });

        merged.map(|item| item.clone()).collect()
    }

    ///
    /// Retrieves the output symbol for a particular state
    ///
    fn output_symbol_for_state(&self, state: StateId) -> Option<&OutputSymbol> {
        let mut result = self.output_symbols.get(&state);

        match result {
            None => {
                let joined_states = self.get_join_closure(state);
                for joined in joined_states {
                    result = self.output_symbols.get(&joined);
                    match result {
                        None => {},
                        _ => { return result; }
                    }
                }

                None
            },

            _ => result
        }
    }
}

impl<InputSymbol : Clone, OutputSymbol> MutableStateMachine<InputSymbol, OutputSymbol> for Ndfa<InputSymbol, OutputSymbol> {
    ///
    /// Creates a new transition in the state machine
    ///
    fn add_transition(&mut self, state: StateId, for_symbol: InputSymbol, new_state: StateId) {
        // Make sure that max_state reflects the highest state added by the user
        if new_state > self.max_state {
            self.max_state = new_state;
        }

        if state > self.max_state {
            self.max_state = state;
        }

        // Expand the transitions vector so that the new state has somewhere to go
        while self.transitions.len() <= state as usize {
            self.transitions.push(vec![]);
        }

        self.transitions[state as usize].push((for_symbol, new_state));
    }

    ///
    /// Ensures that a state with the specified ID exists in this state machine
    ///
    fn create_state(&mut self, state: StateId) {
        if state > self.max_state {
            self.max_state = state;
        }
    }

    ///
    /// Sets the output symbol for a particular state
    ///
    fn set_output_symbol(&mut self, state: StateId, new_output_symbol: OutputSymbol) {
        // Output symbols update the max state too
        if state > self.max_state {
            self.max_state = state;
        }

        self.output_symbols.insert(state, new_output_symbol);
    }

    ///
    /// Joins two states so that the first state has the same transitions as the second state
    ///
    fn join_states(&mut self, first_state: StateId, second_state: StateId) {
        // Joining states updates the overall state count_states
        if first_state > self.max_state {
            self.max_state = first_state;
        }

        if second_state > self.max_state {
            self.max_state = second_state;
        }

        // Expand the join table so we can add the first state
        while self.joined_with.len() <= first_state as usize {
            self.joined_with.push(vec![]);
        }

        // Join the second state to the first state
        self.joined_with[first_state as usize].push(second_state);
    }
}

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

    #[test]
    fn there_is_initially_one_state() {
        let ndfa: Ndfa<u32, u32> = Ndfa::new();

        assert!(ndfa.count_states() == 1);
    }

    #[test]
    fn can_create_state_1() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.create_state(1);

        assert!(ndfa.count_states() == 2);
    }

    #[test]
    fn adding_transition_updates_max_state_to_target() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.add_transition(0, 42, 1);
        assert!(ndfa.count_states() == 2);
    }

    #[test]
    fn adding_output_symbol_updates_max_state() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.set_output_symbol(1, 128);
        assert!(ndfa.count_states() == 2);
    }

    #[test]
    fn adding_transition_updates_max_state_to_source() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.add_transition(1, 42, 0);
        assert!(ndfa.count_states() == 2);
    }

    #[test]
    fn can_retrieve_transition() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.add_transition(1, 42, 0);
        assert!(ndfa.get_transitions_for_state(1).len() == 1);
        assert!(ndfa.get_transitions_for_state(1)[0] == (42, 0));
    }

    #[test]
    fn can_add_multiple_transitions() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.add_transition(1, 42, 0);
        ndfa.add_transition(1, 42, 2);

        assert!(ndfa.get_transitions_for_state(1).len() == 2);
        assert!(ndfa.get_transitions_for_state(1).contains(&(42, 0)));
        assert!(ndfa.get_transitions_for_state(1).contains(&(42, 2)));
    }

    #[test]
    fn output_symbol_is_none_by_default() {
        let ndfa: Ndfa<u32, u32> = Ndfa::new();

        assert!(ndfa.output_symbol_for_state(0) == None);
        assert!(ndfa.output_symbol_for_state(1) == None);
    }

    #[test]
    fn can_set_output_symbol() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.set_output_symbol(0, 64);

        assert!(ndfa.output_symbol_for_state(0) == Some(&64));
        assert!(ndfa.output_symbol_for_state(1) == None);
    }

    #[test]
    fn join_states_attaches_transitions_to_first_state() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.add_transition(0, 42, 1);
        ndfa.add_transition(1, 43, 2);
        ndfa.join_states(0, 1);

        assert!(ndfa.get_transitions_for_state(0).contains(&(42, 1)));
        assert!(ndfa.get_transitions_for_state(0).contains(&(43, 2)));
    }

    #[test]
    fn adding_transition_after_join_updates_target() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.join_states(0, 1);
        ndfa.add_transition(0, 42, 1);
        ndfa.add_transition(1, 43, 2);

        assert!(ndfa.get_transitions_for_state(0).contains(&(42, 1)));
        assert!(ndfa.get_transitions_for_state(0).contains(&(43, 2)));
    }

    #[test]
    fn join_updates_state_count() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.join_states(0, 1);

        assert!(ndfa.count_states() == 2);
    }

    #[test]
    fn join_states_does_not_attach_to_second_state() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.add_transition(0, 42, 1);
        ndfa.add_transition(1, 43, 2);
        ndfa.join_states(0, 1);

        assert!(!ndfa.get_transitions_for_state(1).contains(&(42, 1)));
        assert!(ndfa.get_transitions_for_state(1).contains(&(43, 2)));
    }

    #[test]
    fn join_states_recurses_to_further_states() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.add_transition(0, 42, 1);
        ndfa.add_transition(1, 43, 2);
        ndfa.add_transition(2, 44, 3);
        ndfa.join_states(0, 1);
        ndfa.join_states(1, 2);

        assert!(ndfa.get_transitions_for_state(0).contains(&(42, 1)));
        assert!(ndfa.get_transitions_for_state(0).contains(&(43, 2)));
        assert!(ndfa.get_transitions_for_state(0).contains(&(44, 3)));
    }

    #[test]
    fn join_loop_attaches_to_both_states() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.add_transition(0, 42, 1);
        ndfa.add_transition(1, 43, 2);
        ndfa.join_states(0, 1);
        ndfa.join_states(1, 0);

        assert!(ndfa.get_transitions_for_state(0).contains(&(42, 1)));
        assert!(ndfa.get_transitions_for_state(0).contains(&(43, 2)));

        assert!(ndfa.get_transitions_for_state(1).contains(&(42, 1)));
        assert!(ndfa.get_transitions_for_state(1).contains(&(43, 2)));
    }
}
<|endoftext|>


<commit_before>
use std::ops::{Index, IndexMut};
use value::Value;
use error::Error;

// top level key that contains everything is __top_level__
#[derive(Clone, Debug, PartialEq)]
pub struct Pair {
    pub key: Value,
    pub value: Vec<Pair>
}

impl Pair {
    pub fn new<T>(key: T) -> Pair where Value: From<T> {
        Pair {
            key: Value::from(key),
            value: vec![]
        }
    }

    pub fn add<T>(&mut self, val: T) where Value: From<T> {
        self.value.push(Pair::new(val));
    }

    pub fn add_pair(&mut self, p: Pair) {
        self.value.push(p);
    }

    pub fn get(&self, value: Value) -> Result<&Pair, Error> {
        let mut p = None;
        for (k, v) in self.value.iter().enumerate() {
            if v.key == value {
                p = Some(k);
            }
        }
        if p.is_some() {
            Ok(&self.value[p.unwrap()])
        } else {
            Err(Error::KeyNotFound)
        }
    }

    pub fn get_mut(&mut self, value: Value) -> Result<&mut Pair, Error> {
        let mut p = None;
        for (k, v) in self.value.iter().enumerate() {
            if v.key == value {
                p = Some(k);
            }
        }
        if p.is_some() {
            Ok(&mut self.value[p.unwrap()])
        } else {
            Err(Error::KeyNotFound)
        }
    }
}

impl Index<Value> for Pair {
    type Output = Pair;

    fn index(&self, value: Value) -> &Pair {
        self.get(value).expect("Did not find value in pair")
    }
}

impl IndexMut<Value> for Pair {
    fn index_mut(&mut self, value: Value) -> &mut Pair {
        self.get_mut(value).expect("Did not find value in pair")
    }
}

<commit_msg>update Index/IndexMut for Pair<commit_after>
use std::ops::{Index, IndexMut};
use value::Value;
use error::Error;

// top level key that contains everything is __top_level__
#[derive(Clone, Debug, PartialEq)]
pub struct Pair {
    pub key: Value,
    pub value: Vec<Pair>
}

impl Pair {
    pub fn new<T>(key: T) -> Pair where Value: From<T> {
        Pair {
            key: Value::from(key),
            value: vec![]
        }
    }

    pub fn add<T>(&mut self, val: T) where Value: From<T> {
        self.value.push(Pair::new(val));
    }

    pub fn add_pair(&mut self, p: Pair) {
        self.value.push(p);
    }

    pub fn get(&self, value: Value) -> Result<&Pair, Error> {
        let mut p = None;
        for (k, v) in self.value.iter().enumerate() {
            if v.key == value {
                p = Some(k);
            }
        }
        if p.is_some() {
            Ok(&self.value[p.unwrap()])
        } else {
            Err(Error::KeyNotFound)
        }
    }

    pub fn get_mut(&mut self, value: Value) -> Result<&mut Pair, Error> {
        let mut p = None;
        for (k, v) in self.value.iter().enumerate() {
            if v.key == value {
                p = Some(k);
            }
        }
        if p.is_some() {
            Ok(&mut self.value[p.unwrap()])
        } else {
            Err(Error::KeyNotFound)
        }
    }
}

impl<T> Index<T> for Pair where Value: From<T> {
    type Output = Pair;
    fn index(&self, value: T) -> &Pair {
        self.get(value.into()).expect("Did not find value in pair")
    }
}

impl<T> IndexMut<T> for Pair where Value: From<T> {
    fn index_mut(&mut self, value: T) -> &mut Pair {
        self.get_mut(value.into()).expect("Did not find value in pair")
    }
}

<|endoftext|>


<commit_before>mod body;
mod expr;

use token;
use token::Token;
use Result;
use Expect;

pub use self::body::Body;
pub use self::expr::Expr;

pub struct Block;
pub struct Macro;
pub struct Trait;
pub struct EmbededTemplate; // reference to another module

pub struct Module<'a> {
    // Sub nodes.
    pub body: Body<'a>,
    pub blocks: Vec<Block>,
    pub macros: Vec<Macro>,
    pub traits: Vec<Trait>,

    // Attributes.
    file_id: Option<String>, // this must NOT be treated as file name
    index: i32, // TODO: wtf is this
    embedded_templates: Vec<EmbededTemplate>,

    // TODO: check usage of things bellow
    display_start: Body<'a>,
    display_end: Body<'a>,
    constructor_start: Body<'a>,
    constructor_end: Body<'a>,
    class_end: Body<'a>,
}

/// Root Twig AST node.
impl<'a> Module<'a> {
    pub fn new() -> Module<'a> {
        Module {
            body: Body::new(),
            blocks: vec![],
            macros: vec![],
            traits: vec![],

            file_id: None,
            index: 0,
            embedded_templates: vec![],

            display_start: Body::new(),
            display_end: Body::new(),
            constructor_start: Body::new(),
            constructor_end: Body::new(),
            class_end: Body::new(),
        }
    }

    pub fn from_tokens<'code, I>(mut tokens: I)
        -> Result<Module<'code>>
            where I: Iterator<Item=Result<Token<'code>>>
    {
        let mut module = Module::new();

        module.body = try!(Self::parse_body(&mut tokens));

        Ok(module)
    }

    fn parse_body<'code, I>(tokens: &mut I)
        -> Result<Body<'code>>
            where I: Iterator<Item=Result<Token<'code>>>
    {
        let mut maybe_token = tokens.next();
        let mut line_num = match maybe_token {
            Some(Ok(ref token)) => token.line_num,
            None => 1,
            Some(Err(e)) => return Err(e),
        };
        let mut rv = Vec::new();

        loop {
            match maybe_token {
                Some(Ok(ref token)) => match token.value {
                    token::Value::Text(t) => rv.push(Body::Text(t, token.line_num)),
                    token::Value::VarStart => {
                        let expr = try!(Self::parse_expr(tokens));
                        try!(tokens.expect(token::Value::VarEnd));
                        rv.push(Body::Print(expr, token.line_num));
                    },
                    _ => unimplemented!(),
                },
                None => break,
                Some(Err(e)) => return Err(e),
            };

            maybe_token = tokens.next();
        }

        if rv.len() == 1 {
            Ok(rv.remove(0))
        } else {
            Ok(Body::List(rv))
        }
    }

    fn parse_expr<'code, I>(tokens: &mut I)
        -> Result<Expr<'code>>
            where I: Iterator<Item=Result<Token<'code>>>
    {
        unimplemented!();
        Ok(Expr::Constant("", 1))
    }
}
<commit_msg>Fix ICE on older Rust.<commit_after>mod body;
mod expr;

use token;
use token::Token;
use Result;
use Expect;

pub use self::body::Body;
pub use self::expr::Expr;

pub struct Block;
pub struct Macro;
pub struct Trait;
pub struct EmbededTemplate; // reference to another module

pub struct Module<'a> {
    // Sub nodes.
    pub body: Body<'a>,
    pub blocks: Vec<Block>,
    pub macros: Vec<Macro>,
    pub traits: Vec<Trait>,

    // Attributes.
    file_id: Option<String>, // this must NOT be treated as file name
    index: i32, // TODO: wtf is this
    embedded_templates: Vec<EmbededTemplate>,

    // TODO: check usage of things bellow
    display_start: Body<'a>,
    display_end: Body<'a>,
    constructor_start: Body<'a>,
    constructor_end: Body<'a>,
    class_end: Body<'a>,
}

/// Root Twig AST node.
impl<'a> Module<'a> {
    pub fn new() -> Module<'a> {
        Module {
            body: Body::new(),
            blocks: vec![],
            macros: vec![],
            traits: vec![],

            file_id: None,
            index: 0,
            embedded_templates: vec![],

            display_start: Body::new(),
            display_end: Body::new(),
            constructor_start: Body::new(),
            constructor_end: Body::new(),
            class_end: Body::new(),
        }
    }

    pub fn from_tokens<'code, I>(mut tokens: I)
        -> Result<Module<'code>>
            where I: Iterator<Item=Result<Token<'code>>>
    {
        let mut module = Module::new();

        module.body = try!(Module::parse_body(&mut tokens));

        Ok(module)
    }

    fn parse_body<'code, I>(tokens: &mut I)
        -> Result<Body<'code>>
            where I: Iterator<Item=Result<Token<'code>>>
    {
        let mut maybe_token = tokens.next();
        let mut line_num = match maybe_token {
            Some(Ok(ref token)) => token.line_num,
            None => 1,
            Some(Err(e)) => return Err(e),
        };
        let mut rv = Vec::new();

        loop {
            match maybe_token {
                Some(Ok(ref token)) => match token.value {
                    token::Value::Text(t) => rv.push(Body::Text(t, token.line_num)),
                    token::Value::VarStart => {
                        let expr = try!(Module::parse_expr(tokens));
                        try!(tokens.expect(token::Value::VarEnd));
                        rv.push(Body::Print(expr, token.line_num));
                    },
                    _ => unimplemented!(),
                },
                None => break,
                Some(Err(e)) => return Err(e),
            };

            maybe_token = tokens.next();
        }

        if rv.len() == 1 {
            Ok(rv.remove(0))
        } else {
            Ok(Body::List(rv))
        }
    }

    fn parse_expr<'code, I>(tokens: &mut I)
        -> Result<Expr<'code>>
            where I: Iterator<Item=Result<Token<'code>>>
    {
        Ok(Expr::Constant("", 1))
    }
}
<|endoftext|>


<commit_before>/*!
Library for reading/writing Labeled Tab-Separated Values

# Example

~~~~~~~~~~~~~~~~~~~~~~
extern mod ltsv;
use ltsv::LTSVWriter;
use ltsv::LTSVReader;

fn main() {
    let infile = io::file_reader(&Path("path/fo/file.tlsv")).get();
    for infile.read_ltsv().each |record| {
        for record.each |&(label, value)| {
            io::println(fmt!("%s: %s", *label, *value));
        }
    }
}
~~~~~~~~~~~~~~~~~~~~~~
*/
#[link(name = "ltsv",
       vers = "0.1",
       uuid = "E0EA0251-E165-4612-919F-38E89ACECBE9",
       url  = "https://github.com/tychosci/rust-ltsv/")];

#[comment = "Library for reading/writing Labeled Tab-Separated Values"];
#[license = "MIT license"];
#[crate_type = "lib"];

use core::container::Map;
use core::hashmap::linear::LinearMap;
use io::WriterUtil;

pub type Record = LinearMap<~str, ~str>;

enum Trailing { EOF, NL, TAB }

enum ParseType {
    Record,
    Field,
    FieldLabel,
    FieldValue(Trailing)
}

enum ParseResult<T> {
    ParseError(~str),
    ParseOk(ParseType, T)
}

pub trait LTSVWriter {
    fn write_ltsv(&self, ltsv: &[Record]);
    fn write_ltsv_record(&self, record: &Record);
}

pub trait LTSVReader {
    fn read_ltsv(&self) -> ~[Record];
    fn read_ltsv_record(&self) -> Record;
}

pub impl<T: io::Writer> LTSVWriter for T {
    fn write_ltsv(&self, ltsv: &[Record]) {
        for ltsv.each |record| {
            self.write_ltsv_record(record);
            self.write_char('\n');
        }
    }
    fn write_ltsv_record(&self, record: &Record) {
        let mut is_first = true;
        for record.each |&(k, v)| {
            if !is_first { self.write_char('\t'); }
            self.write_str(fmt!("%s:%s", *k, *v));
            if is_first { is_first = false; }
        }
    }
}

pub impl<T: io::Reader> LTSVReader for T {
    fn read_ltsv(&self) -> ~[Record] {
        let mut parser = LTSVParser::new(self);
        match parser.parse_records() {
            ParseOk(_, records) => records,
            ParseError(reason) => die!(reason)
        }
    }
    fn read_ltsv_record(&self) -> Record {
        let mut parser = LTSVParser::new(self);
        match parser.parse_fields() {
            ParseOk(_, record) => record,
            ParseError(reason) => die!(reason)
        }
    }
}

struct LTSVParser<T> {
    priv rd: &T,
    priv cur: int
}

impl<T: io::Reader> LTSVParser<T> {
    static fn new(rd: &r/T) -> LTSVParser/&r<T> {
        let cur = rd.read_byte();
        LTSVParser { rd: rd, cur: cur }
    }

    fn bump(&mut self) {
        if self.cur != -1 {
            self.cur = self.rd.read_byte();
        }
    }

    fn parse_records(&mut self) -> ParseResult<~[Record]> {
        let mut records = ~[];
        loop {
            match self.parse_fields() {
                ParseOk(_, record) => {
                    records.push(record);
                    if self.cur == -1 { break; }
                }
                ParseError(reason) => {
                    return ParseError(reason);
                }
            }
        }
        ParseOk(Record, records)
    }

    fn parse_fields(&mut self) -> ParseResult<Record> {
        let mut record = LinearMap::new();
        self.skip_whitespaces();
        loop {
            let label = match self.parse_field_label() {
                ParseOk(_, label)  => { self.bump(); label },
                ParseError(reason) => return ParseError(reason)
            };
            match self.parse_field_value() {
                ParseOk(FieldValue(TAB), value) => {
                    self.bump();
                    self.skip_whitespaces();
                    record.insert(label, value);
                }
                ParseOk(_, value) => {
                    self.bump();
                    self.skip_whitespaces();
                    record.insert(label, value);
                    return ParseOk(Field, record);
                }
                ParseError(reason) => {
                    return ParseError(reason);
                }
            }
        }
    }

    fn parse_field_label(&mut self) -> ParseResult<~str> {
        let mut bytes = ~[];
        loop {
            match self.cur {
                0x30..0x39 | 0x41..0x5a | 0x61..0x7a | 0x5f |
                0x2e | 0x2d => bytes.push(self.cur as u8),
                0x3a if bytes.len() == 0 => return ParseError(~"label is empty"),
                0x3a => return ParseOk(FieldLabel, str::from_bytes(bytes)),
                -1   => return ParseError(~"EOF while parsing field label"),
                _    => return ParseError(~"invalid byte detected")
            }
            self.bump();
        }
    }

    fn parse_field_value(&mut self) -> ParseResult<~str> {
        let mut bytes = ~[];
        loop {
            match self.cur {
                0x01..0x08 | 0x0b | 0x0c |
                0x0e..0xff => bytes.push(self.cur as u8),
                0x0d => return self.consume_forward_LF(str::from_bytes(bytes)),
                0x0a => return ParseOk(FieldValue(NL), str::from_bytes(bytes)),
                0x09 => return ParseOk(FieldValue(TAB), str::from_bytes(bytes)),
                -1   => return ParseOk(FieldValue(EOF), str::from_bytes(bytes)),
                _    => return ParseError(~"invalid byte detected")
            }
            self.bump();
        }
    }

    fn consume_forward_LF(&mut self, rv: ~str) -> ParseResult<~str> {
        self.bump();
        if self.cur != 0x0a {
            ParseError(~"CR detected, but not provided with LF")
        } else {
            ParseOk(FieldValue(NL), rv)
        }
    }

    fn skip_whitespaces(&mut self) {
        while char::is_whitespace(self.cur as char) {
            self.bump();
        }
    }
}

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

    #[test]
    fn test_parse_simple() {
        let records = io::with_str_reader(~"a:1\tb:2", |rd| rd.read_ltsv());
        assert records.len() == 1;
    }

    #[test]
    fn test_parse_full() {
        let s = io::with_str_writer(|wr| {
            // genzairyou
            wr.write_str(fmt!("%s:%s\t", "tofu", "豆"));
            wr.write_str(fmt!("%s:%s\t", "kamaboko", "魚"));
            wr.write_str(fmt!("%s:%s\n", "sukonbu", "海藻"));
            // konomi
            wr.write_str(fmt!("%s:%s\t", "tofu", "好き"));
            wr.write_str(fmt!("%s:%s\t", "kamaboko", "普通"));
            wr.write_str(fmt!("%s:%s\n", "sukonbu", "苦手"));
        });
        let records = io::with_str_reader(s, |rd| rd.read_ltsv());
        assert records.len() == 2;
    }

    #[test]
    fn test_parse_ltsv_trailing_nl_and_write() {
        let s = io::with_str_writer(|wr| {
            wr.write_str(fmt!("%s:%s\t", "neko", "yes"));
            wr.write_str(fmt!("%s:%s\t", "inu", "yes"));
            wr.write_str(fmt!("%s:%s\n", "tori", "yes"));
        });
        let records_1 = io::with_str_reader(s, |rd| rd.read_ltsv());
        let s2 = io::with_str_writer(|wr| wr.write_ltsv(records_1));
        let records_2 = io::with_str_reader(s2, |rd| rd.read_ltsv());
        assert records_1 == records_2;
    }
}
<commit_msg>Remove read_ltsv_record() from LTSVReader<commit_after>/*!
Library for reading/writing Labeled Tab-Separated Values

# Example

~~~~~~~~~~~~~~~~~~~~~~
extern mod ltsv;
use ltsv::LTSVWriter;
use ltsv::LTSVReader;

fn main() {
    let infile = io::file_reader(&Path("path/fo/file.tlsv")).get();
    for infile.read_ltsv().each |record| {
        for record.each |&(label, value)| {
            io::println(fmt!("%s: %s", *label, *value));
        }
    }
}
~~~~~~~~~~~~~~~~~~~~~~
*/
#[link(name = "ltsv",
       vers = "0.1",
       uuid = "E0EA0251-E165-4612-919F-38E89ACECBE9",
       url  = "https://github.com/tychosci/rust-ltsv/")];

#[comment = "Library for reading/writing Labeled Tab-Separated Values"];
#[license = "MIT license"];
#[crate_type = "lib"];

use core::container::Map;
use core::hashmap::linear::LinearMap;
use io::WriterUtil;

pub type Record = LinearMap<~str, ~str>;

enum Trailing { EOF, NL, TAB }

enum ParseType {
    Record,
    Field,
    FieldLabel,
    FieldValue(Trailing)
}

enum ParseResult<T> {
    ParseError(~str),
    ParseOk(ParseType, T)
}

pub trait LTSVWriter {
    fn write_ltsv(&self, ltsv: &[Record]);
    fn write_ltsv_record(&self, record: &Record);
}

pub trait LTSVReader {
    fn read_ltsv(&self) -> ~[Record];
}

pub impl<T: io::Writer> LTSVWriter for T {
    fn write_ltsv(&self, ltsv: &[Record]) {
        for ltsv.each |record| {
            self.write_ltsv_record(record);
            self.write_char('\n');
        }
    }
    fn write_ltsv_record(&self, record: &Record) {
        let mut is_first = true;
        for record.each |&(k, v)| {
            if !is_first { self.write_char('\t'); }
            self.write_str(fmt!("%s:%s", *k, *v));
            if is_first { is_first = false; }
        }
    }
}

pub impl<T: io::Reader> LTSVReader for T {
    fn read_ltsv(&self) -> ~[Record] {
        let mut parser = LTSVParser::new(self);
        match parser.parse_records() {
            ParseOk(_, records) => records,
            ParseError(reason) => die!(reason)
        }
    }
}

struct LTSVParser<T> {
    priv rd: &T,
    priv cur: int
}

impl<T: io::Reader> LTSVParser<T> {
    static fn new(rd: &r/T) -> LTSVParser/&r<T> {
        let cur = rd.read_byte();
        LTSVParser { rd: rd, cur: cur }
    }

    fn bump(&mut self) {
        if self.cur != -1 {
            self.cur = self.rd.read_byte();
        }
    }

    fn parse_records(&mut self) -> ParseResult<~[Record]> {
        let mut records = ~[];
        loop {
            match self.parse_fields() {
                ParseOk(_, record) => {
                    records.push(record);
                    if self.cur == -1 { break; }
                }
                ParseError(reason) => {
                    return ParseError(reason);
                }
            }
        }
        ParseOk(Record, records)
    }

    fn parse_fields(&mut self) -> ParseResult<Record> {
        let mut record = LinearMap::new();
        self.skip_whitespaces();
        loop {
            let label = match self.parse_field_label() {
                ParseOk(_, label)  => { self.bump(); label },
                ParseError(reason) => return ParseError(reason)
            };
            match self.parse_field_value() {
                ParseOk(FieldValue(TAB), value) => {
                    self.bump();
                    self.skip_whitespaces();
                    record.insert(label, value);
                }
                ParseOk(_, value) => {
                    self.bump();
                    self.skip_whitespaces();
                    record.insert(label, value);
                    return ParseOk(Field, record);
                }
                ParseError(reason) => {
                    return ParseError(reason);
                }
            }
        }
    }

    fn parse_field_label(&mut self) -> ParseResult<~str> {
        let mut bytes = ~[];
        loop {
            match self.cur {
                0x30..0x39 | 0x41..0x5a | 0x61..0x7a | 0x5f |
                0x2e | 0x2d => bytes.push(self.cur as u8),
                0x3a if bytes.len() == 0 => return ParseError(~"label is empty"),
                0x3a => return ParseOk(FieldLabel, str::from_bytes(bytes)),
                -1   => return ParseError(~"EOF while parsing field label"),
                _    => return ParseError(~"invalid byte detected")
            }
            self.bump();
        }
    }

    fn parse_field_value(&mut self) -> ParseResult<~str> {
        let mut bytes = ~[];
        loop {
            match self.cur {
                0x01..0x08 | 0x0b | 0x0c |
                0x0e..0xff => bytes.push(self.cur as u8),
                0x0d => return self.consume_forward_LF(str::from_bytes(bytes)),
                0x0a => return ParseOk(FieldValue(NL), str::from_bytes(bytes)),
                0x09 => return ParseOk(FieldValue(TAB), str::from_bytes(bytes)),
                -1   => return ParseOk(FieldValue(EOF), str::from_bytes(bytes)),
                _    => return ParseError(~"invalid byte detected")
            }
            self.bump();
        }
    }

    fn consume_forward_LF(&mut self, rv: ~str) -> ParseResult<~str> {
        self.bump();
        if self.cur != 0x0a {
            ParseError(~"CR detected, but not provided with LF")
        } else {
            ParseOk(FieldValue(NL), rv)
        }
    }

    fn skip_whitespaces(&mut self) {
        while char::is_whitespace(self.cur as char) {
            self.bump();
        }
    }
}

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

    #[test]
    fn test_parse_simple() {
        let records = io::with_str_reader(~"a:1\tb:2", |rd| rd.read_ltsv());
        assert records.len() == 1;
    }

    #[test]
    fn test_parse_full() {
        let s = io::with_str_writer(|wr| {
            // genzairyou
            wr.write_str(fmt!("%s:%s\t", "tofu", "豆"));
            wr.write_str(fmt!("%s:%s\t", "kamaboko", "魚"));
            wr.write_str(fmt!("%s:%s\n", "sukonbu", "海藻"));
            // konomi
            wr.write_str(fmt!("%s:%s\t", "tofu", "好き"));
            wr.write_str(fmt!("%s:%s\t", "kamaboko", "普通"));
            wr.write_str(fmt!("%s:%s\n", "sukonbu", "苦手"));
        });
        let records = io::with_str_reader(s, |rd| rd.read_ltsv());
        assert records.len() == 2;
    }

    #[test]
    fn test_parse_ltsv_trailing_nl_and_write() {
        let s = io::with_str_writer(|wr| {
            wr.write_str(fmt!("%s:%s\t", "neko", "yes"));
            wr.write_str(fmt!("%s:%s\t", "inu", "yes"));
            wr.write_str(fmt!("%s:%s\n", "tori", "yes"));
        });
        let records_1 = io::with_str_reader(s, |rd| rd.read_ltsv());
        let s2 = io::with_str_writer(|wr| wr.write_ltsv(records_1));
        let records_2 = io::with_str_reader(s2, |rd| rd.read_ltsv());
        assert records_1 == records_2;
    }
}
<|endoftext|>


<commit_before>/*!
Typed virtual address.
*/

use std::{cmp, fmt, hash, mem, str};
use std::marker::PhantomData;

use crate::Pod;

use super::image::{Va, SignedVa};

/// Typed virtual address.
#[repr(transparent)]
pub struct Ptr<T: ?Sized = ()> {
	va: Va,
	marker: PhantomData<fn() -> T>
}

impl<T: ?Sized> Ptr<T> {
	/// Null pointer constant.
	pub const NULL: Ptr<T> = Ptr { va: 0, marker: PhantomData };
	/// Creates a null pointer.
	pub fn null() -> Ptr<T> {
		Ptr::NULL
	}
	/// Returns true if the pointer is null.
	pub fn is_null(self) -> bool {
		self.va == 0
	}
	/// Constructs a pointer with an offset.
	pub fn member(va: Va, offset: u32) -> Ptr<T> {
		let va = va + offset as Va;
		Ptr { va, marker: PhantomData }
	}
	/// Casts the pointer to a different type keeping the pointer address fixed.
	pub fn cast<U: ?Sized>(self) -> Ptr<U> {
		Ptr { va: self.va, marker: PhantomData }
	}
	/// Offsets and casts the pointer.
	///
	/// Because the type of the current and the target may be unrelated, this is a byte offset.
	///
	/// # Examples
	///
	/// ```
	/// use pelite::pe64::Ptr;
	///
	/// #[repr(C)]
	/// struct Composite {
	/// 	int: i32,
	/// 	float: f32,
	/// }
	///
	/// let p: Ptr<Composite> = Ptr::from(0x2000);
	/// let target = p.offset::<f32>(4);
	///
	/// assert_eq!(target, Ptr::from(0x2004));
	/// ```
	pub fn offset<U: ?Sized>(self, offset: SignedVa) -> Ptr<U> {
		let va = self.va.wrapping_add(offset as Va);
		Ptr { va, marker: PhantomData }
	}
	/// Returns the raw integer, type ascription helper.
	pub fn into_raw(self) -> Va {
		self.va
	}
	/// Formats the pointer.
	fn fmt(self) -> [u8; mem::size_of::<Va>() * 2 + 2] {
		let mut s = [0; mem::size_of::<Va>() * 2 + 2];
		s[0] = b'0';
		s[1] = b'x';
		let mut va = self.va;
		for i in 0..mem::size_of::<Va>() * 2 {
			va = va.rotate_left(4);
			let digit = (va & 0xf) as u8;
			let chr = if digit < 10 { b'0' + digit } else { b'a' + (digit - 10) };
			s[i + 2] = chr;
		}
		return s;
	}
}
impl<T> Ptr<[T]> {
	/// Decays the pointer from `[T]` to `T`.
	pub fn decay(self) -> Ptr<T> {
		Ptr { va: self.va, marker: PhantomData }
	}
	/// Pointer arithmetic, gets the pointer of an element at the specified index.
	pub fn at(self, i: usize) -> Ptr<T> {
		let va = self.va + (i * mem::size_of::<T>()) as Va;
		Ptr { va, marker: PhantomData }
	}
}

unsafe impl<T: ?Sized> Pod for Ptr<T> where Ptr<T>: 'static {}

impl<T: ?Sized> Copy for Ptr<T> {}
impl<T: ?Sized> Clone for Ptr<T> {
	fn clone(&self) -> Ptr<T> {
		*self
	}
}
impl<T: ?Sized> Default for Ptr<T> {
	fn default() -> Ptr<T> {
		Ptr::NULL
	}
}
impl<T: ?Sized> Eq for Ptr<T> {}
impl<T: ?Sized> PartialEq for Ptr<T> {
	fn eq(&self, rhs: &Ptr<T>) -> bool {
		self.va == rhs.va
	}
}
impl<T: ?Sized> PartialOrd for Ptr<T> {
	fn partial_cmp(&self, rhs: &Ptr<T>) -> Option<cmp::Ordering> {
		self.va.partial_cmp(&rhs.va)
	}
}
impl<T: ?Sized> Ord for Ptr<T> {
	fn cmp(&self, rhs: &Ptr<T>) -> cmp::Ordering {
		self.va.cmp(&rhs.va)
	}
}
impl<T: ?Sized> hash::Hash for Ptr<T> {
	fn hash<H: hash::Hasher>(&self, state: &mut H) {
		self.va.hash(state)
	}
}
impl<T: ?Sized> From<Va> for Ptr<T> {
	fn from(va: Va) -> Ptr<T> {
		Ptr { va, marker: PhantomData }
	}
}
impl<T: ?Sized> From<Ptr<T>> for Va {
	fn from(ptr: Ptr<T>) -> Va {
		ptr.va
	}
}
impl<T: ?Sized> AsRef<Va> for Ptr<T> {
	fn as_ref(&self) -> &Va {
		&self.va
	}
}
impl<T: ?Sized> AsMut<Va> for Ptr<T> {
	fn as_mut(&mut self) -> &mut Va {
		&mut self.va
	}
}
impl<T: ?Sized> fmt::Debug for Ptr<T> {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		let buf = Ptr::fmt(*self);
		f.write_str(unsafe { str::from_utf8_unchecked(&buf) })
	}
}
impl<T: ?Sized> fmt::UpperHex for Ptr<T> {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		self.va.fmt(f)
	}
}
impl<T: ?Sized> fmt::LowerHex for Ptr<T> {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		self.va.fmt(f)
	}
}
impl<T: ?Sized> fmt::Display for Ptr<T> {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		let buf = Ptr::fmt(*self);
		f.write_str(unsafe { str::from_utf8_unchecked(&buf) })
	}
}

#[cfg(feature = "serde")]
impl<T: ?Sized> serde::Serialize for Ptr<T> {
	fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
		branch! {
			pe32 { serializer.serialize_u32(self.va) }
			pe64 { serializer.serialize_u64(self.va) }
		}
	}
}
<commit_msg>Const fn pointers (#163)<commit_after>/*!
Typed virtual address.
*/

use std::{cmp, fmt, hash, mem, str};
use std::marker::PhantomData;

use crate::Pod;

use super::image::{Va, SignedVa};

/// Typed virtual address.
#[repr(transparent)]
pub struct Ptr<T: ?Sized = ()> {
	va: Va,
	marker: PhantomData<fn() -> T>
}

impl<T: ?Sized> Ptr<T> {
	// Work around unstable const fn features
	const MARKER: PhantomData<fn() -> T> = PhantomData;
	/// Null pointer constant.
	pub const NULL: Ptr<T> = Ptr { va: 0, marker: PhantomData };
	/// Creates a null pointer.
	pub const fn null() -> Ptr<T> {
		Ptr::NULL
	}
	/// Returns true if the pointer is null.
	pub const fn is_null(self) -> bool {
		self.va == 0
	}
	/// Constructs a pointer with an offset.
	pub const fn member(va: Va, offset: u32) -> Ptr<T> {
		let va = va + offset as Va;
		Ptr { va, marker: Self::MARKER }
	}
	/// Casts the pointer to a different type keeping the pointer address fixed.
	pub const fn cast<U: ?Sized>(self) -> Ptr<U> {
		Ptr { va: self.va, marker: Ptr::<U>::MARKER }
	}
	/// Offsets and casts the pointer.
	///
	/// Because the type of the current and the target may be unrelated, this is a byte offset.
	///
	/// # Examples
	///
	/// ```
	/// use pelite::pe64::Ptr;
	///
	/// #[repr(C)]
	/// struct Composite {
	/// 	int: i32,
	/// 	float: f32,
	/// }
	///
	/// let p: Ptr<Composite> = Ptr::from(0x2000);
	/// let target = p.offset::<f32>(4);
	///
	/// assert_eq!(target, Ptr::from(0x2004));
	/// ```
	pub const fn offset<U: ?Sized>(self, offset: SignedVa) -> Ptr<U> {
		let va = self.va.wrapping_add(offset as Va);
		Ptr { va, marker: Ptr::<U>::MARKER }
	}
	/// Returns the raw integer, type ascription helper.
	pub const fn into_raw(self) -> Va {
		self.va
	}
	/// Formats the pointer.
	fn fmt(self) -> [u8; mem::size_of::<Va>() * 2 + 2] {
		let mut s = [0; mem::size_of::<Va>() * 2 + 2];
		s[0] = b'0';
		s[1] = b'x';
		let mut va = self.va;
		for i in 0..mem::size_of::<Va>() * 2 {
			va = va.rotate_left(4);
			let digit = (va & 0xf) as u8;
			let chr = if digit < 10 { b'0' + digit } else { b'a' + (digit - 10) };
			s[i + 2] = chr;
		}
		return s;
	}
}
impl<T> Ptr<[T]> {
	/// Decays the pointer from `[T]` to `T`.
	pub const fn decay(self) -> Ptr<T> {
		Ptr { va: self.va, marker: Ptr::<T>::MARKER }
	}
	/// Pointer arithmetic, gets the pointer of an element at the specified index.
	pub const fn at(self, i: usize) -> Ptr<T> {
		let va = self.va + (i * mem::size_of::<T>()) as Va;
		Ptr { va, marker: Ptr::<T>::MARKER }
	}
}

unsafe impl<T: ?Sized> Pod for Ptr<T> where Ptr<T>: 'static {}

impl<T: ?Sized> Copy for Ptr<T> {}
impl<T: ?Sized> Clone for Ptr<T> {
	fn clone(&self) -> Ptr<T> {
		*self
	}
}
impl<T: ?Sized> Default for Ptr<T> {
	fn default() -> Ptr<T> {
		Ptr::NULL
	}
}
impl<T: ?Sized> Eq for Ptr<T> {}
impl<T: ?Sized> PartialEq for Ptr<T> {
	fn eq(&self, rhs: &Ptr<T>) -> bool {
		self.va == rhs.va
	}
}
impl<T: ?Sized> PartialOrd for Ptr<T> {
	fn partial_cmp(&self, rhs: &Ptr<T>) -> Option<cmp::Ordering> {
		self.va.partial_cmp(&rhs.va)
	}
}
impl<T: ?Sized> Ord for Ptr<T> {
	fn cmp(&self, rhs: &Ptr<T>) -> cmp::Ordering {
		self.va.cmp(&rhs.va)
	}
}
impl<T: ?Sized> hash::Hash for Ptr<T> {
	fn hash<H: hash::Hasher>(&self, state: &mut H) {
		self.va.hash(state)
	}
}
impl<T: ?Sized> From<Va> for Ptr<T> {
	fn from(va: Va) -> Ptr<T> {
		Ptr { va, marker: PhantomData }
	}
}
impl<T: ?Sized> From<Ptr<T>> for Va {
	fn from(ptr: Ptr<T>) -> Va {
		ptr.va
	}
}
impl<T: ?Sized> AsRef<Va> for Ptr<T> {
	fn as_ref(&self) -> &Va {
		&self.va
	}
}
impl<T: ?Sized> AsMut<Va> for Ptr<T> {
	fn as_mut(&mut self) -> &mut Va {
		&mut self.va
	}
}
impl<T: ?Sized> fmt::Debug for Ptr<T> {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		let buf = Ptr::fmt(*self);
		f.write_str(unsafe { str::from_utf8_unchecked(&buf) })
	}
}
impl<T: ?Sized> fmt::UpperHex for Ptr<T> {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		self.va.fmt(f)
	}
}
impl<T: ?Sized> fmt::LowerHex for Ptr<T> {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		self.va.fmt(f)
	}
}
impl<T: ?Sized> fmt::Display for Ptr<T> {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		let buf = Ptr::fmt(*self);
		f.write_str(unsafe { str::from_utf8_unchecked(&buf) })
	}
}

#[cfg(feature = "serde")]
impl<T: ?Sized> serde::Serialize for Ptr<T> {
	fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
		branch! {
			pe32 { serializer.serialize_u32(self.va) }
			pe64 { serializer.serialize_u64(self.va) }
		}
	}
}
<|endoftext|>


<commit_before>extern crate pkg_config;

use std::env;
use std::fs::{self, File};
use std::io::ErrorKind;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use std::process::Command;

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(n) => n,
        Err(e) => fail(&format!("\n{} failed with {}\n", stringify!($e), e)),
    })
}

fn main() {
    register_dep("SSH2");
    register_dep("OPENSSL");

    if env::var("LIBSSH2_SYS_USE_PKG_CONFIG").is_ok() {
        if pkg_config::find_library("libgit2").is_ok() {
            return
        }
    }

    let mut cflags = env::var("CFLAGS").unwrap_or(String::new());
    let target = env::var("TARGET").unwrap();
    let mingw = target.contains("windows-gnu");
    let msvc = target.contains("msvc");

    if msvc {
        // libgit2 passes the /GL flag to enable whole program optimization, but
        // this requires that the /LTCG flag is passed to the linker later on,
        // and currently the compiler does not do that, so we disable whole
        // program optimization entirely.
        cflags.push_str(" /GL-");
    } else {
        cflags.push_str(" -ffunction-sections -fdata-sections");

        if target.contains("i686") {
            cflags.push_str(" -m32");
        } else if target.contains("x86_64") {
            cflags.push_str(" -m64");
        }
        if !target.contains("i686") {
            cflags.push_str(" -fPIC");
        }
    }

    // libgit2 uses pkg-config to discover libssh2, but this doesn't work on
    // windows as libssh2 doesn't come with a libssh2.pc file in that install.
    // As a result we just manually turn on SSH support in libgit2 (a little
    // jankily) here...
    if mingw {
        cflags.push_str(" -DGIT_SSH");
        let libssh2_root = env::var("DEP_SSH2_ROOT").unwrap();
        cflags.push_str(&format!(" -I{}/include", libssh2_root));
    } else if msvc {
        cflags.push_str(" /DGIT_SSH");
        let libssh2_root = env::var("DEP_SSH2_ROOT").unwrap();
        cflags.push_str(&format!(" /I{}\\include", libssh2_root));
    }

    let src = PathBuf::from(&env::var("CARGO_MANIFEST_DIR").unwrap());
    let dst = PathBuf::from(&env::var("OUT_DIR").unwrap());
    let _ = fs::create_dir(&dst.join("build"));

    let mut cmd = Command::new("cmake");
    cmd.arg(&src.join("libgit2"))
       .current_dir(&dst.join("build"));
    if mingw {
        cmd.arg("-G").arg("Unix Makefiles");
    } else if msvc {
        // If we don't pass this unfortunately cmake produces 32-bit builds
        cmd.arg("-G").arg("Visual Studio 12 2013 Win64");

        // Currently liblibc links to msvcrt which apparently is a dynamic CRT,
        // so we need to turn this off to get it to link right.
        cmd.arg("-DSTATIC_CRT=OFF");
    }
    let profile = match &env::var("PROFILE").unwrap()[..] {
        "bench" | "release" => "Release",
        _ => "Debug",
    };
    run(cmd.arg("-DBUILD_SHARED_LIBS=OFF")
           .arg("-DBUILD_CLAR=OFF")
           .arg(&format!("-DCMAKE_BUILD_TYPE={}", profile))
           .arg(&format!("-DCMAKE_INSTALL_PREFIX={}", dst.display()))
           .arg(&format!("-DCMAKE_C_FLAGS={}", cflags)), "cmake");

    let flags = dst.join("build/CMakeFiles/git2.dir/flags.make");
    let mut contents = String::new();

    // Make sure libssh2 was detected on unix systems, because it definitely
    // should have been!
    if !msvc {
        t!(t!(File::open(flags)).read_to_string(&mut contents));
        if !contents.contains("-DGIT_SSH") {
            fail("libgit2 failed to find libssh2, and SSH support is required");
        }
    }

    run(Command::new("cmake")
                .arg("--build").arg(".")
                .arg("--target").arg("install")
                .arg("--config").arg(profile)
                .current_dir(&dst.join("build")), "cmake");

    println!("cargo:root={}", dst.display());
    if mingw || target.contains("windows") {
        println!("cargo:rustc-flags=-l winhttp -l rpcrt4 -l ole32 \
                                    -l static=git2");
        println!("cargo:rustc-link-search=native={}/lib", dst.display());
        return
    }

    if env::var("HOST") == env::var("TARGET") {
        prepend("PKG_CONFIG_PATH", dst.join("lib/pkgconfig"));
        if pkg_config::Config::new().statik(true).find("libgit2").is_ok() {
            return
        }
    }

    println!("cargo:rustc-flags=-l static=git2");
    println!("cargo:rustc-flags=-L {}", dst.join("lib").display());
    if target.contains("apple") {
        println!("cargo:rustc-flags=-l iconv");
    }
}

fn run(cmd: &mut Command, program: &str) {
    println!("running: {:?}", cmd);
    let status = match cmd.status() {
        Ok(status) => status,
        Err(ref e) if e.kind() == ErrorKind::NotFound => {
            fail(&format!("failed to execute command: {}\nis `{}` not installed?",
                          e, program));
        }
        Err(e) => fail(&format!("failed to execute command: {}", e)),
    };
    if !status.success() {
        fail(&format!("command did not execute successfully, got: {}", status));
    }
}

fn register_dep(dep: &str) {
    match env::var(&format!("DEP_{}_ROOT", dep)) {
        Ok(s) => {
            prepend("CMAKE_PREFIX_PATH", PathBuf::from(&s));
            prepend("PKG_CONFIG_PATH", Path::new(&s).join("lib/pkgconfig"));
        }
        Err(..) => {}
    }
}

fn prepend(var: &str, val: PathBuf) {
    let prefix = env::var(var).unwrap_or(String::new());
    let mut v = vec![val];
    v.extend(env::split_paths(&prefix));
    env::set_var(var, &env::join_paths(v).unwrap());
}

fn fail(s: &str) -> ! {
    panic!("\n{}\n\nbuild script failed, must exit now", s)
}
<commit_msg>Always use Release on MSVC<commit_after>extern crate pkg_config;

use std::env;
use std::fs::{self, File};
use std::io::ErrorKind;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use std::process::Command;

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(n) => n,
        Err(e) => fail(&format!("\n{} failed with {}\n", stringify!($e), e)),
    })
}

fn main() {
    register_dep("SSH2");
    register_dep("OPENSSL");

    if env::var("LIBSSH2_SYS_USE_PKG_CONFIG").is_ok() {
        if pkg_config::find_library("libgit2").is_ok() {
            return
        }
    }

    let mut cflags = env::var("CFLAGS").unwrap_or(String::new());
    let target = env::var("TARGET").unwrap();
    let mingw = target.contains("windows-gnu");
    let msvc = target.contains("msvc");

    if msvc {
        // libgit2 passes the /GL flag to enable whole program optimization, but
        // this requires that the /LTCG flag is passed to the linker later on,
        // and currently the compiler does not do that, so we disable whole
        // program optimization entirely.
        cflags.push_str(" /GL-");
    } else {
        cflags.push_str(" -ffunction-sections -fdata-sections");

        if target.contains("i686") {
            cflags.push_str(" -m32");
        } else if target.contains("x86_64") {
            cflags.push_str(" -m64");
        }
        if !target.contains("i686") {
            cflags.push_str(" -fPIC");
        }
    }

    // libgit2 uses pkg-config to discover libssh2, but this doesn't work on
    // windows as libssh2 doesn't come with a libssh2.pc file in that install.
    // As a result we just manually turn on SSH support in libgit2 (a little
    // jankily) here...
    if mingw {
        cflags.push_str(" -DGIT_SSH");
        let libssh2_root = env::var("DEP_SSH2_ROOT").unwrap();
        cflags.push_str(&format!(" -I{}/include", libssh2_root));
    } else if msvc {
        cflags.push_str(" /DGIT_SSH");
        let libssh2_root = env::var("DEP_SSH2_ROOT").unwrap();
        cflags.push_str(&format!(" /I{}\\include", libssh2_root));
    }

    let src = PathBuf::from(&env::var("CARGO_MANIFEST_DIR").unwrap());
    let dst = PathBuf::from(&env::var("OUT_DIR").unwrap());
    let _ = fs::create_dir(&dst.join("build"));

    let mut cmd = Command::new("cmake");
    cmd.arg(&src.join("libgit2"))
       .current_dir(&dst.join("build"));
    if mingw {
        cmd.arg("-G").arg("Unix Makefiles");
    } else if msvc {
        // If we don't pass this unfortunately cmake produces 32-bit builds
        cmd.arg("-G").arg("Visual Studio 12 2013 Win64");

        // Currently liblibc links to msvcrt which apparently is a dynamic CRT,
        // so we need to turn this off to get it to link right.
        cmd.arg("-DSTATIC_CRT=OFF");
    }
    let profile = match &env::var("PROFILE").unwrap()[..] {
        "bench" | "release" => "Release",
        _ if msvc => "Release", // currently we need to always use the same CRT
        _ => "Debug",
    };
    run(cmd.arg("-DBUILD_SHARED_LIBS=OFF")
           .arg("-DBUILD_CLAR=OFF")
           .arg(&format!("-DCMAKE_BUILD_TYPE={}", profile))
           .arg(&format!("-DCMAKE_INSTALL_PREFIX={}", dst.display()))
           .arg(&format!("-DCMAKE_C_FLAGS={}", cflags)), "cmake");

    let flags = dst.join("build/CMakeFiles/git2.dir/flags.make");
    let mut contents = String::new();

    // Make sure libssh2 was detected on unix systems, because it definitely
    // should have been!
    if !msvc {
        t!(t!(File::open(flags)).read_to_string(&mut contents));
        if !contents.contains("-DGIT_SSH") {
            fail("libgit2 failed to find libssh2, and SSH support is required");
        }
    }

    run(Command::new("cmake")
                .arg("--build").arg(".")
                .arg("--target").arg("install")
                .arg("--config").arg(profile)
                .current_dir(&dst.join("build")), "cmake");

    println!("cargo:root={}", dst.display());
    if mingw || target.contains("windows") {
        println!("cargo:rustc-flags=-l winhttp -l rpcrt4 -l ole32 \
                                    -l static=git2");
        println!("cargo:rustc-link-search=native={}/lib", dst.display());
        return
    }

    if env::var("HOST") == env::var("TARGET") {
        prepend("PKG_CONFIG_PATH", dst.join("lib/pkgconfig"));
        if pkg_config::Config::new().statik(true).find("libgit2").is_ok() {
            return
        }
    }

    println!("cargo:rustc-flags=-l static=git2");
    println!("cargo:rustc-flags=-L {}", dst.join("lib").display());
    if target.contains("apple") {
        println!("cargo:rustc-flags=-l iconv");
    }
}

fn run(cmd: &mut Command, program: &str) {
    println!("running: {:?}", cmd);
    let status = match cmd.status() {
        Ok(status) => status,
        Err(ref e) if e.kind() == ErrorKind::NotFound => {
            fail(&format!("failed to execute command: {}\nis `{}` not installed?",
                          e, program));
        }
        Err(e) => fail(&format!("failed to execute command: {}", e)),
    };
    if !status.success() {
        fail(&format!("command did not execute successfully, got: {}", status));
    }
}

fn register_dep(dep: &str) {
    match env::var(&format!("DEP_{}_ROOT", dep)) {
        Ok(s) => {
            prepend("CMAKE_PREFIX_PATH", PathBuf::from(&s));
            prepend("PKG_CONFIG_PATH", Path::new(&s).join("lib/pkgconfig"));
        }
        Err(..) => {}
    }
}

fn prepend(var: &str, val: PathBuf) {
    let prefix = env::var(var).unwrap_or(String::new());
    let mut v = vec![val];
    v.extend(env::split_paths(&prefix));
    env::set_var(var, &env::join_paths(v).unwrap());
}

fn fail(s: &str) -> ! {
    panic!("\n{}\n\nbuild script failed, must exit now", s)
}
<|endoftext|>