<commit_before>#![allow(dead_code)]
#![allow(non_snake_case)]

extern crate libc;

#[link(name="libmesos")]
extern "C" {

    //////////////////////////////////////////////////////////////////
    // Scheduler driver methods
    //////////////////////////////////////////////////////////////////

    /// SchedulerDriverStatus scheduler_launchTasks() [int]
    ///   SchedulerDriverPtr driver [void *]
    ///   ProtobufObj * offerId [ProtobufObj *]
    ///   ProtobufObj * tasks [ProtobufObj *]
    ///   ProtobufObj * filters [ProtobufObj *]
    pub fn scheduler_launchTasks(
        driver: *mut libc::c_void,
        offerId: *mut ProtobufObj,
        tasks: *mut ProtobufObj,
        filters: *mut ProtobufObj) -> libc::c_int;

    /// SchedulerDriverStatus scheduler_start() [int]
    ///   SchedulerDriverPtr driver [void *]
    pub fn scheduler_start(driver: *mut libc::c_void) -> libc::c_int;

    /// SchedulerDriverStatus scheduler_stop() [int]
    ///   SchedulerDriverPtr driver [void *]
    ///   int failover
    pub fn scheduler_stop(
        driver: *mut libc::c_void,
        failover: libc::c_int) -> libc::c_int;

    /// SchedulerDriverStatus scheduler_abort() [int]
    ///   SchedulerDriverPtr driver [void *]
    pub fn scheduler_abort(driver: *mut libc::c_void) -> libc::c_int;

    /// SchedulerDriverStatus scheduler_join() [int]
    ///   SchedulerDriverPtr driver [void *]
    pub fn scheduler_join(driver: *mut libc::c_void) -> libc::c_int;

    /// SchedulerDriverStatus scheduler_run() [int]
    ///   SchedulerDriverPtr driver [void *]
    pub fn scheduler_run(driver: *mut libc::c_void) -> libc::c_int;

    /// SchedulerDriverStatus scheduler_requestResources() [int]
    ///   SchedulerDriverPtr driver [void *]
    ///   ProtobufObj * requestsData [ProtobufObj *]
    pub fn scheduler_requestResources(
        driver: *mut libc::c_void,
        requestsData: *mut ProtobufObj) -> libc::c_int;

    /// SchedulerDriverStatus scheduler_declineOffer() [int]
    ///   SchedulerDriverPtr driver [void *]
    ///   ProtobufObj * offerId [ProtobufObj *]
    ///   ProtobufObj * filters [ProtobufObj *]
    pub fn scheduler_declineOffer(
        driver: *mut libc::c_void,
        offerId: *mut ProtobufObj,
        filters: *mut ProtobufObj) -> libc::c_int;

    /// SchedulerDriverStatus scheduler_killTask() [int]
    ///   SchedulerDriverPtr driver [void *]
    ///   ProtobufObj * taskId [ProtobufObj *]
    pub fn scheduler_killTask(
        driver: *mut libc::c_void,
        taskId: *mut ProtobufObj) -> libc::c_int;

    /// SchedulerDriverStatus scheduler_reviveOffers() [int]
    ///   SchedulerDriverPtr driver [void *]
    pub fn scheduler_reviveOffers(driver: *mut libc::c_void) -> libc::c_int;

    /// SchedulerDriverStatus scheduler_sendFrameworkMessage() [int]
    ///   SchedulerDriverPtr driver [void *]
    ///   ProtobufObj * executor [ProtobufObj *]
    ///   ProtobufObj * slaveId [ProtobufObj *]
    ///   const char * data
    pub fn scheduler_sendFrameworkMessage(
        driver: *mut libc::c_void,
        executor: *mut ProtobufObj,
        slaveId: *mut ProtobufObj,
        data: *const libc::c_char) -> libc::c_int;

    /// SchedulerPtrPair scheduler_init() [SchedulerPtrPair]
    ///   SchedulerCallbacks * callbacks [SchedulerCallbacks *]
    ///   void * payload
    ///   ProtobufObj * framework [ProtobufObj *]
    ///   const char * master
    pub fn scheduler_init(
        callbacks: *mut SchedulerCallbacks,
        payload: *mut libc::c_void,
        framework: *mut ProtobufObj,
        master: *const libc::c_char) -> SchedulerPtrPair;

    /// void scheduler_destroy()
    ///   void * driver
    ///   void * scheduler
    pub fn scheduler_destroy(
        driver: *mut libc::c_void,
        scheduler: *mut libc::c_void);

    //////////////////////////////////////////////////////////////////
    // Executor driver methods
    //////////////////////////////////////////////////////////////////

    /// ExecutorDriverStatus executor_start() [int]
    ///   ExecutorDriverPtr driver [void *]
    pub fn executor_start(driver: *mut libc::c_void) -> libc::c_int;

    /// ExecutorDriverStatus executor_stop() [int]
    ///   ExecutorDriverPtr driver [void *]
    pub fn executor_stop(driver: *mut libc::c_void) -> libc::c_int;

    /// ExecutorDriverStatus executor_abort() [int]
    ///   ExecutorDriverPtr driver [void *]
    pub fn executor_abort(driver: *mut libc::c_void) -> libc::c_int;

    /// ExecutorDriverStatus executor_join() [int]
    ///   ExecutorDriverPtr driver [void *]
    pub fn executor_join(driver: *mut libc::c_void) -> libc::c_int;

    /// ExecutorDriverStatus executor_run() [int]
    ///   ExecutorDriverPtr driver [void *]
    pub fn executor_run(driver: *mut libc::c_void) -> libc::c_int;

    /// ExecutorDriverStatus executor_sendStatusUpdate() [int]
    ///   ExecutorDriverPtr driver [void *]
    ///   ProtobufObj * status [ProtobufObj *]
    pub fn executor_sendStatusUpdate(
        driver: *mut libc::c_void,
        status: *mut ProtobufObj) -> libc::c_int;

    /// ExecutorDriverStatus executor_sendFrameworkMessage() [int]
    ///   ExecutorDriverPtr driver [void *]
    ///   const char * data
    pub fn executor_sendFrameworkMessage(
        driver: *mut libc::c_void,
        data: *const libc::c_char) -> libc::c_int;

    /// ExecutorPtrPair executor_init() [ExecutorPtrPair]
    ///   ExecutorCallbacks * callbacks [ExecutorCallbacks *]
    ///   void * payload
    pub fn executor_init(
        callbacks: *mut ExecutorCallbacks,
        payload: *mut libc::c_void) -> ExecutorPtrPair;

    /// void executor_destroy()
    ///   void * driver
    ///   void * executor
    pub fn executor_destroy(
        driver: *mut libc::c_void,
        executor: *mut libc::c_void);

}

/*
   struct
   void * data
   size_t size
*/
#[repr(C)]
pub struct ProtobufObj {
    pub data: *mut libc::c_void,
    pub size: libc::size_t,
}

/*
   struct
   scheduler_registeredCallBack_t registeredCallBack [void (*)(void *, ProtobufObj *, ProtobufObj *)]
   scheduler_reregisteredCallBack_t reregisteredCallBack [void (*)(void *, ProtobufObj *)]
   scheduler_resourceOffersCallBack_t resourceOffersCallBack [void (*)(void *, ProtobufObj *, size_t)]
   scheduler_statusUpdateCallBack_t statusUpdateCallBack [void (*)(void *, ProtobufObj *)]
   scheduler_disconnectedCallBack_t disconnectedCallBack [void (*)(void *)]
   scheduler_offerRescindedCallBack_t offerRescindedCallBack [void (*)(void *, ProtobufObj *)]
   scheduler_frameworkMessageCallBack_t frameworkMessageCallBack [void (*)(void *, ProtobufObj *, ProtobufObj *, ProtobufObj *)]
   scheduler_slaveLostCallBack_t slaveLostCallBack [void (*)(void *, ProtobufObj *)]
   scheduler_executorLostCallBack_t executorLostCallBack [void (*)(void *, ProtobufObj *, ProtobufObj *, int)]
   scheduler_errorCallBack_t errorCallBack [void (*)(void *, ProtobufObj *)]
*/
#[repr(C)]
pub struct SchedulerCallbacks {
    registeredCallBack: extern fn(
        *mut libc::c_void,
        *mut ProtobufObj,
        *mut ProtobufObj),

    reregisteredCallBack: extern fn(
        *mut libc::c_void,
        *mut ProtobufObj),

    resourceOffersCallBack: extern fn(
        *mut libc::c_void,
        *mut ProtobufObj,
        libc::size_t),

    statusUpdateCallBack: extern fn(*mut libc::c_void, *mut ProtobufObj),

    disconnectedCallBack: extern fn(*mut libc::c_void),

    offerRescindedCallBack: extern fn(*mut libc::c_void, *mut ProtobufObj),

    frameworkMessageCallBack: extern fn(
        *mut libc::c_void,
        *mut ProtobufObj,
        *mut ProtobufObj,
        *mut ProtobufObj),

    slaveLostCallBack: extern fn(*mut libc::c_void, *mut ProtobufObj),

    executorLostCallBack: extern fn(
        *mut libc::c_void,
        *mut ProtobufObj,
        *mut ProtobufObj,
        libc::c_int),

    errorCallBack: extern fn(*mut libc::c_void, *mut ProtobufObj),
}

/*
   struct
   void * scheduler
   void * driver
*/
#[repr(C)]
pub struct SchedulerPtrPair {
    scheduler: libc::c_void,
    driver: libc::c_void,
}

/*
   struct
   executor_registeredCallBack_t registeredCallBack [void (*)(void *, ProtobufObj *, ProtobufObj *, ProtobufObj *)]
   executor_reregisteredCallBack_t reregisteredCallBack [void (*)(void *, ProtobufObj *)]
   executor_disconnectedCallBack_t disconnectedCallBack [void (*)(void *)]
   executor_launchTaskCallBack_t launchTaskCallBack [void (*)(void *, ProtobufObj *)]
   executor_killTaskCallBack_t killTaskCallBack [void (*)(void *, ProtobufObj *)]
   executor_frameworkMessageCallBack_t frameworkMessageCallBack [void (*)(void *, ProtobufObj *)]
   executor_shutdownCallBack_t shutdownCallBack [void (*)(void *)]
   executor_errorCallBack_t errorCallBack [void (*)(void *, ProtobufObj *)]
*/
#[repr(C)]
pub struct ExecutorCallbacks {

    registeredCallBack: extern fn(
        *mut libc::c_void,
        *mut ProtobufObj,
        *mut ProtobufObj,
        *mut ProtobufObj),

    reregisteredCallBack: extern fn(*mut libc::c_void, *mut ProtobufObj),

    disconnectedCallBack: extern fn(*mut libc::c_void),

    launchTaskCallBack: extern fn(*mut libc::c_void, *mut ProtobufObj),

    killTaskCallBack: extern fn(*mut libc::c_void, *mut ProtobufObj),

    frameworkMessageCallBack: extern fn(*mut libc::c_void, *mut ProtobufObj),

    shutdownCallBack: extern fn(*mut libc::c_void),

    errorCallBack: extern fn(*mut libc::c_void, *mut ProtobufObj),
}

/*
   struct
   void * executor
   void * driver
*/
#[repr(C)]
pub struct ExecutorPtrPair {
    executor: libc::c_void,
    driver: libc::c_void,
}

<commit_msg>Using link attribute wihtout lib- prefix<commit_after>#![allow(dead_code)]
#![allow(non_snake_case)]

extern crate libc;

#[link(name="mesos")]
extern "C" {

    //////////////////////////////////////////////////////////////////
    // Scheduler driver methods
    //////////////////////////////////////////////////////////////////

    /// SchedulerDriverStatus scheduler_launchTasks() [int]
    ///   SchedulerDriverPtr driver [void *]
    ///   ProtobufObj * offerId [ProtobufObj *]
    ///   ProtobufObj * tasks [ProtobufObj *]
    ///   ProtobufObj * filters [ProtobufObj *]
    pub fn scheduler_launchTasks(
        driver: *mut libc::c_void,
        offerId: *mut ProtobufObj,
        tasks: *mut ProtobufObj,
        filters: *mut ProtobufObj) -> libc::c_int;

    /// SchedulerDriverStatus scheduler_start() [int]
    ///   SchedulerDriverPtr driver [void *]
    pub fn scheduler_start(driver: *mut libc::c_void) -> libc::c_int;

    /// SchedulerDriverStatus scheduler_stop() [int]
    ///   SchedulerDriverPtr driver [void *]
    ///   int failover
    pub fn scheduler_stop(
        driver: *mut libc::c_void,
        failover: libc::c_int) -> libc::c_int;

    /// SchedulerDriverStatus scheduler_abort() [int]
    ///   SchedulerDriverPtr driver [void *]
    pub fn scheduler_abort(driver: *mut libc::c_void) -> libc::c_int;

    /// SchedulerDriverStatus scheduler_join() [int]
    ///   SchedulerDriverPtr driver [void *]
    pub fn scheduler_join(driver: *mut libc::c_void) -> libc::c_int;

    /// SchedulerDriverStatus scheduler_run() [int]
    ///   SchedulerDriverPtr driver [void *]
    pub fn scheduler_run(driver: *mut libc::c_void) -> libc::c_int;

    /// SchedulerDriverStatus scheduler_requestResources() [int]
    ///   SchedulerDriverPtr driver [void *]
    ///   ProtobufObj * requestsData [ProtobufObj *]
    pub fn scheduler_requestResources(
        driver: *mut libc::c_void,
        requestsData: *mut ProtobufObj) -> libc::c_int;

    /// SchedulerDriverStatus scheduler_declineOffer() [int]
    ///   SchedulerDriverPtr driver [void *]
    ///   ProtobufObj * offerId [ProtobufObj *]
    ///   ProtobufObj * filters [ProtobufObj *]
    pub fn scheduler_declineOffer(
        driver: *mut libc::c_void,
        offerId: *mut ProtobufObj,
        filters: *mut ProtobufObj) -> libc::c_int;

    /// SchedulerDriverStatus scheduler_killTask() [int]
    ///   SchedulerDriverPtr driver [void *]
    ///   ProtobufObj * taskId [ProtobufObj *]
    pub fn scheduler_killTask(
        driver: *mut libc::c_void,
        taskId: *mut ProtobufObj) -> libc::c_int;

    /// SchedulerDriverStatus scheduler_reviveOffers() [int]
    ///   SchedulerDriverPtr driver [void *]
    pub fn scheduler_reviveOffers(driver: *mut libc::c_void) -> libc::c_int;

    /// SchedulerDriverStatus scheduler_sendFrameworkMessage() [int]
    ///   SchedulerDriverPtr driver [void *]
    ///   ProtobufObj * executor [ProtobufObj *]
    ///   ProtobufObj * slaveId [ProtobufObj *]
    ///   const char * data
    pub fn scheduler_sendFrameworkMessage(
        driver: *mut libc::c_void,
        executor: *mut ProtobufObj,
        slaveId: *mut ProtobufObj,
        data: *const libc::c_char) -> libc::c_int;

    /// SchedulerPtrPair scheduler_init() [SchedulerPtrPair]
    ///   SchedulerCallbacks * callbacks [SchedulerCallbacks *]
    ///   void * payload
    ///   ProtobufObj * framework [ProtobufObj *]
    ///   const char * master
    pub fn scheduler_init(
        callbacks: *mut SchedulerCallbacks,
        payload: *mut libc::c_void,
        framework: *mut ProtobufObj,
        master: *const libc::c_char) -> SchedulerPtrPair;

    /// void scheduler_destroy()
    ///   void * driver
    ///   void * scheduler
    pub fn scheduler_destroy(
        driver: *mut libc::c_void,
        scheduler: *mut libc::c_void);

    //////////////////////////////////////////////////////////////////
    // Executor driver methods
    //////////////////////////////////////////////////////////////////

    /// ExecutorDriverStatus executor_start() [int]
    ///   ExecutorDriverPtr driver [void *]
    pub fn executor_start(driver: *mut libc::c_void) -> libc::c_int;

    /// ExecutorDriverStatus executor_stop() [int]
    ///   ExecutorDriverPtr driver [void *]
    pub fn executor_stop(driver: *mut libc::c_void) -> libc::c_int;

    /// ExecutorDriverStatus executor_abort() [int]
    ///   ExecutorDriverPtr driver [void *]
    pub fn executor_abort(driver: *mut libc::c_void) -> libc::c_int;

    /// ExecutorDriverStatus executor_join() [int]
    ///   ExecutorDriverPtr driver [void *]
    pub fn executor_join(driver: *mut libc::c_void) -> libc::c_int;

    /// ExecutorDriverStatus executor_run() [int]
    ///   ExecutorDriverPtr driver [void *]
    pub fn executor_run(driver: *mut libc::c_void) -> libc::c_int;

    /// ExecutorDriverStatus executor_sendStatusUpdate() [int]
    ///   ExecutorDriverPtr driver [void *]
    ///   ProtobufObj * status [ProtobufObj *]
    pub fn executor_sendStatusUpdate(
        driver: *mut libc::c_void,
        status: *mut ProtobufObj) -> libc::c_int;

    /// ExecutorDriverStatus executor_sendFrameworkMessage() [int]
    ///   ExecutorDriverPtr driver [void *]
    ///   const char * data
    pub fn executor_sendFrameworkMessage(
        driver: *mut libc::c_void,
        data: *const libc::c_char) -> libc::c_int;

    /// ExecutorPtrPair executor_init() [ExecutorPtrPair]
    ///   ExecutorCallbacks * callbacks [ExecutorCallbacks *]
    ///   void * payload
    pub fn executor_init(
        callbacks: *mut ExecutorCallbacks,
        payload: *mut libc::c_void) -> ExecutorPtrPair;

    /// void executor_destroy()
    ///   void * driver
    ///   void * executor
    pub fn executor_destroy(
        driver: *mut libc::c_void,
        executor: *mut libc::c_void);

}

/*
   struct
   void * data
   size_t size
*/
#[repr(C)]
pub struct ProtobufObj {
    pub data: *mut libc::c_void,
    pub size: libc::size_t,
}

/*
   struct
   scheduler_registeredCallBack_t registeredCallBack [void (*)(void *, ProtobufObj *, ProtobufObj *)]
   scheduler_reregisteredCallBack_t reregisteredCallBack [void (*)(void *, ProtobufObj *)]
   scheduler_resourceOffersCallBack_t resourceOffersCallBack [void (*)(void *, ProtobufObj *, size_t)]
   scheduler_statusUpdateCallBack_t statusUpdateCallBack [void (*)(void *, ProtobufObj *)]
   scheduler_disconnectedCallBack_t disconnectedCallBack [void (*)(void *)]
   scheduler_offerRescindedCallBack_t offerRescindedCallBack [void (*)(void *, ProtobufObj *)]
   scheduler_frameworkMessageCallBack_t frameworkMessageCallBack [void (*)(void *, ProtobufObj *, ProtobufObj *, ProtobufObj *)]
   scheduler_slaveLostCallBack_t slaveLostCallBack [void (*)(void *, ProtobufObj *)]
   scheduler_executorLostCallBack_t executorLostCallBack [void (*)(void *, ProtobufObj *, ProtobufObj *, int)]
   scheduler_errorCallBack_t errorCallBack [void (*)(void *, ProtobufObj *)]
*/
#[repr(C)]
pub struct SchedulerCallbacks {
    registeredCallBack: extern fn(
        *mut libc::c_void,
        *mut ProtobufObj,
        *mut ProtobufObj),

    reregisteredCallBack: extern fn(
        *mut libc::c_void,
        *mut ProtobufObj),

    resourceOffersCallBack: extern fn(
        *mut libc::c_void,
        *mut ProtobufObj,
        libc::size_t),

    statusUpdateCallBack: extern fn(*mut libc::c_void, *mut ProtobufObj),

    disconnectedCallBack: extern fn(*mut libc::c_void),

    offerRescindedCallBack: extern fn(*mut libc::c_void, *mut ProtobufObj),

    frameworkMessageCallBack: extern fn(
        *mut libc::c_void,
        *mut ProtobufObj,
        *mut ProtobufObj,
        *mut ProtobufObj),

    slaveLostCallBack: extern fn(*mut libc::c_void, *mut ProtobufObj),

    executorLostCallBack: extern fn(
        *mut libc::c_void,
        *mut ProtobufObj,
        *mut ProtobufObj,
        libc::c_int),

    errorCallBack: extern fn(*mut libc::c_void, *mut ProtobufObj),
}

/*
   struct
   void * scheduler
   void * driver
*/
#[repr(C)]
pub struct SchedulerPtrPair {
    scheduler: libc::c_void,
    driver: libc::c_void,
}

/*
   struct
   executor_registeredCallBack_t registeredCallBack [void (*)(void *, ProtobufObj *, ProtobufObj *, ProtobufObj *)]
   executor_reregisteredCallBack_t reregisteredCallBack [void (*)(void *, ProtobufObj *)]
   executor_disconnectedCallBack_t disconnectedCallBack [void (*)(void *)]
   executor_launchTaskCallBack_t launchTaskCallBack [void (*)(void *, ProtobufObj *)]
   executor_killTaskCallBack_t killTaskCallBack [void (*)(void *, ProtobufObj *)]
   executor_frameworkMessageCallBack_t frameworkMessageCallBack [void (*)(void *, ProtobufObj *)]
   executor_shutdownCallBack_t shutdownCallBack [void (*)(void *)]
   executor_errorCallBack_t errorCallBack [void (*)(void *, ProtobufObj *)]
*/
#[repr(C)]
pub struct ExecutorCallbacks {

    registeredCallBack: extern fn(
        *mut libc::c_void,
        *mut ProtobufObj,
        *mut ProtobufObj,
        *mut ProtobufObj),

    reregisteredCallBack: extern fn(*mut libc::c_void, *mut ProtobufObj),

    disconnectedCallBack: extern fn(*mut libc::c_void),

    launchTaskCallBack: extern fn(*mut libc::c_void, *mut ProtobufObj),

    killTaskCallBack: extern fn(*mut libc::c_void, *mut ProtobufObj),

    frameworkMessageCallBack: extern fn(*mut libc::c_void, *mut ProtobufObj),

    shutdownCallBack: extern fn(*mut libc::c_void),

    errorCallBack: extern fn(*mut libc::c_void, *mut ProtobufObj),
}

/*
   struct
   void * executor
   void * driver
*/
#[repr(C)]
pub struct ExecutorPtrPair {
    executor: libc::c_void,
    driver: libc::c_void,
}

<|endoftext|>


<commit_before>//! Operator norm

use ndarray::*;

use super::error::*;
use super::layout::*;
use super::types::*;

pub use lapack_traits::NormType;

pub trait OperationNorm {
    type Output;
    fn opnorm(&self, t: NormType) -> Self::Output;
    fn opnorm_one(&self) -> Self::Output {
        self.opnorm(NormType::One)
    }
    fn opnorm_inf(&self) -> Self::Output {
        self.opnorm(NormType::Infinity)
    }
    fn opnorm_fro(&self) -> Self::Output {
        self.opnorm(NormType::Frobenius)
    }
}

impl<A, S> OperationNorm for ArrayBase<S, Ix2>
where
    A: Scalar,
    S: Data<Elem = A>,
{
    type Output = Result<A::Real>;

    fn opnorm(&self, t: NormType) -> Self::Output {
        let l = self.layout()?;
        let a = self.as_allocated()?;
        Ok(A::opnorm(t, l, a))
    }
}
<commit_msg>Cleanup OperatorNorm<commit_after>//! Operator norm

use ndarray::*;

use super::error::*;
use super::layout::*;
use super::types::*;

pub use lapack_traits::NormType;

/// Operator norm using `*lange` LAPACK routines
///
/// https://en.wikipedia.org/wiki/Operator_norm
pub trait OperationNorm {
    /// the value of norm
    type Output: RealScalar;

    fn opnorm(&self, t: NormType) -> Result<Self::Output>;

    /// the one norm of a matrix (maximum column sum)
    fn opnorm_one(&self) -> Result<Self::Output> {
        self.opnorm(NormType::One)
    }

    /// the infinity norm of a matrix (maximum row sum)
    fn opnorm_inf(&self) -> Result<Self::Output> {
        self.opnorm(NormType::Infinity)
    }

    /// the Frobenius norm of a matrix (square root of sum of squares)
    fn opnorm_fro(&self) -> Result<Self::Output> {
        self.opnorm(NormType::Frobenius)
    }
}

impl<A, S> OperationNorm for ArrayBase<S, Ix2>
where
    A: Scalar,
    S: Data<Elem = A>,
{
    type Output = A::Real;

    fn opnorm(&self, t: NormType) -> Result<Self::Output> {
        let l = self.layout()?;
        let a = self.as_allocated()?;
        Ok(A::opnorm(t, l, a))
    }
}
<|endoftext|>


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

use std::str::CowString;
use super::{Token, NumericValue, Tokenizer, SourcePosition, SourceLocation};

pub struct Parser<'i: 't, 't> {
    tokenizer: &'t mut Tokenizer<'i>,
    parent_state: Option<&'t mut ParserState>,
    state: ParserState,
}

struct ParserState {
    nested_blocks: NestedBlockList,
    /// For block/function parsers that need to stop at the matching `)`, `]`, or `}`
    at_start_of: Option<BlockType>,
    /// For block/function parsers that need to stop at the matching `)`, `]`, or `}`
    stop_at_end_of: Option<BlockType>,
    /// For parsers from `parse_until`
    stop_before: Delimiters,
    exhausted: bool,
}

#[deriving(Copy, PartialEq, Eq, Show)]
enum BlockType {
    Parenthesis,
    SquareBracket,
    CurlyBracket,
}

impl BlockType {
    fn opening(token: &Token) -> Option<BlockType> {
        match *token {
            Token::Function(_) |
            Token::ParenthesisBlock => Some(BlockType::Parenthesis),
            Token::SquareBracketBlock => Some(BlockType::SquareBracket),
            Token::CurlyBracketBlock => Some(BlockType::CurlyBracket),
            _ => None
        }
    }

    fn closing(token: &Token) -> Option<BlockType> {
        match *token {
            Token::CloseParenthesis => Some(BlockType::Parenthesis),
            Token::CloseSquareBracket => Some(BlockType::SquareBracket),
            Token::CloseCurlyBracket => Some(BlockType::CurlyBracket),
            _ => None
        }
    }
}

type NestedBlockList = Option<Box<NestedBlockListItem>>;

struct NestedBlockListItem {
    next: NestedBlockList,
    block_type: BlockType,
}

trait NestedBlockListExt {
    fn push(&mut self, block_type: BlockType);
    fn consume(self, tokenizer: &mut Tokenizer) -> bool;
}

impl NestedBlockListExt for NestedBlockList {
    fn push(&mut self, block_type: BlockType) {
        debug_assert!(self.is_none());
        *self = Some(box NestedBlockListItem {
            next: self.take(),
            block_type: block_type,
        })
    }

    /// Return value indicates whether the end of the input was reached.
    fn consume(self, tokenizer: &mut Tokenizer) -> bool {
        if let Some(box NestedBlockListItem { block_type, next }) = self {
            // Recursion first: the inner-most item of the list
            // is for the inner-most nested block.
            next.consume(tokenizer) || consume_until_end_of_block(block_type, tokenizer)
        } else {
            false
        }
    }
}

#[unsafe_destructor] // FIXME What does this mean?
impl<'i, 't> Drop for Parser<'i, 't> {
    fn drop(&mut self) {
        if self.state.exhausted {
            // We’ve already reached the end of our delimited input:
            // nothing to inform the parent of.
            debug_assert!(self.state.nested_blocks.is_none());
            return
        }
        if let Some(parent_state) = self.parent_state.take() {
            // Inform our parent parser of what they need to consume.
            debug_assert!(parent_state.nested_blocks.is_none());
            parent_state.nested_blocks = self.state.nested_blocks.take();
            if let Some(block_type) = self.state.at_start_of {
                parent_state.nested_blocks.push(block_type)
            }
            // Don’t propagate stop_at_end_of back for delimited parsers:
            if self.state.stop_before.is_none() {
                debug_assert!(parent_state.at_start_of.is_none());
                parent_state.at_start_of = self.state.stop_at_end_of;
            }
        }
    }
}

#[deriving(Copy, PartialEq, Eq, Show)]
pub struct Delimiters {
    bits: u8,
}

#[allow(non_upper_case_globals, non_snake_case)]
pub mod Delimiter {
    use super::Delimiters;

    pub const None: Delimiters = Delimiters { bits: 0 };
    /// `{`
    pub const CurlyBracketBlock: Delimiters = Delimiters { bits: 1 << 1 };
    /// `;`
    pub const Semicolon: Delimiters = Delimiters { bits: 1 << 2 };
    /// `!`
    pub const Bang: Delimiters = Delimiters { bits: 1 << 3 };
    /// `,`
    pub const Comma: Delimiters = Delimiters { bits: 1 << 4 };
}

impl BitOr<Delimiters, Delimiters> for Delimiters {
    fn bitor(&self, other: &Delimiters) -> Delimiters {
        Delimiters { bits: self.bits | other.bits }
    }
}

impl Delimiters {
    fn contains(&self, other: Delimiters) -> bool {
        (self.bits & other.bits) != 0
    }

    fn is_none(&self) -> bool {
        self.bits == 0
    }

    fn from_token(token: &Token) -> Delimiters {
        match *token {
            Token::Semicolon => Delimiter::Semicolon,
            Token::Comma  => Delimiter::Comma,
            Token::Delim('!') => Delimiter::Bang,
            Token::CurlyBracketBlock => Delimiter::CurlyBracketBlock,
            _ => Delimiter::None,
        }
    }
}

impl<'i, 't> Parser<'i, 't> {
    #[inline]
    pub fn new(tokenizer: &'t mut Tokenizer<'i>) -> Parser<'i, 't> {
        Parser {
            tokenizer: tokenizer,
            parent_state: None,
            state: ParserState {
                nested_blocks: None,
                at_start_of: None,
                stop_at_end_of: None,
                stop_before: Delimiter::None,
                exhausted: false,
            },
        }
    }

    #[inline]
    pub fn parse_str<T>(input: &str, parse: |&mut Parser| -> T) -> T {
        parse(&mut Parser::new(&mut Tokenizer::new(input.as_slice())))
    }

    #[inline]
    pub fn is_exhausted(&mut self) -> bool {
        self.peek().is_err()
    }

    #[inline]
    pub fn expect_exhausted(&mut self) -> Result<(), ()> {
        if self.is_exhausted() {
            Ok(())
        } else {
            Err(())
        }
    }

    #[inline]
    pub fn peek(&mut self) -> Result<&Token<'i>, ()> {
        // Consume whatever needs to be consumed (e.g. open blocks).
        let token = try!(self.next());
        self.push_back(token);

        self.tokenizer.peek()
    }

    #[inline]
    pub fn push_back(&mut self, token: Token<'i>) {
        if BlockType::opening(&token) == self.state.at_start_of {
            self.state.at_start_of = None;
        }
        self.tokenizer.push_back(token)
    }

    #[inline]
    pub fn push_back_result(&mut self, token_result: Result<Token<'i>, ()>) {
        if let Ok(token) = token_result {
            self.push_back(token)
        }
    }

    #[inline]
    pub fn unexpected<T>(&mut self, token: Token<'i>) -> Result<T, ()> {
        self.push_back(token);
        Err(())
    }

    #[inline]
    pub fn position(&self) -> SourcePosition {
        self.tokenizer.position()
    }

    #[inline]
    pub fn slice_from(&self, start_pos: SourcePosition) -> &'i str {
        self.tokenizer.slice_from(start_pos)
    }

    #[inline]
    pub fn current_source_location(&mut self) -> SourceLocation {
        self.tokenizer.current_source_location()
    }

    #[inline]
    pub fn source_location(&mut self, target: SourcePosition) -> SourceLocation {
        self.tokenizer.source_location(target)
    }

    pub fn next(&mut self) -> Result<Token<'i>, ()> {
        loop {
            match self.next_including_whitespace() {
                Ok(Token::WhiteSpace) => {},
                result => return result
            }
        }
    }

    pub fn next_including_whitespace(&mut self) -> Result<Token<'i>, ()> {
        if self.state.exhausted {
            return Err(())
        }
        if self.state.nested_blocks.take().consume(self.tokenizer) {
            self.state.exhausted = true;
            return Err(())
        }
        if let Some(block_type) = self.state.at_start_of.take() {
            if consume_until_end_of_block(block_type, self.tokenizer) {
                self.state.exhausted = true;
                return Err(())
            }
        }
        match self.tokenizer.next() {
            Err(()) => {
                self.state.exhausted = true;
                Err(())
            },
            Ok(token) => {
                if self.state.stop_before.contains(Delimiters::from_token(&token)) {
                    self.tokenizer.push_back(token);
                    self.state.exhausted = true;
                    return Err(())
                }
                if self.state.stop_at_end_of.is_some() &&
                        BlockType::closing(&token) == self.state.stop_at_end_of {
                    self.state.exhausted = true;
                    return Err(())
                }
                if let Some(block_type) = BlockType::opening(&token) {
                    self.state.at_start_of = Some(block_type);
                }
                Ok(token)
            }
        }
    }

    #[inline]
    pub fn err_consume_until_after<T>(&mut self, stop_after: Delimiters) -> Result<T, ()> {
        self.consume_until_after(stop_after);
        Err(())
    }

    pub fn consume_until_after(&mut self, stop_after: Delimiters) {
        if self.state.exhausted {
            return
        }
        // FIXME: have a special-purpose tokenizer method for this that does less work.
        while let Ok(token) = self.tokenizer.next() {
            if stop_after.contains(Delimiters::from_token(&token)) {
                return
            }
            if self.state.stop_before.contains(Delimiters::from_token(&token)) {
                self.tokenizer.push_back(token);
                self.state.exhausted = true;
                return
            }
            if self.state.stop_at_end_of.is_some() &&
                    BlockType::closing(&token) == self.state.stop_at_end_of {
                self.state.exhausted = true;
                return
            }
            if let Some(block_type) = BlockType::opening(&token) {
                if consume_until_end_of_block(block_type, self.tokenizer) {
                    self.state.exhausted = true;
                    return
                }
            }
        }
        self.state.exhausted = true;
    }

    // FIXME: Take an unboxed `FnOnce` closure.
    #[inline]
    pub fn parse_entirely<T>(&mut self, parse: |&mut Parser| -> Result<T, ()>)
                             -> Result<T, ()> {
        let result = parse(self);
        try!(self.expect_exhausted());
        result
    }

    #[inline]
    pub fn parse_nested_block<'a>(&'a mut self) -> Parser<'i, 'a> {
        if let Some(block_type) = self.state.at_start_of.take() {
            debug_assert!(!self.state.exhausted);
            Parser {
                tokenizer: self.tokenizer,
                state: ParserState {
                    nested_blocks: self.state.nested_blocks.take(),
                    at_start_of: None,
                    stop_at_end_of: Some(block_type),
                    stop_before: Delimiter::None,
                    exhausted: false,
                },
                parent_state: Some(&mut self.state),
            }
        } else {
            panic!("\
                parse_block can only be called when a Function, \
                ParenthesisBlock, SquareBracketBlock, or CurlyBracketBlock \
                token was just consumed.\
            ");
        }
    }

    #[inline]
    pub fn parse_until_before<'a>(&'a mut self, stop_before: Delimiters) -> Parser<'i, 'a> {
        if self.state.stop_before != Delimiter::None {
            panic!("`parse_until_before` cannot be used on a `Parser` \
                    that is itself from `parse_until_before`")
        }
        Parser {
            tokenizer: self.tokenizer,
            state: ParserState {
                nested_blocks: self.state.nested_blocks.take(),
                at_start_of: self.state.at_start_of.take(),
                stop_at_end_of: self.state.stop_at_end_of,
                stop_before: stop_before,
                exhausted: self.state.exhausted,
            },
            parent_state: Some(&mut self.state),
        }
    }

    #[inline]
    pub fn expect_ident(&mut self) -> Result<CowString<'i>, ()> {
        match try!(self.next()) {
            Token::Ident(value) => Ok(value),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_quoted_string(&mut self) -> Result<CowString<'i>, ()> {
        match try!(self.next()) {
            Token::QuotedString(value) => Ok(value),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_url(&mut self) -> Result<CowString<'i>, ()> {
        match try!(self.next()) {
            Token::Url(value) => Ok(value),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_url_or_string(&mut self) -> Result<CowString<'i>, ()> {
        match try!(self.next()) {
            Token::Url(value) => Ok(value),
            Token::QuotedString(value) => Ok(value),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_number(&mut self) -> Result<f64, ()> {
        match try!(self.next()) {
            Token::Number(NumericValue { value, .. }) => Ok(value),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_integer(&mut self) -> Result<i64, ()> {
        match try!(self.next()) {
            Token::Number(NumericValue { int_value, .. }) => int_value.ok_or(()),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_percentage(&mut self) -> Result<f64, ()> {
        match try!(self.next()) {
            Token::Percentage(NumericValue { value, .. }) => Ok(value),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_colon(&mut self) -> Result<(), ()> {
        match try!(self.next()) {
            Token::Colon => Ok(()),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_semicolon(&mut self) -> Result<(), ()> {
        match try!(self.next()) {
            Token::Semicolon => Ok(()),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_comma(&mut self) -> Result<(), ()> {
        match try!(self.next()) {
            Token::Comma => Ok(()),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_curly_bracke_block(&mut self) -> Result<(), ()> {
        match try!(self.next()) {
            Token::CurlyBracketBlock => Ok(()),
            token => self.unexpected(token)
        }
    }
}

/// Return value indicates whether the end of the input was reached.
fn consume_until_end_of_block(block_type: BlockType, tokenizer: &mut Tokenizer) -> bool {
    // FIXME: have a special-purpose tokenizer method for this that does less work.
    while let Ok(ref token) = tokenizer.next() {
        if BlockType::closing(token) == Some(block_type) {
            return false
        }
        if let Some(block_type) = BlockType::opening(token) {
            if consume_until_end_of_block(block_type, tokenizer) {
                return true
            }
        }
    }
    true
}
<commit_msg>Allow parse_until_before to be reentrant<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::str::CowString;
use super::{Token, NumericValue, Tokenizer, SourcePosition, SourceLocation};

pub struct Parser<'i: 't, 't> {
    tokenizer: &'t mut Tokenizer<'i>,
    parent_state: Option<&'t mut ParserState>,
    state: ParserState,
}

struct ParserState {
    nested_blocks: NestedBlockList,
    /// For block/function parsers that need to stop at the matching `)`, `]`, or `}`
    at_start_of: Option<BlockType>,
    /// For block/function parsers that need to stop at the matching `)`, `]`, or `}`
    stop_at_end_of: Option<BlockType>,
    /// For parsers from `parse_until`
    stop_before: Delimiters,
    exhausted: bool,
}

#[deriving(Copy, PartialEq, Eq, Show)]
enum BlockType {
    Parenthesis,
    SquareBracket,
    CurlyBracket,
}

impl BlockType {
    fn opening(token: &Token) -> Option<BlockType> {
        match *token {
            Token::Function(_) |
            Token::ParenthesisBlock => Some(BlockType::Parenthesis),
            Token::SquareBracketBlock => Some(BlockType::SquareBracket),
            Token::CurlyBracketBlock => Some(BlockType::CurlyBracket),
            _ => None
        }
    }

    fn closing(token: &Token) -> Option<BlockType> {
        match *token {
            Token::CloseParenthesis => Some(BlockType::Parenthesis),
            Token::CloseSquareBracket => Some(BlockType::SquareBracket),
            Token::CloseCurlyBracket => Some(BlockType::CurlyBracket),
            _ => None
        }
    }
}

type NestedBlockList = Option<Box<NestedBlockListItem>>;

struct NestedBlockListItem {
    next: NestedBlockList,
    block_type: BlockType,
}

trait NestedBlockListExt {
    fn push(&mut self, block_type: BlockType);
    fn consume(self, tokenizer: &mut Tokenizer) -> bool;
}

impl NestedBlockListExt for NestedBlockList {
    fn push(&mut self, block_type: BlockType) {
        debug_assert!(self.is_none());
        *self = Some(box NestedBlockListItem {
            next: self.take(),
            block_type: block_type,
        })
    }

    /// Return value indicates whether the end of the input was reached.
    fn consume(self, tokenizer: &mut Tokenizer) -> bool {
        if let Some(box NestedBlockListItem { block_type, next }) = self {
            // Recursion first: the inner-most item of the list
            // is for the inner-most nested block.
            next.consume(tokenizer) || consume_until_end_of_block(block_type, tokenizer)
        } else {
            false
        }
    }
}

#[unsafe_destructor] // FIXME What does this mean?
impl<'i, 't> Drop for Parser<'i, 't> {
    fn drop(&mut self) {
        if self.state.exhausted {
            // We’ve already reached the end of our delimited input:
            // nothing to inform the parent of.
            debug_assert!(self.state.nested_blocks.is_none());
            return
        }
        if let Some(parent_state) = self.parent_state.take() {
            // Inform our parent parser of what they need to consume.
            debug_assert!(parent_state.nested_blocks.is_none());
            parent_state.nested_blocks = self.state.nested_blocks.take();
            if let Some(block_type) = self.state.at_start_of {
                parent_state.nested_blocks.push(block_type)
            }
            // Don’t propagate stop_at_end_of back for delimited parsers:
            if self.state.stop_before.is_none() {
                debug_assert!(parent_state.at_start_of.is_none());
                parent_state.at_start_of = self.state.stop_at_end_of;
            }
        }
    }
}

#[deriving(Copy, PartialEq, Eq, Show)]
pub struct Delimiters {
    bits: u8,
}

#[allow(non_upper_case_globals, non_snake_case)]
pub mod Delimiter {
    use super::Delimiters;

    pub const None: Delimiters = Delimiters { bits: 0 };
    /// `{`
    pub const CurlyBracketBlock: Delimiters = Delimiters { bits: 1 << 1 };
    /// `;`
    pub const Semicolon: Delimiters = Delimiters { bits: 1 << 2 };
    /// `!`
    pub const Bang: Delimiters = Delimiters { bits: 1 << 3 };
    /// `,`
    pub const Comma: Delimiters = Delimiters { bits: 1 << 4 };
}

impl BitOr<Delimiters, Delimiters> for Delimiters {
    fn bitor(&self, other: &Delimiters) -> Delimiters {
        Delimiters { bits: self.bits | other.bits }
    }
}

impl Delimiters {
    fn contains(&self, other: Delimiters) -> bool {
        (self.bits & other.bits) != 0
    }

    fn is_none(&self) -> bool {
        self.bits == 0
    }

    fn from_token(token: &Token) -> Delimiters {
        match *token {
            Token::Semicolon => Delimiter::Semicolon,
            Token::Comma  => Delimiter::Comma,
            Token::Delim('!') => Delimiter::Bang,
            Token::CurlyBracketBlock => Delimiter::CurlyBracketBlock,
            _ => Delimiter::None,
        }
    }
}

impl<'i, 't> Parser<'i, 't> {
    #[inline]
    pub fn new(tokenizer: &'t mut Tokenizer<'i>) -> Parser<'i, 't> {
        Parser {
            tokenizer: tokenizer,
            parent_state: None,
            state: ParserState {
                nested_blocks: None,
                at_start_of: None,
                stop_at_end_of: None,
                stop_before: Delimiter::None,
                exhausted: false,
            },
        }
    }

    #[inline]
    pub fn parse_str<T>(input: &str, parse: |&mut Parser| -> T) -> T {
        parse(&mut Parser::new(&mut Tokenizer::new(input.as_slice())))
    }

    #[inline]
    pub fn is_exhausted(&mut self) -> bool {
        self.peek().is_err()
    }

    #[inline]
    pub fn expect_exhausted(&mut self) -> Result<(), ()> {
        if self.is_exhausted() {
            Ok(())
        } else {
            Err(())
        }
    }

    #[inline]
    pub fn peek(&mut self) -> Result<&Token<'i>, ()> {
        // Consume whatever needs to be consumed (e.g. open blocks).
        let token = try!(self.next());
        self.push_back(token);

        self.tokenizer.peek()
    }

    #[inline]
    pub fn push_back(&mut self, token: Token<'i>) {
        if BlockType::opening(&token) == self.state.at_start_of {
            self.state.at_start_of = None;
        }
        self.tokenizer.push_back(token)
    }

    #[inline]
    pub fn push_back_result(&mut self, token_result: Result<Token<'i>, ()>) {
        if let Ok(token) = token_result {
            self.push_back(token)
        }
    }

    #[inline]
    pub fn unexpected<T>(&mut self, token: Token<'i>) -> Result<T, ()> {
        self.push_back(token);
        Err(())
    }

    #[inline]
    pub fn position(&self) -> SourcePosition {
        self.tokenizer.position()
    }

    #[inline]
    pub fn slice_from(&self, start_pos: SourcePosition) -> &'i str {
        self.tokenizer.slice_from(start_pos)
    }

    #[inline]
    pub fn current_source_location(&mut self) -> SourceLocation {
        self.tokenizer.current_source_location()
    }

    #[inline]
    pub fn source_location(&mut self, target: SourcePosition) -> SourceLocation {
        self.tokenizer.source_location(target)
    }

    pub fn next(&mut self) -> Result<Token<'i>, ()> {
        loop {
            match self.next_including_whitespace() {
                Ok(Token::WhiteSpace) => {},
                result => return result
            }
        }
    }

    pub fn next_including_whitespace(&mut self) -> Result<Token<'i>, ()> {
        if self.state.exhausted {
            return Err(())
        }
        if self.state.nested_blocks.take().consume(self.tokenizer) {
            self.state.exhausted = true;
            return Err(())
        }
        if let Some(block_type) = self.state.at_start_of.take() {
            if consume_until_end_of_block(block_type, self.tokenizer) {
                self.state.exhausted = true;
                return Err(())
            }
        }
        match self.tokenizer.next() {
            Err(()) => {
                self.state.exhausted = true;
                Err(())
            },
            Ok(token) => {
                if self.state.stop_before.contains(Delimiters::from_token(&token)) {
                    self.tokenizer.push_back(token);
                    self.state.exhausted = true;
                    return Err(())
                }
                if self.state.stop_at_end_of.is_some() &&
                        BlockType::closing(&token) == self.state.stop_at_end_of {
                    self.state.exhausted = true;
                    return Err(())
                }
                if let Some(block_type) = BlockType::opening(&token) {
                    self.state.at_start_of = Some(block_type);
                }
                Ok(token)
            }
        }
    }

    #[inline]
    pub fn err_consume_until_after<T>(&mut self, stop_after: Delimiters) -> Result<T, ()> {
        self.consume_until_after(stop_after);
        Err(())
    }

    pub fn consume_until_after(&mut self, stop_after: Delimiters) {
        if self.state.exhausted {
            return
        }
        // FIXME: have a special-purpose tokenizer method for this that does less work.
        while let Ok(token) = self.tokenizer.next() {
            if stop_after.contains(Delimiters::from_token(&token)) {
                return
            }
            if self.state.stop_before.contains(Delimiters::from_token(&token)) {
                self.tokenizer.push_back(token);
                self.state.exhausted = true;
                return
            }
            if self.state.stop_at_end_of.is_some() &&
                    BlockType::closing(&token) == self.state.stop_at_end_of {
                self.state.exhausted = true;
                return
            }
            if let Some(block_type) = BlockType::opening(&token) {
                if consume_until_end_of_block(block_type, self.tokenizer) {
                    self.state.exhausted = true;
                    return
                }
            }
        }
        self.state.exhausted = true;
    }

    // FIXME: Take an unboxed `FnOnce` closure.
    #[inline]
    pub fn parse_entirely<T>(&mut self, parse: |&mut Parser| -> Result<T, ()>)
                             -> Result<T, ()> {
        let result = parse(self);
        try!(self.expect_exhausted());
        result
    }

    #[inline]
    pub fn parse_nested_block<'a>(&'a mut self) -> Parser<'i, 'a> {
        if let Some(block_type) = self.state.at_start_of.take() {
            debug_assert!(!self.state.exhausted);
            Parser {
                tokenizer: self.tokenizer,
                state: ParserState {
                    nested_blocks: self.state.nested_blocks.take(),
                    at_start_of: None,
                    stop_at_end_of: Some(block_type),
                    stop_before: Delimiter::None,
                    exhausted: false,
                },
                parent_state: Some(&mut self.state),
            }
        } else {
            panic!("\
                parse_block can only be called when a Function, \
                ParenthesisBlock, SquareBracketBlock, or CurlyBracketBlock \
                token was just consumed.\
            ");
        }
    }

    #[inline]
    pub fn parse_until_before<'a>(&'a mut self, stop_before: Delimiters) -> Parser<'i, 'a> {
        Parser {
            tokenizer: self.tokenizer,
            state: ParserState {
                nested_blocks: self.state.nested_blocks.take(),
                at_start_of: self.state.at_start_of.take(),
                stop_at_end_of: self.state.stop_at_end_of,
                stop_before: self.state.stop_before | stop_before,
                exhausted: self.state.exhausted,
            },
            parent_state: Some(&mut self.state),
        }
    }

    #[inline]
    pub fn expect_ident(&mut self) -> Result<CowString<'i>, ()> {
        match try!(self.next()) {
            Token::Ident(value) => Ok(value),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_quoted_string(&mut self) -> Result<CowString<'i>, ()> {
        match try!(self.next()) {
            Token::QuotedString(value) => Ok(value),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_url(&mut self) -> Result<CowString<'i>, ()> {
        match try!(self.next()) {
            Token::Url(value) => Ok(value),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_url_or_string(&mut self) -> Result<CowString<'i>, ()> {
        match try!(self.next()) {
            Token::Url(value) => Ok(value),
            Token::QuotedString(value) => Ok(value),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_number(&mut self) -> Result<f64, ()> {
        match try!(self.next()) {
            Token::Number(NumericValue { value, .. }) => Ok(value),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_integer(&mut self) -> Result<i64, ()> {
        match try!(self.next()) {
            Token::Number(NumericValue { int_value, .. }) => int_value.ok_or(()),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_percentage(&mut self) -> Result<f64, ()> {
        match try!(self.next()) {
            Token::Percentage(NumericValue { value, .. }) => Ok(value),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_colon(&mut self) -> Result<(), ()> {
        match try!(self.next()) {
            Token::Colon => Ok(()),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_semicolon(&mut self) -> Result<(), ()> {
        match try!(self.next()) {
            Token::Semicolon => Ok(()),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_comma(&mut self) -> Result<(), ()> {
        match try!(self.next()) {
            Token::Comma => Ok(()),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_curly_bracke_block(&mut self) -> Result<(), ()> {
        match try!(self.next()) {
            Token::CurlyBracketBlock => Ok(()),
            token => self.unexpected(token)
        }
    }
}

/// Return value indicates whether the end of the input was reached.
fn consume_until_end_of_block(block_type: BlockType, tokenizer: &mut Tokenizer) -> bool {
    // FIXME: have a special-purpose tokenizer method for this that does less work.
    while let Ok(ref token) = tokenizer.next() {
        if BlockType::closing(token) == Some(block_type) {
            return false
        }
        if let Some(block_type) = BlockType::opening(token) {
            if consume_until_end_of_block(block_type, tokenizer) {
                return true
            }
        }
    }
    true
}
<|endoftext|>


<commit_before>use std::clone::Clone;

use encoding::types::{EncodingRef, RawDecoder};

#[derive(Debug, PartialEq)]
pub enum Token {
    Null,
    CtrlA,
    CtrlB,
    CtrlC,
    CtrlD,
    CtrlE,
    CtrlF,
    CtrlG,
    CtrlH,
    Tab,
    CtrlJ,
    CtrlK,
    CtrlL,
    Enter,
    CtrlN,
    CtrlO,
    CtrlP,
    CtrlQ,
    CtrlR,
    CtrlS,
    CtrlT,
    CtrlU,
    CtrlV,
    CtrlW,
    CtrlX,
    CtrlY,
    CtrlZ,
    Esc,
    Backspace,
    EscBracket3T,
    EscBracketA,
    EscBracketB,
    EscBracketC,
    EscBracketD,
    EscBracketH,
    EscBracketF,
    Text(String)
}

#[derive(Debug, PartialEq)]
pub enum ParseError {
    Error(usize),
    Incomplete
}

#[derive(Debug, PartialEq)]
pub struct ParseSuccess<T>(pub T, pub usize);

pub type ParseResult<T> = Result<ParseSuccess<T>, ParseError>;

fn map_and_filter_result<T, U, F: FnOnce(T) -> Option<U>>(r: ParseResult<T>, f: F) -> ParseResult<U> {
    r.and_then(|ParseSuccess(t, n)| {
        match f(t) {
            Some(u) => Ok(ParseSuccess(u, n)),
            None => Err(ParseError::Error(n))
        }
    })
}

fn filter_result<T, F: FnOnce(T) -> bool>(r: ParseResult<T>, f: F) -> ParseResult<()> {
    map_and_filter_result(r, |t| {
        if f(t) {
            Some(())
        } else {
            None
        }
    })
}

fn match_head(i: u8) -> Option<Token> {
    match i {
        0   => Some(Token::Null),
        1   => Some(Token::CtrlA),
        2   => Some(Token::CtrlB),
        3   => Some(Token::CtrlC),
        4   => Some(Token::CtrlD),
        5   => Some(Token::CtrlE),
        6   => Some(Token::CtrlF),
        7   => Some(Token::CtrlG),
        8   => Some(Token::CtrlH),
        9   => Some(Token::Tab),
        10  => Some(Token::CtrlJ),
        11  => Some(Token::CtrlK),
        12  => Some(Token::CtrlL),
        13  => Some(Token::Enter),
        14  => Some(Token::CtrlN),
        15  => Some(Token::CtrlO),
        16  => Some(Token::CtrlP),
        17  => Some(Token::CtrlQ),
        18  => Some(Token::CtrlR),
        19  => Some(Token::CtrlS),
        20  => Some(Token::CtrlT),
        21  => Some(Token::CtrlU),
        22  => Some(Token::CtrlV),
        23  => Some(Token::CtrlW),
        24  => Some(Token::CtrlX),
        25  => Some(Token::CtrlY),
        26  => Some(Token::CtrlZ),
        27  => Some(Token::Esc),
        127 => Some(Token::Backspace),
        _   => None
    }
}

fn parse_char(vec: &[u8], off: usize) -> ParseResult<u8> {
    match vec.get(off) {
        None => Err(ParseError::Incomplete),
        Some(i) => {
            Ok(ParseSuccess(i.clone(), off + 1))
        }
    }
}

fn parse_esc_bracket(vec: &[u8]) -> ParseResult<Token> {
    let c = try!(parse_char(vec, 2)).0 as char;
    if c >= '0' && c <= '9' {
        /* Extended escape, read additional byte. */
        let d = try!(parse_char(vec, 3)).0 as char;
        match (c, d) {
            ('3', '~') => Ok(ParseSuccess(Token::EscBracket3T, 4)),
            _ => Err(ParseError::Error(4))
        }
    } else {
        match c {
            'A' => Ok(ParseSuccess(Token::EscBracketA, 3)),
            'B' => Ok(ParseSuccess(Token::EscBracketB, 3)),
            'C' => Ok(ParseSuccess(Token::EscBracketC, 3)),
            'D' => Ok(ParseSuccess(Token::EscBracketD, 3)),
            'F' => Ok(ParseSuccess(Token::EscBracketF, 3)),
            'H' => Ok(ParseSuccess(Token::EscBracketH, 3)),
            _ => Err(ParseError::Error(2)) // TODO: implement more
        }
    }
}

fn parse_esc(vec: &[u8]) -> ParseResult<Token> {
    let c = try!(parse_char(vec, 1)).0 as char;
    if c == '[' {
        parse_esc_bracket(vec)
    } else if c == '0' {
        Err(ParseError::Error(2)) // TODO: implement
    } else {
        Err(ParseError::Error(2))
    }
}

pub fn parse(vec: &[u8], enc: EncodingRef) -> ParseResult<Token> {
    let i = try!(parse_char(vec, 0)).0;
    match match_head(i) {
        Some(Token::Esc) => parse_esc(vec),
        Some(t) => Ok(ParseSuccess(t, 1)),
        None => {
            let mut dec = enc.raw_decoder();
            let mut text = String::new();
            match dec.raw_feed(vec, &mut text) {
                (offset, None) => Ok(ParseSuccess(Token::Text(text), offset)),
                (offset, Some(_)) => Err(ParseError::Error(offset))
            }
        }
    }
}

fn parse_number(vec: &[u8], off: usize) -> (u64, usize) {
    vec
    .iter().skip(off).cloned()
    .take_while(|&c| c >= 48 && c < 58)
    .fold((0, 0), |(x, n), c| {
        (x * 10 + (c as u64 - 48), n + 1)
    })
}

#[test]
fn parse_number_empty() {
    let v = vec![];
    assert_eq!(parse_number(&v, 0), (0, 0));
}

#[test]
fn parse_number_42() {
    let v = vec![48 + 4, 48 + 2, 20, 33];
    assert_eq!(parse_number(&v, 0), (42, 2));
}

#[test]
fn parse_number_invalid() {
    let v = vec![20, 33];
    assert_eq!(parse_number(&v, 0), (0, 0));
}

pub fn parse_cursor_pos(vec: &[u8]) -> ParseResult<(u64, u64)> {
    try!(filter_result(parse_char(vec, 0), |i| i == 27));
    try!(filter_result(parse_char(vec, 1), |i| i == 91));
    let (y, n) = parse_number(vec, 2);
    try!(filter_result(parse_char(vec, 2+n), |i| i == 59));
    let (x, m) = parse_number(vec, 3+n);
    try!(filter_result(parse_char(vec, 3+n+m), |i| i == 82));
    Ok(ParseSuccess((x, y), 4+n+m))
}

#[test]
fn parse_cursor_pos_full() {
    let v = vec![27, 91, 48 + 4, 48 + 2, 59, 48 + 6, 82];
    assert_eq!(parse_cursor_pos(&v), Ok(ParseSuccess((6, 42), 7)));
}

#[test]
fn parse_cursor_pos_incomplete() {
    let v = vec![27, 91, 48 + 4, 48 + 2, 59, 48 + 6];
    assert_eq!(parse_cursor_pos(&v), Err(ParseError::Incomplete));
}

#[test]
fn parse_cursor_pos_invalid() {
    let v = vec![27, 91, 48 + 4, 48 + 10, 59, 48 + 6];
    assert_eq!(parse_cursor_pos(&v), Err(ParseError::Error(4)));
}
<commit_msg>only parse escape sequences if we have multiple bytes<commit_after>use std::clone::Clone;

use encoding::types::{EncodingRef, RawDecoder};

#[derive(Debug, PartialEq)]
pub enum Token {
    Null,
    CtrlA,
    CtrlB,
    CtrlC,
    CtrlD,
    CtrlE,
    CtrlF,
    CtrlG,
    CtrlH,
    Tab,
    CtrlJ,
    CtrlK,
    CtrlL,
    Enter,
    CtrlN,
    CtrlO,
    CtrlP,
    CtrlQ,
    CtrlR,
    CtrlS,
    CtrlT,
    CtrlU,
    CtrlV,
    CtrlW,
    CtrlX,
    CtrlY,
    CtrlZ,
    Esc,
    Backspace,
    EscBracket3T,
    EscBracketA,
    EscBracketB,
    EscBracketC,
    EscBracketD,
    EscBracketH,
    EscBracketF,
    Text(String)
}

#[derive(Debug, PartialEq)]
pub enum ParseError {
    Error(usize),
    Incomplete
}

#[derive(Debug, PartialEq)]
pub struct ParseSuccess<T>(pub T, pub usize);

pub type ParseResult<T> = Result<ParseSuccess<T>, ParseError>;

fn map_and_filter_result<T, U, F: FnOnce(T) -> Option<U>>(r: ParseResult<T>, f: F) -> ParseResult<U> {
    r.and_then(|ParseSuccess(t, n)| {
        match f(t) {
            Some(u) => Ok(ParseSuccess(u, n)),
            None => Err(ParseError::Error(n))
        }
    })
}

fn filter_result<T, F: FnOnce(T) -> bool>(r: ParseResult<T>, f: F) -> ParseResult<()> {
    map_and_filter_result(r, |t| {
        if f(t) {
            Some(())
        } else {
            None
        }
    })
}

fn match_head(i: u8) -> Option<Token> {
    match i {
        0   => Some(Token::Null),
        1   => Some(Token::CtrlA),
        2   => Some(Token::CtrlB),
        3   => Some(Token::CtrlC),
        4   => Some(Token::CtrlD),
        5   => Some(Token::CtrlE),
        6   => Some(Token::CtrlF),
        7   => Some(Token::CtrlG),
        8   => Some(Token::CtrlH),
        9   => Some(Token::Tab),
        10  => Some(Token::CtrlJ),
        11  => Some(Token::CtrlK),
        12  => Some(Token::CtrlL),
        13  => Some(Token::Enter),
        14  => Some(Token::CtrlN),
        15  => Some(Token::CtrlO),
        16  => Some(Token::CtrlP),
        17  => Some(Token::CtrlQ),
        18  => Some(Token::CtrlR),
        19  => Some(Token::CtrlS),
        20  => Some(Token::CtrlT),
        21  => Some(Token::CtrlU),
        22  => Some(Token::CtrlV),
        23  => Some(Token::CtrlW),
        24  => Some(Token::CtrlX),
        25  => Some(Token::CtrlY),
        26  => Some(Token::CtrlZ),
        27  => Some(Token::Esc),
        127 => Some(Token::Backspace),
        _   => None
    }
}

fn parse_char(vec: &[u8], off: usize) -> ParseResult<u8> {
    match vec.get(off) {
        None => Err(ParseError::Incomplete),
        Some(i) => {
            Ok(ParseSuccess(i.clone(), off + 1))
        }
    }
}

fn parse_esc_bracket(vec: &[u8]) -> ParseResult<Token> {
    let c = try!(parse_char(vec, 2)).0 as char;
    if c >= '0' && c <= '9' {
        /* Extended escape, read additional byte. */
        let d = try!(parse_char(vec, 3)).0 as char;
        match (c, d) {
            ('3', '~') => Ok(ParseSuccess(Token::EscBracket3T, 4)),
            _ => Err(ParseError::Error(4))
        }
    } else {
        match c {
            'A' => Ok(ParseSuccess(Token::EscBracketA, 3)),
            'B' => Ok(ParseSuccess(Token::EscBracketB, 3)),
            'C' => Ok(ParseSuccess(Token::EscBracketC, 3)),
            'D' => Ok(ParseSuccess(Token::EscBracketD, 3)),
            'F' => Ok(ParseSuccess(Token::EscBracketF, 3)),
            'H' => Ok(ParseSuccess(Token::EscBracketH, 3)),
            _ => Err(ParseError::Error(2)) // TODO: implement more
        }
    }
}

fn parse_esc(vec: &[u8]) -> ParseResult<Token> {
    let c = try!(parse_char(vec, 1)).0 as char;
    if c == '[' {
        parse_esc_bracket(vec)
    } else if c == '0' {
        Err(ParseError::Error(2)) // TODO: implement
    } else {
        Err(ParseError::Error(2))
    }
}

pub fn parse(vec: &[u8], enc: EncodingRef) -> ParseResult<Token> {
    let i = try!(parse_char(vec, 0)).0;
    match match_head(i) {
        Some(Token::Esc) if vec.len() > 1 => parse_esc(vec),
        Some(t) => Ok(ParseSuccess(t, 1)),
        None => {
            let mut dec = enc.raw_decoder();
            let mut text = String::new();
            match dec.raw_feed(vec, &mut text) {
                (offset, None) => Ok(ParseSuccess(Token::Text(text), offset)),
                (offset, Some(_)) => Err(ParseError::Error(offset))
            }
        }
    }
}

fn parse_number(vec: &[u8], off: usize) -> (u64, usize) {
    vec
    .iter().skip(off).cloned()
    .take_while(|&c| c >= 48 && c < 58)
    .fold((0, 0), |(x, n), c| {
        (x * 10 + (c as u64 - 48), n + 1)
    })
}

#[test]
fn parse_number_empty() {
    let v = vec![];
    assert_eq!(parse_number(&v, 0), (0, 0));
}

#[test]
fn parse_number_42() {
    let v = vec![48 + 4, 48 + 2, 20, 33];
    assert_eq!(parse_number(&v, 0), (42, 2));
}

#[test]
fn parse_number_invalid() {
    let v = vec![20, 33];
    assert_eq!(parse_number(&v, 0), (0, 0));
}

pub fn parse_cursor_pos(vec: &[u8]) -> ParseResult<(u64, u64)> {
    try!(filter_result(parse_char(vec, 0), |i| i == 27));
    try!(filter_result(parse_char(vec, 1), |i| i == 91));
    let (y, n) = parse_number(vec, 2);
    try!(filter_result(parse_char(vec, 2+n), |i| i == 59));
    let (x, m) = parse_number(vec, 3+n);
    try!(filter_result(parse_char(vec, 3+n+m), |i| i == 82));
    Ok(ParseSuccess((x, y), 4+n+m))
}

#[test]
fn parse_cursor_pos_full() {
    let v = vec![27, 91, 48 + 4, 48 + 2, 59, 48 + 6, 82];
    assert_eq!(parse_cursor_pos(&v), Ok(ParseSuccess((6, 42), 7)));
}

#[test]
fn parse_cursor_pos_incomplete() {
    let v = vec![27, 91, 48 + 4, 48 + 2, 59, 48 + 6];
    assert_eq!(parse_cursor_pos(&v), Err(ParseError::Incomplete));
}

#[test]
fn parse_cursor_pos_invalid() {
    let v = vec![27, 91, 48 + 4, 48 + 10, 59, 48 + 6];
    assert_eq!(parse_cursor_pos(&v), Err(ParseError::Error(4)));
}
<|endoftext|>


<commit_before>use super::{Document,Root,RootChild,Element,ElementChild};

struct Parser;

struct ParsedElement<'a> {
    name: &'a str,
    attributes: Vec<ParsedAttribute<'a>>,
    children: Vec<ParsedElement<'a>>,
}

struct ParsedAttribute<'a> {
    name: &'a str,
    value: &'a str,
}

macro_rules! try_parse(
    ($e:expr) => ({
        match $e {
            None => return None,
            Some(x) => x,
        }
    })
)

// Pattern: 0-or-1
macro_rules! optional_parse(
    ($f:expr, $start:expr) => ({
        match $f {
            None => (None, $start),
            Some((value, next)) => (Some(value), next),
        }
    })
)

impl Parser {
    fn new() -> Parser {
        Parser
    }

    fn parse_preamble<'a>(&self, xml: &'a str) -> &'a str {
        // Parse the preamble
        let idx = xml.find_str("?>").expect("No preamble end");
        let end_of_preamble = idx + "?>".len();
        xml.slice_from(end_of_preamble)
    }

    fn optional_space<'a>(&self, xml: &'a str) -> &'a str {
        match xml.slice_space() {
            Some((_, next_xml)) => next_xml,
            None => xml,
        }
    }

    fn parse_attribute_value_quote<'a>(&self, xml: &'a str, quote: &str) -> Option<(&'a str, &'a str)> {
        let (_, xml) = match xml.slice_literal(quote) {
            None => return None,
            Some(x) => x,
        };
        // TODO: don't consume & or <
        let (value, xml) = xml.slice_until(quote).expect("No value");
        let (_, xml) = xml.slice_literal(quote).expect("No quote");

        Some((value, xml))
    }

    fn parse_attribute<'a>(&self, xml: &'a str) -> Option<(ParsedAttribute<'a>, &'a str)> {
        let (name, xml) = match xml.slice_name() {
            Some(x) => x,
            None => return None,
        };

        let xml = self.optional_space(xml);
        let (_, xml) = xml.slice_literal("=").expect("No equal sign");
        let xml = self.optional_space(xml);

        // Pattern: alternate
        let (value, xml) = match self.parse_attribute_value_quote(xml, "'") {
            Some(x) => x,
            None => match self.parse_attribute_value_quote(xml, "\"") {
                Some(x) => x,
                None => fail!("No attribute value"),
            },
        };

        Some((ParsedAttribute{name: name, value: value}, xml))
    }

    fn parse_attributes<'a>(&self, xml: &'a str) -> (Vec<ParsedAttribute<'a>>, &'a str) {
        let mut xml = xml;
        let mut attrs = Vec::new();

        // Pattern: zero-or-more
        // On failure, return the end of the last successful parse
        loop {
            let (_, after_space) = match xml.slice_space() {
                None => return (attrs, xml),
                Some(x) => x,
            };

            xml = match self.parse_attribute(after_space) {
                None => return (attrs, xml),
                Some((attr, after_attr)) => {
                    attrs.push(attr);
                    after_attr
                },
            };
        }
    }

    fn parse_empty_element<'a>(&self, xml: &'a str) -> Option<(ParsedElement<'a>, &'a str)> {
        let (_, xml) = try_parse!(xml.slice_literal("<"));
        let (name, xml) = try_parse!(xml.slice_name());
        let (attrs, xml) = self.parse_attributes(xml);
        let xml = self.optional_space(xml);
        let (_, xml) = try_parse!(xml.slice_literal("/>"));

        Some((ParsedElement{name: name, attributes: attrs, children: Vec::new()}, xml))
    }

    fn parse_element_start<'a>(&self, xml: &'a str) -> Option<(ParsedElement<'a>, &'a str)> {
        let (_, xml) = try_parse!(xml.slice_literal("<"));
        let (name, xml) = try_parse!(xml.slice_name());
        let (attrs, xml) = self.parse_attributes(xml);
        let xml = self.optional_space(xml);
        let (_, xml) = try_parse!(xml.slice_literal(">"));

        Some((ParsedElement{name: name, attributes: attrs, children: Vec::new()}, xml))
    }

    fn parse_element_end<'a>(&self, xml: &'a str) -> Option<(&'a str, &'a str)> {
        let (_, xml) = try_parse!(xml.slice_literal("</"));
        let (name, xml) = try_parse!(xml.slice_name());
        let xml = self.optional_space(xml);
        let (_, xml) = try_parse!(xml.slice_literal(">"));
        Some((name, xml))
    }

    fn parse_non_empty_element<'a>(&self, xml: &'a str) -> Option<(ParsedElement<'a>, &'a str)> {
        let (mut element, xml) = try_parse!(self.parse_element_start(xml));
        let (child, xml) = optional_parse!(self.parse_element(xml), xml);
        let (name, xml) = try_parse!(self.parse_element_end(xml));

        if element.name != name {
            fail!("tags do not match!");
        }

        child.map(|c| element.children.push(c));

        Some((element, xml))
    }

    fn parse_element<'a>(&self, xml: &'a str) -> Option<(ParsedElement<'a>, &'a str)> {
        // Pattern: alternate
        match self.parse_empty_element(xml) {
            Some(x) => Some(x),
            None => match self.parse_non_empty_element(xml) {
                Some(x) => Some(x),
                None => None,
            },
        }
    }

    fn hydrate_element(&self, doc: Document, element_data: ParsedElement) -> Element {
        let element = doc.new_element(element_data.name.to_string());
        for attr in element_data.attributes.iter() {
            element.set_attribute(attr.name.to_string(), attr.value.to_string());
        }
        for child in element_data.children.move_iter() {
            element.append_child(self.hydrate_element(doc.clone(), child));
        }
        element
    }

    fn hydrate_parsed_data(&self, element_data: ParsedElement) -> Document {
        let doc = Document::new();

        doc.root().append_child(self.hydrate_element(doc.clone(), element_data));

        doc
    }

    fn parse(&self, xml: &str) -> Document {
        let after_preamble = self.parse_preamble(xml);

        let (element, _tail) = self.parse_element(after_preamble).expect("no element");

        self.hydrate_parsed_data(element)
    }
}

trait XmlStr<'a> {
    fn slice_at(&self, position: uint) -> (&'a str, &'a str);
    fn slice_until(&self, s: &str) -> Option<(&'a str, &'a str)>;
    fn slice_literal(&self, expected: &str) -> Option<(&'a str, &'a str)>;
    fn slice_start_rest(&self, is_first: |char| -> bool, is_rest: |char| -> bool) -> Option<(&'a str, &'a str)>;
    fn slice_name(&self) -> Option<(&'a str, &'a str)>;
    fn slice_space(&self) -> Option<(&'a str, &'a str)>;
}

impl<'a> XmlStr<'a> for &'a str {
    fn slice_at(&self, position: uint) -> (&'a str, &'a str) {
        (self.slice_to(position), self.slice_from(position))
    }

    fn slice_until(&self, s: &str) -> Option<(&'a str, &'a str)> {
        match self.find_str(s) {
            Some(position) => Some(self.slice_at(position)),
            None => None
        }
    }

    fn slice_literal(&self, expected: &str) -> Option<(&'a str, &'a str)> {
        if self.starts_with(expected) {
            Some(self.slice_at(expected.len()))
        } else {
            None
        }
    }

    fn slice_start_rest(&self,
                        is_first: |char| -> bool,
                        is_rest: |char| -> bool)
                        -> Option<(&'a str, &'a str)>
    {
        let mut positions = self.char_indices();

        match positions.next() {
            Some((_, c)) if is_first(c) => (),
            Some((_, _)) => return None,
            None => return None,
        };

        let mut positions = positions.skip_while(|&(_, c)| is_rest(c));
        match positions.next() {
            Some((offset, _)) => Some(self.slice_at(offset)),
            None => Some((self.clone(), "")),
        }
    }

    fn slice_name(&self) -> Option<(&'a str, &'a str)> {
        self.slice_start_rest(|c| c.is_name_start_char(), |c| c.is_name_char())
    }

    fn slice_space(&self) -> Option<(&'a str, &'a str)> {
        self.slice_start_rest(|c| c.is_space_char(), |c| c.is_space_char())
    }
}

trait XmlChar {
    fn is_name_start_char(&self) -> bool;
    fn is_name_char(&self) -> bool;
    fn is_space_char(&self) -> bool;
}

impl XmlChar for char {
    fn is_name_start_char(&self) -> bool {
        match *self {
            ':'                        |
            'A'..'Z'                   |
            '_'                        |
            'a'..'z'                   |
            '\U000000C0'..'\U000000D6' |
            '\U000000D8'..'\U000000F6' |
            '\U000000F8'..'\U000002FF' |
            '\U00000370'..'\U0000037D' |
            '\U0000037F'..'\U00001FFF' |
            '\U0000200C'..'\U0000200D' |
            '\U00002070'..'\U0000218F' |
            '\U00002C00'..'\U00002FEF' |
            '\U00003001'..'\U0000D7FF' |
            '\U0000F900'..'\U0000FDCF' |
            '\U0000FDF0'..'\U0000FFFD' |
            '\U00010000'..'\U000EFFFF' => true,
            _ => false,
        }
    }

    fn is_name_char(&self) -> bool {
        if self.is_name_start_char() { return true; }
        match *self {
            '-'                |
            '.'                |
            '0'..'9'           |
            '\u00B7'           |
            '\u0300'..'\u036F' |
            '\u203F'..'\u2040' => true,
            _ => false
        }
    }

    fn is_space_char(&self) -> bool {
        match *self {
            '\x20' |
            '\x09' |
            '\x0D' |
            '\x0A' => true,
            _ => false,
        }
    }
}

trait Hax {
    fn first_child(&self) -> Option<RootChild>;
}

impl Hax for Root {
    fn first_child(&self) -> Option<RootChild> {
        self.children().remove(0)
    }
}

trait Hax2 {
    fn first_child(&self) -> Option<ElementChild>;
}

impl Hax2 for Element {
    fn first_child(&self) -> Option<ElementChild> {
        self.children().remove(0)
    }
}

#[test]
fn parses_a_document_with_a_single_element() {
    let parser = Parser::new();
    let doc = parser.parse("<?xml version='1.0' ?><hello />");
    let top = doc.root().first_child().unwrap().element().unwrap();

    assert_eq!(top.name().as_slice(), "hello");
}

#[test]
fn parses_an_element_with_an_attribute() {
    let parser = Parser::new();
    let doc = parser.parse("<?xml version='1.0' ?><hello scope='world'/>");
    let top = doc.root().first_child().unwrap().element().unwrap();

    assert_eq!(top.get_attribute("scope").unwrap().as_slice(), "world");
}

#[test]
fn parses_an_element_with_an_attribute_using_double_quotes() {
    let parser = Parser::new();
    let doc = parser.parse("<?xml version='1.0' ?><hello scope=\"world\"/>");
    let top = doc.root().first_child().unwrap().element().unwrap();

    assert_eq!(top.get_attribute("scope").unwrap().as_slice(), "world");
}

#[test]
fn parses_an_element_with_multiple_attributes() {
    let parser = Parser::new();
    let doc = parser.parse("<?xml version='1.0' ?><hello scope=\"world\" happy='true'/>");
    let top = doc.root().first_child().unwrap().element().unwrap();

    assert_eq!(top.get_attribute("scope").unwrap().as_slice(), "world");
    assert_eq!(top.get_attribute("happy").unwrap().as_slice(), "true");
}

#[test]
fn parses_an_element_that_is_not_self_closing() {
    let parser = Parser::new();
    let doc = parser.parse("<?xml version='1.0' ?><hello></hello>");
    let top = doc.root().first_child().unwrap().element().unwrap();

    assert_eq!(top.name().as_slice(), "hello");
}

#[test]
fn parses_nested_elements() {
    let parser = Parser::new();
    let doc = parser.parse("<?xml version='1.0' ?><hello><world/></hello>");
    let nested = doc.root().first_child().unwrap().element().unwrap().first_child().unwrap().element().unwrap();

    assert_eq!(nested.name().as_slice(), "world");
}

#[test]
fn parses_multiply_nested_elements() {
    let parser = Parser::new();
    let doc = parser.parse("<?xml version='1.0' ?><hello><awesome><world/></awesome></hello>");
    let hello = doc.root().first_child().unwrap().element().unwrap();
    let awesome = hello.first_child().unwrap().element().unwrap();
    let world = awesome.first_child().unwrap().element().unwrap();

    assert_eq!(world.name().as_slice(), "world");
}

#[test]
fn parses_nested_elements_with_attributes() {
    let parser = Parser::new();
    let doc = parser.parse("<?xml version='1.0' ?><hello><world name='Earth'/></hello>");
    let hello = doc.root().first_child().unwrap().element().unwrap();
    let world = hello.first_child().unwrap().element().unwrap();

    assert_eq!(world.get_attribute("name").unwrap().as_slice(), "Earth");
}
<commit_msg>Ignore dead code for now<commit_after>use super::{Document,Root,RootChild,Element,ElementChild};

#[allow(dead_code)]
struct Parser;

#[allow(dead_code)]
struct ParsedElement<'a> {
    name: &'a str,
    attributes: Vec<ParsedAttribute<'a>>,
    children: Vec<ParsedElement<'a>>,
}

#[allow(dead_code)]
struct ParsedAttribute<'a> {
    name: &'a str,
    value: &'a str,
}

macro_rules! try_parse(
    ($e:expr) => ({
        match $e {
            None => return None,
            Some(x) => x,
        }
    })
)

// Pattern: 0-or-1
macro_rules! optional_parse(
    ($f:expr, $start:expr) => ({
        match $f {
            None => (None, $start),
            Some((value, next)) => (Some(value), next),
        }
    })
)

#[allow(dead_code)]
impl Parser {
    fn new() -> Parser {
        Parser
    }

    fn parse_preamble<'a>(&self, xml: &'a str) -> &'a str {
        // Parse the preamble
        let idx = xml.find_str("?>").expect("No preamble end");
        let end_of_preamble = idx + "?>".len();
        xml.slice_from(end_of_preamble)
    }

    fn optional_space<'a>(&self, xml: &'a str) -> &'a str {
        match xml.slice_space() {
            Some((_, next_xml)) => next_xml,
            None => xml,
        }
    }

    fn parse_attribute_value_quote<'a>(&self, xml: &'a str, quote: &str) -> Option<(&'a str, &'a str)> {
        let (_, xml) = match xml.slice_literal(quote) {
            None => return None,
            Some(x) => x,
        };
        // TODO: don't consume & or <
        let (value, xml) = xml.slice_until(quote).expect("No value");
        let (_, xml) = xml.slice_literal(quote).expect("No quote");

        Some((value, xml))
    }

    fn parse_attribute<'a>(&self, xml: &'a str) -> Option<(ParsedAttribute<'a>, &'a str)> {
        let (name, xml) = match xml.slice_name() {
            Some(x) => x,
            None => return None,
        };

        let xml = self.optional_space(xml);
        let (_, xml) = xml.slice_literal("=").expect("No equal sign");
        let xml = self.optional_space(xml);

        // Pattern: alternate
        let (value, xml) = match self.parse_attribute_value_quote(xml, "'") {
            Some(x) => x,
            None => match self.parse_attribute_value_quote(xml, "\"") {
                Some(x) => x,
                None => fail!("No attribute value"),
            },
        };

        Some((ParsedAttribute{name: name, value: value}, xml))
    }

    fn parse_attributes<'a>(&self, xml: &'a str) -> (Vec<ParsedAttribute<'a>>, &'a str) {
        let mut xml = xml;
        let mut attrs = Vec::new();

        // Pattern: zero-or-more
        // On failure, return the end of the last successful parse
        loop {
            let (_, after_space) = match xml.slice_space() {
                None => return (attrs, xml),
                Some(x) => x,
            };

            xml = match self.parse_attribute(after_space) {
                None => return (attrs, xml),
                Some((attr, after_attr)) => {
                    attrs.push(attr);
                    after_attr
                },
            };
        }
    }

    fn parse_empty_element<'a>(&self, xml: &'a str) -> Option<(ParsedElement<'a>, &'a str)> {
        let (_, xml) = try_parse!(xml.slice_literal("<"));
        let (name, xml) = try_parse!(xml.slice_name());
        let (attrs, xml) = self.parse_attributes(xml);
        let xml = self.optional_space(xml);
        let (_, xml) = try_parse!(xml.slice_literal("/>"));

        Some((ParsedElement{name: name, attributes: attrs, children: Vec::new()}, xml))
    }

    fn parse_element_start<'a>(&self, xml: &'a str) -> Option<(ParsedElement<'a>, &'a str)> {
        let (_, xml) = try_parse!(xml.slice_literal("<"));
        let (name, xml) = try_parse!(xml.slice_name());
        let (attrs, xml) = self.parse_attributes(xml);
        let xml = self.optional_space(xml);
        let (_, xml) = try_parse!(xml.slice_literal(">"));

        Some((ParsedElement{name: name, attributes: attrs, children: Vec::new()}, xml))
    }

    fn parse_element_end<'a>(&self, xml: &'a str) -> Option<(&'a str, &'a str)> {
        let (_, xml) = try_parse!(xml.slice_literal("</"));
        let (name, xml) = try_parse!(xml.slice_name());
        let xml = self.optional_space(xml);
        let (_, xml) = try_parse!(xml.slice_literal(">"));
        Some((name, xml))
    }

    fn parse_non_empty_element<'a>(&self, xml: &'a str) -> Option<(ParsedElement<'a>, &'a str)> {
        let (mut element, xml) = try_parse!(self.parse_element_start(xml));
        let (child, xml) = optional_parse!(self.parse_element(xml), xml);
        let (name, xml) = try_parse!(self.parse_element_end(xml));

        if element.name != name {
            fail!("tags do not match!");
        }

        child.map(|c| element.children.push(c));

        Some((element, xml))
    }

    fn parse_element<'a>(&self, xml: &'a str) -> Option<(ParsedElement<'a>, &'a str)> {
        // Pattern: alternate
        match self.parse_empty_element(xml) {
            Some(x) => Some(x),
            None => match self.parse_non_empty_element(xml) {
                Some(x) => Some(x),
                None => None,
            },
        }
    }

    fn hydrate_element(&self, doc: Document, element_data: ParsedElement) -> Element {
        let element = doc.new_element(element_data.name.to_string());
        for attr in element_data.attributes.iter() {
            element.set_attribute(attr.name.to_string(), attr.value.to_string());
        }
        for child in element_data.children.move_iter() {
            element.append_child(self.hydrate_element(doc.clone(), child));
        }
        element
    }

    fn hydrate_parsed_data(&self, element_data: ParsedElement) -> Document {
        let doc = Document::new();

        doc.root().append_child(self.hydrate_element(doc.clone(), element_data));

        doc
    }

    fn parse(&self, xml: &str) -> Document {
        let after_preamble = self.parse_preamble(xml);

        let (element, _tail) = self.parse_element(after_preamble).expect("no element");

        self.hydrate_parsed_data(element)
    }
}

trait XmlStr<'a> {
    fn slice_at(&self, position: uint) -> (&'a str, &'a str);
    fn slice_until(&self, s: &str) -> Option<(&'a str, &'a str)>;
    fn slice_literal(&self, expected: &str) -> Option<(&'a str, &'a str)>;
    fn slice_start_rest(&self, is_first: |char| -> bool, is_rest: |char| -> bool) -> Option<(&'a str, &'a str)>;
    fn slice_name(&self) -> Option<(&'a str, &'a str)>;
    fn slice_space(&self) -> Option<(&'a str, &'a str)>;
}

impl<'a> XmlStr<'a> for &'a str {
    fn slice_at(&self, position: uint) -> (&'a str, &'a str) {
        (self.slice_to(position), self.slice_from(position))
    }

    fn slice_until(&self, s: &str) -> Option<(&'a str, &'a str)> {
        match self.find_str(s) {
            Some(position) => Some(self.slice_at(position)),
            None => None
        }
    }

    fn slice_literal(&self, expected: &str) -> Option<(&'a str, &'a str)> {
        if self.starts_with(expected) {
            Some(self.slice_at(expected.len()))
        } else {
            None
        }
    }

    fn slice_start_rest(&self,
                        is_first: |char| -> bool,
                        is_rest: |char| -> bool)
                        -> Option<(&'a str, &'a str)>
    {
        let mut positions = self.char_indices();

        match positions.next() {
            Some((_, c)) if is_first(c) => (),
            Some((_, _)) => return None,
            None => return None,
        };

        let mut positions = positions.skip_while(|&(_, c)| is_rest(c));
        match positions.next() {
            Some((offset, _)) => Some(self.slice_at(offset)),
            None => Some((self.clone(), "")),
        }
    }

    fn slice_name(&self) -> Option<(&'a str, &'a str)> {
        self.slice_start_rest(|c| c.is_name_start_char(), |c| c.is_name_char())
    }

    fn slice_space(&self) -> Option<(&'a str, &'a str)> {
        self.slice_start_rest(|c| c.is_space_char(), |c| c.is_space_char())
    }
}

trait XmlChar {
    fn is_name_start_char(&self) -> bool;
    fn is_name_char(&self) -> bool;
    fn is_space_char(&self) -> bool;
}

impl XmlChar for char {
    fn is_name_start_char(&self) -> bool {
        match *self {
            ':'                        |
            'A'..'Z'                   |
            '_'                        |
            'a'..'z'                   |
            '\U000000C0'..'\U000000D6' |
            '\U000000D8'..'\U000000F6' |
            '\U000000F8'..'\U000002FF' |
            '\U00000370'..'\U0000037D' |
            '\U0000037F'..'\U00001FFF' |
            '\U0000200C'..'\U0000200D' |
            '\U00002070'..'\U0000218F' |
            '\U00002C00'..'\U00002FEF' |
            '\U00003001'..'\U0000D7FF' |
            '\U0000F900'..'\U0000FDCF' |
            '\U0000FDF0'..'\U0000FFFD' |
            '\U00010000'..'\U000EFFFF' => true,
            _ => false,
        }
    }

    fn is_name_char(&self) -> bool {
        if self.is_name_start_char() { return true; }
        match *self {
            '-'                |
            '.'                |
            '0'..'9'           |
            '\u00B7'           |
            '\u0300'..'\u036F' |
            '\u203F'..'\u2040' => true,
            _ => false
        }
    }

    fn is_space_char(&self) -> bool {
        match *self {
            '\x20' |
            '\x09' |
            '\x0D' |
            '\x0A' => true,
            _ => false,
        }
    }
}

trait Hax {
    fn first_child(&self) -> Option<RootChild>;
}

impl Hax for Root {
    fn first_child(&self) -> Option<RootChild> {
        self.children().remove(0)
    }
}

trait Hax2 {
    fn first_child(&self) -> Option<ElementChild>;
}

impl Hax2 for Element {
    fn first_child(&self) -> Option<ElementChild> {
        self.children().remove(0)
    }
}

#[test]
fn parses_a_document_with_a_single_element() {
    let parser = Parser::new();
    let doc = parser.parse("<?xml version='1.0' ?><hello />");
    let top = doc.root().first_child().unwrap().element().unwrap();

    assert_eq!(top.name().as_slice(), "hello");
}

#[test]
fn parses_an_element_with_an_attribute() {
    let parser = Parser::new();
    let doc = parser.parse("<?xml version='1.0' ?><hello scope='world'/>");
    let top = doc.root().first_child().unwrap().element().unwrap();

    assert_eq!(top.get_attribute("scope").unwrap().as_slice(), "world");
}

#[test]
fn parses_an_element_with_an_attribute_using_double_quotes() {
    let parser = Parser::new();
    let doc = parser.parse("<?xml version='1.0' ?><hello scope=\"world\"/>");
    let top = doc.root().first_child().unwrap().element().unwrap();

    assert_eq!(top.get_attribute("scope").unwrap().as_slice(), "world");
}

#[test]
fn parses_an_element_with_multiple_attributes() {
    let parser = Parser::new();
    let doc = parser.parse("<?xml version='1.0' ?><hello scope=\"world\" happy='true'/>");
    let top = doc.root().first_child().unwrap().element().unwrap();

    assert_eq!(top.get_attribute("scope").unwrap().as_slice(), "world");
    assert_eq!(top.get_attribute("happy").unwrap().as_slice(), "true");
}

#[test]
fn parses_an_element_that_is_not_self_closing() {
    let parser = Parser::new();
    let doc = parser.parse("<?xml version='1.0' ?><hello></hello>");
    let top = doc.root().first_child().unwrap().element().unwrap();

    assert_eq!(top.name().as_slice(), "hello");
}

#[test]
fn parses_nested_elements() {
    let parser = Parser::new();
    let doc = parser.parse("<?xml version='1.0' ?><hello><world/></hello>");
    let nested = doc.root().first_child().unwrap().element().unwrap().first_child().unwrap().element().unwrap();

    assert_eq!(nested.name().as_slice(), "world");
}

#[test]
fn parses_multiply_nested_elements() {
    let parser = Parser::new();
    let doc = parser.parse("<?xml version='1.0' ?><hello><awesome><world/></awesome></hello>");
    let hello = doc.root().first_child().unwrap().element().unwrap();
    let awesome = hello.first_child().unwrap().element().unwrap();
    let world = awesome.first_child().unwrap().element().unwrap();

    assert_eq!(world.name().as_slice(), "world");
}

#[test]
fn parses_nested_elements_with_attributes() {
    let parser = Parser::new();
    let doc = parser.parse("<?xml version='1.0' ?><hello><world name='Earth'/></hello>");
    let hello = doc.root().first_child().unwrap().element().unwrap();
    let world = hello.first_child().unwrap().element().unwrap();

    assert_eq!(world.get_attribute("name").unwrap().as_slice(), "Earth");
}
<|endoftext|>