<commit_before>use std::borrow;
use std::cmp::Ordering;
use std::fmt;

#[cfg(feature = "object_sorted")]
use std::collections::BTreeMap;

#[cfg(not(any(feature = "object_sorted")))]
use std::collections::HashMap;

use super::Scalar;

#[cfg(feature = "object_sorted")]
type MapImpl<K, V> = BTreeMap<K, V>;

#[cfg(not(any(feature = "object_sorted")))]
type MapImpl<K, V> = HashMap<K, V>;

/// An enum to represent different value types
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Value {
    /// A scalar value.
    Scalar(Scalar),
    /// A sequence of `Value`s.
    Array(Array),
    /// A sequence of key/`Value` pairs.
    Object(Object),
    /// Nothing.
    Nil,
}

/// Type representing a Liquid array, payload of the `Value::Array` variant
pub type Array = Vec<Value>;

/// Type representing a Liquid object, payload of the `Value::Object` variant
pub type Object = MapImpl<borrow::Cow<'static, str>, Value>;

impl Value {
    /// Create as a `Scalar`.
    pub fn scalar<T: Into<Scalar>>(value: T) -> Self {
        Value::Scalar(Scalar::new(value))
    }

    /// Create as an `Array`.
    pub fn array<I: IntoIterator<Item = Self>>(iter: I) -> Self {
        let v: Array = iter.into_iter().collect();
        Value::Array(v)
    }

    /// Create as nothing.
    pub fn nil() -> Self {
        Value::Nil
    }

    /// Interpret as a string.
    pub fn to_str(&self) -> borrow::Cow<str> {
        match *self {
            Value::Scalar(ref x) => x.to_str(),
            Value::Array(ref x) => {
                let arr: Vec<String> = x.iter().map(|v| v.to_string()).collect();
                borrow::Cow::Owned(arr.join(", "))
            }
            Value::Object(ref x) => {
                let arr: Vec<String> = x.iter().map(|(k, v)| format!("{}: {}", k, v)).collect();
                borrow::Cow::Owned(arr.join(", "))
            }
            Value::Nil => borrow::Cow::Borrowed(""),
        }
    }

    /// Extracts the scalar value if it is a scalar.
    pub fn as_scalar(&self) -> Option<&Scalar> {
        match *self {
            Value::Scalar(ref s) => Some(s),
            _ => None,
        }
    }

    /// Extracts the scalar value if it is a scalar.
    pub fn into_scalar(self) -> Option<Scalar> {
        match self {
            Value::Scalar(s) => Some(s),
            _ => None,
        }
    }

    /// Tests whether this value is a scalar
    pub fn is_scalar(&self) -> bool {
        self.as_scalar().is_some()
    }

    /// Extracts the array value if it is an array.
    pub fn as_array(&self) -> Option<&Array> {
        match *self {
            Value::Array(ref s) => Some(s),
            _ => None,
        }
    }

    /// Extracts the array value if it is an array.
    pub fn as_array_mut(&mut self) -> Option<&mut Array> {
        match *self {
            Value::Array(ref mut s) => Some(s),
            _ => None,
        }
    }

    /// Extracts the array value if it is an array.
    pub fn into_array(self) -> Option<Array> {
        match self {
            Value::Array(s) => Some(s),
            _ => None,
        }
    }

    /// Tests whether this value is an array
    pub fn is_array(&self) -> bool {
        self.as_array().is_some()
    }

    /// Extracts the object value if it is a object.
    pub fn as_object(&self) -> Option<&Object> {
        match *self {
            Value::Object(ref s) => Some(s),
            _ => None,
        }
    }

    /// Extracts the object value if it is a object.
    pub fn as_object_mut(&mut self) -> Option<&mut Object> {
        match *self {
            Value::Object(ref mut s) => Some(s),
            _ => None,
        }
    }

    /// Extracts the object value if it is a object.
    pub fn into_object(self) -> Option<Object> {
        match self {
            Value::Object(s) => Some(s),
            _ => None,
        }
    }

    /// Tests whether this value is an object
    pub fn is_object(&self) -> bool {
        self.as_object().is_some()
    }

    /// Extracts the nil value if it is nil
    pub fn as_nil(&self) -> Option<()> {
        match *self {
            Value::Nil => Some(()),
            _ => None,
        }
    }

    /// Tests whether this value is nil
    pub fn is_nil(&self) -> bool {
        match *self {
            Value::Nil => true,
            _ => false,
        }
    }

    /// Evaluate using Liquid "truthiness"
    pub fn is_truthy(&self) -> bool {
        // encode Ruby truthiness: all values except false and nil are true
        match *self {
            Value::Scalar(ref x) => x.is_truthy(),
            Value::Nil => false,
            _ => true,
        }
    }

    /// Whether a default constructed value.
    pub fn is_default(&self) -> bool {
        match *self {
            Value::Scalar(ref x) => x.is_default(),
            Value::Nil => true,
            Value::Array(ref x) => x.is_empty(),
            Value::Object(ref x) => x.is_empty(),
        }
    }

    /// Report the data type (generally for error reporting).
    pub fn type_name(&self) -> &'static str {
        match *self {
            Value::Scalar(ref x) => x.type_name(),
            Value::Nil => "nil",
            Value::Array(_) => "array",
            Value::Object(_) => "object",
        }
    }

    /// Access a contained `Value`.
    pub fn contains_key(&self, index: &Scalar) -> bool {
        match *self {
            Value::Array(ref x) => {
                if let Some(index) = index.to_integer() {
                    let index = convert_index(index, x.len());
                    index < x.len()
                } else {
                    match &*index.to_str() {
                        "first" | "last" => true,
                        _ => false,
                    }
                }
            }
            Value::Object(ref x) => x.contains_key(index.to_str().as_ref()),
            _ => false,
        }
    }

    /// All keys
    pub fn keys(&self) -> Vec<Scalar> {
        match *self {
            Value::Array(ref x) => {
                let start: i32 = 0;
                let end = x.len() as i32;
                let mut keys: Vec<_> = (start..end).map(|i| Scalar::new(i)).collect();
                keys.push(Scalar::new("first"));
                keys.push(Scalar::new("last"));
                keys
            }
            Value::Object(ref x) => x.keys().map(|s| {
                match *s {
                    borrow::Cow::Borrowed(s) => Scalar::new(s),
                    borrow::Cow::Owned(ref s) => Scalar::new(s.to_owned()),
                }
            }).collect(),
            _ => vec![],
        }
    }

    /// Access a contained `Value`.
    pub fn get<'s>(&'s self, index: &Scalar) -> Option<&'s Self> {
        match *self {
            Value::Array(ref x) => {
                if let Some(index) = index.to_integer() {
                    let index = convert_index(index, x.len());
                    x.get(index as usize)
                } else {
                    match &*index.to_str() {
                        "first" => x.get(0),
                        "last" => x.get(x.len() - 1),
                        _ => None,
                    }
                }
            }
            Value::Object(ref x) => x.get(index.to_str().as_ref()),
            _ => None,
        }
    }
}

fn convert_index(index: i32, max_size: usize) -> usize {
    let index = index as isize;
    let max_size = max_size as isize;
    let index = if 0 <= index {
        index
    } else {
        max_size + index
    };
    index as usize
}

impl Default for Value {
    fn default() -> Self {
        Self::nil()
    }
}

impl PartialEq<Value> for Value {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (&Value::Scalar(ref x), &Value::Scalar(ref y)) => x == y,
            (&Value::Array(ref x), &Value::Array(ref y)) => x == y,
            (&Value::Object(ref x), &Value::Object(ref y)) => x == y,
            (&Value::Nil, &Value::Nil) => true,

            // encode Ruby truthiness: all values except false and nil are true
            (&Value::Nil, &Value::Scalar(ref b)) | (&Value::Scalar(ref b), &Value::Nil) => {
                !b.to_bool().unwrap_or(true)
            }
            (_, &Value::Scalar(ref b)) | (&Value::Scalar(ref b), _) => b.to_bool().unwrap_or(false),

            _ => false,
        }
    }
}

impl Eq for Value {}

impl PartialOrd<Value> for Value {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        match (self, other) {
            (&Value::Scalar(ref x), &Value::Scalar(ref y)) => x.partial_cmp(y),
            (&Value::Array(ref x), &Value::Array(ref y)) => x.iter().partial_cmp(y.iter()),
            (&Value::Object(ref x), &Value::Object(ref y)) => x.iter().partial_cmp(y.iter()),
            _ => None,
        }
    }
}

impl fmt::Display for Value {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let data = self.to_str();
        write!(f, "{}", data)
    }
}

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

    #[test]
    fn test_to_string_scalar() {
        let val = Value::scalar(42f64);
        assert_eq!(&val.to_string(), "42");
    }

    #[test]
    fn test_to_string_array() {
        let val = Value::Array(vec![
            Value::scalar(3f64),
            Value::scalar("test"),
            Value::scalar(5.3),
        ]);
        assert_eq!(&val.to_string(), "3, test, 5.3");
    }

    // TODO make a test for object, remember values are in arbitrary orders in HashMaps

    #[test]
    fn test_to_string_nil() {
        assert_eq!(&Value::nil().to_string(), "");
    }

    #[test]
    fn scalar_equality() {
        assert_eq!(Value::scalar("alpha"), Value::scalar("alpha"));
        assert_eq!(Value::scalar(""), Value::scalar(""));
        assert!(Value::scalar("alpha") != Value::scalar("beta"));
        assert!(Value::scalar("beta") != Value::scalar("alpha"));
    }

    #[test]
    fn scalars_have_ruby_truthiness() {
        // all strings in ruby are true
        assert_eq!(Value::scalar(true), Value::scalar("All strings are truthy"));
        assert_eq!(Value::scalar(true), Value::scalar(""));
        assert!(Value::scalar("").is_truthy());

        assert_eq!(Value::scalar(true), Value::scalar(true));
        assert!(Value::scalar(true) != Value::scalar(false));
    }

    #[test]
    fn array_equality() {
        let a = Value::Array(vec![Value::scalar("one"), Value::scalar("two")]);
        let b = Value::Array(vec![Value::scalar("alpha"), Value::scalar("beta")]);

        assert_eq!(a, a);
        assert!(a != b);
        assert!(b != a);
    }

    #[test]
    fn arrays_have_ruby_truthiness() {
        assert_eq!(Value::scalar(true), Value::Array(Vec::new()));
        assert!(Value::Array(Vec::new()).is_truthy());
    }

    #[test]
    fn object_equality() {
        let a: Object = [
            ("alpha".into(), Value::scalar("1")),
            ("beta".into(), Value::scalar(2f64)),
        ]
            .into_iter()
            .cloned()
            .collect();
        let a = Value::Object(a);

        let b: Object = [
            ("alpha".into(), Value::scalar("1")),
            ("beta".into(), Value::scalar(2f64)),
            ("gamma".into(), Value::Array(vec![])),
        ]
            .into_iter()
            .cloned()
            .collect();
        let b = Value::Object(b);

        assert_eq!(a, a);
        assert!(a != b);
        assert!(b != a);
    }

    #[test]
    fn objects_have_ruby_truthiness() {
        assert_eq!(Value::scalar(true), Value::Object(Object::new()));
        assert!(Value::Object(Object::new()).is_truthy());
    }

    #[test]
    fn nil_equality() {
        assert_eq!(Value::Nil, Value::Nil);
    }

    #[test]
    fn nils_have_ruby_truthiness() {
        assert_eq!(Value::scalar(false), Value::Nil);
        assert!(!Value::Nil.is_truthy());

        assert_eq!(Value::scalar(false), Value::Nil);
        assert!(Value::scalar(true) != Value::Nil);
        assert!(Value::scalar("") != Value::Nil);
    }
}
<commit_msg>refactor(value): Improve API stability<commit_after>use std::borrow;
use std::cmp::Ordering;
use std::fmt;

#[cfg(feature = "object_sorted")]
use std::collections::BTreeMap;

#[cfg(not(any(feature = "object_sorted")))]
use std::collections::HashMap;

use super::Scalar;

#[cfg(feature = "object_sorted")]
type MapImpl<K, V> = BTreeMap<K, V>;

#[cfg(not(any(feature = "object_sorted")))]
type MapImpl<K, V> = HashMap<K, V>;

/// An enum to represent different value types
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Value {
    /// A scalar value.
    Scalar(Scalar),
    /// A sequence of `Value`s.
    Array(Array),
    /// A sequence of key/`Value` pairs.
    Object(Object),
    /// Nothing.
    Nil,
}

/// Type representing a Liquid array, payload of the `Value::Array` variant
pub type Array = Vec<Value>;

/// Type representing a Liquid object, payload of the `Value::Object` variant
pub type Object = MapImpl<borrow::Cow<'static, str>, Value>;

impl Value {
    /// Create as a `Scalar`.
    pub fn scalar<T: Into<Scalar>>(value: T) -> Self {
        Value::Scalar(Scalar::new(value))
    }

    /// Create as an `Array`.
    pub fn array<I: IntoIterator<Item = Self>>(iter: I) -> Self {
        let v: Array = iter.into_iter().collect();
        Value::Array(v)
    }

    /// Create as nothing.
    pub fn nil() -> Self {
        Value::Nil
    }

    /// Interpret as a string.
    pub fn to_str(&self) -> borrow::Cow<str> {
        match *self {
            Value::Scalar(ref x) => x.to_str(),
            Value::Array(ref x) => {
                let arr: Vec<String> = x.iter().map(|v| v.to_string()).collect();
                borrow::Cow::Owned(arr.join(", "))
            }
            Value::Object(ref x) => {
                let arr: Vec<String> = x.iter().map(|(k, v)| format!("{}: {}", k, v)).collect();
                borrow::Cow::Owned(arr.join(", "))
            }
            Value::Nil => borrow::Cow::Borrowed(""),
        }
    }

    /// Extracts the scalar value if it is a scalar.
    pub fn as_scalar(&self) -> Option<&Scalar> {
        match *self {
            Value::Scalar(ref s) => Some(s),
            _ => None,
        }
    }

    /// Extracts the scalar value if it is a scalar.
    pub fn into_scalar(self) -> Option<Scalar> {
        match self {
            Value::Scalar(s) => Some(s),
            _ => None,
        }
    }

    /// Tests whether this value is a scalar
    pub fn is_scalar(&self) -> bool {
        self.as_scalar().is_some()
    }

    /// Extracts the array value if it is an array.
    pub fn as_array(&self) -> Option<&Array> {
        match *self {
            Value::Array(ref s) => Some(s),
            _ => None,
        }
    }

    /// Extracts the array value if it is an array.
    pub fn as_array_mut(&mut self) -> Option<&mut Array> {
        match *self {
            Value::Array(ref mut s) => Some(s),
            _ => None,
        }
    }

    /// Extracts the array value if it is an array.
    pub fn into_array(self) -> Option<Array> {
        match self {
            Value::Array(s) => Some(s),
            _ => None,
        }
    }

    /// Tests whether this value is an array
    pub fn is_array(&self) -> bool {
        self.as_array().is_some()
    }

    /// Extracts the object value if it is a object.
    pub fn as_object(&self) -> Option<&Object> {
        match *self {
            Value::Object(ref s) => Some(s),
            _ => None,
        }
    }

    /// Extracts the object value if it is a object.
    pub fn as_object_mut(&mut self) -> Option<&mut Object> {
        match *self {
            Value::Object(ref mut s) => Some(s),
            _ => None,
        }
    }

    /// Extracts the object value if it is a object.
    pub fn into_object(self) -> Option<Object> {
        match self {
            Value::Object(s) => Some(s),
            _ => None,
        }
    }

    /// Tests whether this value is an object
    pub fn is_object(&self) -> bool {
        self.as_object().is_some()
    }

    /// Extracts the nil value if it is nil
    pub fn as_nil(&self) -> Option<()> {
        match *self {
            Value::Nil => Some(()),
            _ => None,
        }
    }

    /// Tests whether this value is nil
    pub fn is_nil(&self) -> bool {
        match *self {
            Value::Nil => true,
            _ => false,
        }
    }

    /// Evaluate using Liquid "truthiness"
    pub fn is_truthy(&self) -> bool {
        // encode Ruby truthiness: all values except false and nil are true
        match *self {
            Value::Scalar(ref x) => x.is_truthy(),
            Value::Nil => false,
            _ => true,
        }
    }

    /// Whether a default constructed value.
    pub fn is_default(&self) -> bool {
        match *self {
            Value::Scalar(ref x) => x.is_default(),
            Value::Nil => true,
            Value::Array(ref x) => x.is_empty(),
            Value::Object(ref x) => x.is_empty(),
        }
    }

    /// Report the data type (generally for error reporting).
    pub fn type_name(&self) -> &'static str {
        match *self {
            Value::Scalar(ref x) => x.type_name(),
            Value::Nil => "nil",
            Value::Array(_) => "array",
            Value::Object(_) => "object",
        }
    }

    /// Access a contained `Value`.
    pub fn contains_key(&self, index: &Scalar) -> bool {
        match *self {
            Value::Array(ref x) => {
                if let Some(index) = index.to_integer() {
                    let index = convert_index(index, x.len());
                    index < x.len()
                } else {
                    match &*index.to_str() {
                        "first" | "last" => true,
                        _ => false,
                    }
                }
            }
            Value::Object(ref x) => x.contains_key(index.to_str().as_ref()),
            _ => false,
        }
    }

    /// Keys available for lookup.
    pub fn keys(&self) -> Keys {
        let v = match *self {
            Value::Array(ref x) => {
                let start: i32 = 0;
                let end = x.len() as i32;
                let mut keys: Vec<_> = (start..end).map(|i| Scalar::new(i)).collect();
                keys.push(Scalar::new("first"));
                keys.push(Scalar::new("last"));
                keys
            }
            Value::Object(ref x) => x.keys().map(|s| {
                match *s {
                    borrow::Cow::Borrowed(s) => Scalar::new(s),
                    borrow::Cow::Owned(ref s) => Scalar::new(s.to_owned()),
                }
            }).collect(),
            _ => vec![],
        };
        Keys(v.into_iter())
    }

    /// Access a contained `Value`.
    pub fn get<'s>(&'s self, index: &Scalar) -> Option<&'s Self> {
        match *self {
            Value::Array(ref x) => {
                if let Some(index) = index.to_integer() {
                    let index = convert_index(index, x.len());
                    x.get(index as usize)
                } else {
                    match &*index.to_str() {
                        "first" => x.get(0),
                        "last" => x.get(x.len() - 1),
                        _ => None,
                    }
                }
            }
            Value::Object(ref x) => x.get(index.to_str().as_ref()),
            _ => None,
        }
    }
}

/// Iterator over a `Value`s keys.
#[derive(Debug)]
pub struct Keys(::std::vec::IntoIter<Scalar>);

impl Iterator for Keys {
    type Item = Scalar;

    #[inline]
    fn next(&mut self) -> Option<Scalar> {
        self.0.next()
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.0.size_hint()
    }

    #[inline]
    fn count(self) -> usize {
        self.0.count()
    }
}

impl ExactSizeIterator for Keys {
    #[inline]
    fn len(&self) -> usize {
        self.0.len()
    }
}

fn convert_index(index: i32, max_size: usize) -> usize {
    let index = index as isize;
    let max_size = max_size as isize;
    let index = if 0 <= index {
        index
    } else {
        max_size + index
    };
    index as usize
}

impl Default for Value {
    fn default() -> Self {
        Self::nil()
    }
}

impl PartialEq<Value> for Value {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (&Value::Scalar(ref x), &Value::Scalar(ref y)) => x == y,
            (&Value::Array(ref x), &Value::Array(ref y)) => x == y,
            (&Value::Object(ref x), &Value::Object(ref y)) => x == y,
            (&Value::Nil, &Value::Nil) => true,

            // encode Ruby truthiness: all values except false and nil are true
            (&Value::Nil, &Value::Scalar(ref b)) | (&Value::Scalar(ref b), &Value::Nil) => {
                !b.to_bool().unwrap_or(true)
            }
            (_, &Value::Scalar(ref b)) | (&Value::Scalar(ref b), _) => b.to_bool().unwrap_or(false),

            _ => false,
        }
    }
}

impl Eq for Value {}

impl PartialOrd<Value> for Value {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        match (self, other) {
            (&Value::Scalar(ref x), &Value::Scalar(ref y)) => x.partial_cmp(y),
            (&Value::Array(ref x), &Value::Array(ref y)) => x.iter().partial_cmp(y.iter()),
            (&Value::Object(ref x), &Value::Object(ref y)) => x.iter().partial_cmp(y.iter()),
            _ => None,
        }
    }
}

impl fmt::Display for Value {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let data = self.to_str();
        write!(f, "{}", data)
    }
}

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

    #[test]
    fn test_to_string_scalar() {
        let val = Value::scalar(42f64);
        assert_eq!(&val.to_string(), "42");
    }

    #[test]
    fn test_to_string_array() {
        let val = Value::Array(vec![
            Value::scalar(3f64),
            Value::scalar("test"),
            Value::scalar(5.3),
        ]);
        assert_eq!(&val.to_string(), "3, test, 5.3");
    }

    // TODO make a test for object, remember values are in arbitrary orders in HashMaps

    #[test]
    fn test_to_string_nil() {
        assert_eq!(&Value::nil().to_string(), "");
    }

    #[test]
    fn scalar_equality() {
        assert_eq!(Value::scalar("alpha"), Value::scalar("alpha"));
        assert_eq!(Value::scalar(""), Value::scalar(""));
        assert!(Value::scalar("alpha") != Value::scalar("beta"));
        assert!(Value::scalar("beta") != Value::scalar("alpha"));
    }

    #[test]
    fn scalars_have_ruby_truthiness() {
        // all strings in ruby are true
        assert_eq!(Value::scalar(true), Value::scalar("All strings are truthy"));
        assert_eq!(Value::scalar(true), Value::scalar(""));
        assert!(Value::scalar("").is_truthy());

        assert_eq!(Value::scalar(true), Value::scalar(true));
        assert!(Value::scalar(true) != Value::scalar(false));
    }

    #[test]
    fn array_equality() {
        let a = Value::Array(vec![Value::scalar("one"), Value::scalar("two")]);
        let b = Value::Array(vec![Value::scalar("alpha"), Value::scalar("beta")]);

        assert_eq!(a, a);
        assert!(a != b);
        assert!(b != a);
    }

    #[test]
    fn arrays_have_ruby_truthiness() {
        assert_eq!(Value::scalar(true), Value::Array(Vec::new()));
        assert!(Value::Array(Vec::new()).is_truthy());
    }

    #[test]
    fn object_equality() {
        let a: Object = [
            ("alpha".into(), Value::scalar("1")),
            ("beta".into(), Value::scalar(2f64)),
        ]
            .into_iter()
            .cloned()
            .collect();
        let a = Value::Object(a);

        let b: Object = [
            ("alpha".into(), Value::scalar("1")),
            ("beta".into(), Value::scalar(2f64)),
            ("gamma".into(), Value::Array(vec![])),
        ]
            .into_iter()
            .cloned()
            .collect();
        let b = Value::Object(b);

        assert_eq!(a, a);
        assert!(a != b);
        assert!(b != a);
    }

    #[test]
    fn objects_have_ruby_truthiness() {
        assert_eq!(Value::scalar(true), Value::Object(Object::new()));
        assert!(Value::Object(Object::new()).is_truthy());
    }

    #[test]
    fn nil_equality() {
        assert_eq!(Value::Nil, Value::Nil);
    }

    #[test]
    fn nils_have_ruby_truthiness() {
        assert_eq!(Value::scalar(false), Value::Nil);
        assert!(!Value::Nil.is_truthy());

        assert_eq!(Value::scalar(false), Value::Nil);
        assert!(Value::scalar(true) != Value::Nil);
        assert!(Value::scalar("") != Value::Nil);
    }
}
<|endoftext|>


<commit_before>use rand::Rng;
use rand::distributions::{Sample, IndependentSample};
use result::Result;
use super::{Binomial, Distribution, Univariate, Discrete};

/// Implements the [Bernoulli](https://en.wikipedia.org/wiki/Bernoulli_distribution)
/// distribution which is a special case of the [Binomial](https://en.wikipedia.org/wiki/Binomial_distribution)
/// distribution where `n = 1`
///
/// # Examples
///
/// ```
/// use statrs::distribution::{Bernoulli, Univariate, Discrete};
///
/// let n = Bernoulli::new(0.5).unwrap();
/// assert_eq!(n.mean(), 0.5);
/// assert_eq!(n.pmf(0), 0.5);
/// assert_eq!(n.pmf(1), 0.5);
/// assert_eq!(n.pmf(2), 0.0);
/// ```
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Bernoulli {
    b: Binomial,
}

impl Bernoulli {
    /// Constructs a new Bernoulli distribution with
    /// the given `p` probability of success.
    ///
    /// # Errors
    ///
    /// Returns an error if `p` is `NaN, less than `0`
    /// or greater than `1`
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Bernoulli;
    ///
    /// let mut result = Bernoulli::new(0.5);
    /// assert!(result.is_ok());
    ///
    /// result = Bernoulli::new(-0.5);
    /// assert!(result.is_err());
    /// ```
    pub fn new(p: f64) -> Result<Bernoulli> {
        Binomial::new(p, 1).map(|b| Bernoulli { b: b })
    }

    /// Returns the probability of success `p` of the
    /// Bernoulli distribution.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Bernoulli;
    ///
    /// let n = Bernoulli::new(0.5).unwrap();
    /// assert_eq!(n.p(), 0.5);
    /// ```
    pub fn p(&self) -> f64 {
        self.b.p()
    }

    /// Returns the number of trials `n` of the
    /// Bernoulli distribution. Will always be `1.0`.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Bernoulli;
    ///
    /// let n = Bernoulli::new(0.5).unwrap();
    /// assert_eq!(n.n(), 1.0);
    /// ```
    pub fn n(&self) -> f64 {
        1.0
    }
}

impl Sample<f64> for Bernoulli {
    fn sample<R: Rng>(&mut self, r: &mut R) -> f64 {
        super::Distribution::sample(self, r)
    }
}

impl IndependentSample<f64> for Bernoulli {
    fn ind_sample<R: Rng>(&self, r: &mut R) -> f64 {
        super::Distribution::sample(self, r)
    }
}

impl Distribution for Bernoulli {
    fn sample<R: Rng>(&self, r: &mut R) -> f64 {
        self.b.sample(r)
    }
}

impl Univariate for Bernoulli {
    fn mean(&self) -> f64 {
        self.b.mean()
    }

    fn variance(&self) -> f64 {
        self.b.variance()
    }

    fn std_dev(&self) -> f64 {
        self.b.std_dev()
    }

    fn entropy(&self) -> f64 {
        self.b.entropy()
    }

    fn skewness(&self) -> f64 {
        self.b.skewness()
    }

    fn median(&self) -> f64 {
        self.b.median()
    }

    fn cdf(&self, x: f64) -> f64 {
        self.b.cdf(x)
    }
}

impl Discrete for Bernoulli {
    fn mode(&self) -> i64 {
        self.b.mode()
    }

    fn min(&self) -> i64 {
        0
    }

    fn max(&self) -> i64 {
        1
    }

    fn pmf(&self, x: i64) -> f64 {
        self.b.pmf(x)
    }

    fn ln_pmf(&self, x: i64) -> f64 {
        self.b.ln_pmf(x)
    }
}
<commit_msg>update bernoulli docs<commit_after>use rand::Rng;
use rand::distributions::{Sample, IndependentSample};
use result::Result;
use super::{Binomial, Distribution, Univariate, Discrete};

/// Implements the [Bernoulli](https://en.wikipedia.org/wiki/Bernoulli_distribution)
/// distribution which is a special case of the [Binomial](https://en.wikipedia.org/wiki/Binomial_distribution)
/// distribution where `n = 1`
///
/// # Examples
///
/// ```
/// use statrs::distribution::{Bernoulli, Univariate, Discrete};
///
/// let n = Bernoulli::new(0.5).unwrap();
/// assert_eq!(n.mean(), 0.5);
/// assert_eq!(n.pmf(0), 0.5);
/// assert_eq!(n.pmf(1), 0.5);
/// assert_eq!(n.pmf(2), 0.0);
/// ```
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Bernoulli {
    b: Binomial,
}

impl Bernoulli {
    /// Constructs a new Bernoulli distribution with
    /// the given `p` probability of success.
    ///
    /// # Errors
    ///
    /// Returns an error if `p` is `NaN, less than `0`
    /// or greater than `1`
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Bernoulli;
    ///
    /// let mut result = Bernoulli::new(0.5);
    /// assert!(result.is_ok());
    ///
    /// result = Bernoulli::new(-0.5);
    /// assert!(result.is_err());
    /// ```
    pub fn new(p: f64) -> Result<Bernoulli> {
        Binomial::new(p, 1).map(|b| Bernoulli { b: b })
    }

    /// Returns the probability of success `p` of the
    /// Bernoulli distribution.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Bernoulli;
    ///
    /// let n = Bernoulli::new(0.5).unwrap();
    /// assert_eq!(n.p(), 0.5);
    /// ```
    pub fn p(&self) -> f64 {
        self.b.p()
    }

    /// Returns the number of trials `n` of the
    /// Bernoulli distribution. Will always be `1.0`.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Bernoulli;
    ///
    /// let n = Bernoulli::new(0.5).unwrap();
    /// assert_eq!(n.n(), 1.0);
    /// ```
    pub fn n(&self) -> f64 {
        1.0
    }
}

impl Sample<f64> for Bernoulli {
    fn sample<R: Rng>(&mut self, r: &mut R) -> f64 {
        super::Distribution::sample(self, r)
    }
}

impl IndependentSample<f64> for Bernoulli {
    fn ind_sample<R: Rng>(&self, r: &mut R) -> f64 {
        super::Distribution::sample(self, r)
    }
}

impl Distribution for Bernoulli {
    /// Draws and returns a random sample from the
    /// Bernoulli distribution where the returned
    /// values are `1` with probability `p` and `0`
    /// with probability `1-p`.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate rand;
    /// # extern crate statrs;
    ///
    /// use rand::StdRng;
    /// use statrs::distribution::{Bernoulli, Distribution};
    ///
    /// # fn main() {
    /// let mut r = rand::StdRng::new().unwrap();
    /// let n = Bernoulli::new(0.5).unwrap();
    /// print!("{}", n.sample::<StdRng>(&mut r));
    /// # }
    /// ```
    fn sample<R: Rng>(&self, r: &mut R) -> f64 {
        self.b.sample(r)
    }
}

impl Univariate for Bernoulli {
    /// Returns the mean of the Bernoulli
    /// distribution
    fn mean(&self) -> f64 {
        self.b.mean()
    }

    /// Returns the variance of the Bernoulli
    /// distribution
    fn variance(&self) -> f64 {
        self.b.variance()
    }

    /// Returns the standard deviation of the
    /// Bernoulli distribution
    fn std_dev(&self) -> f64 {
        self.b.std_dev()
    }

    /// Returns the entropy of the Bernoulli
    /// distribution
    fn entropy(&self) -> f64 {
        self.b.entropy()
    }

    /// Returns the skewness of the Bernoulli
    /// distribution
    fn skewness(&self) -> f64 {
        self.b.skewness()
    }

    /// Returns the median of the Bernoulli
    /// distribution
    fn median(&self) -> f64 {
        self.b.median()
    }

    /// Calculates and returns the cumulative distribution
    /// function for the Bernoulli distribution at `x`.
    ///
    /// # Remarks
    ///
    /// Returns `0.0` if `x < 0.0` and `1.0` if `x >= 1.0`
    fn cdf(&self, x: f64) -> f64 {
        self.b.cdf(x)
    }
}

impl Discrete for Bernoulli {
    fn mode(&self) -> i64 {
        self.b.mode()
    }

    fn min(&self) -> i64 {
        0
    }

    fn max(&self) -> i64 {
        1
    }

    fn pmf(&self, x: i64) -> f64 {
        self.b.pmf(x)
    }

    fn ln_pmf(&self, x: i64) -> f64 {
        self.b.ln_pmf(x)
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use kvm_sys::*;

/// A capability the kernel's KVM interface can possibly expose.
#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(u32)]
pub enum Cap {
    Irqchip = KVM_CAP_IRQCHIP,
    Hlt = KVM_CAP_HLT,
    MmuShadowCacheControl = KVM_CAP_MMU_SHADOW_CACHE_CONTROL,
    UserMemory = KVM_CAP_USER_MEMORY,
    SetTssAddr = KVM_CAP_SET_TSS_ADDR,
    Vapic = KVM_CAP_VAPIC,
    ExtCpuid = KVM_CAP_EXT_CPUID,
    Clocksource = KVM_CAP_CLOCKSOURCE,
    NrVcpus = KVM_CAP_NR_VCPUS,
    NrMemslots = KVM_CAP_NR_MEMSLOTS,
    Pit = KVM_CAP_PIT,
    NopIoDelay = KVM_CAP_NOP_IO_DELAY,
    PvMmu = KVM_CAP_PV_MMU,
    MpState = KVM_CAP_MP_STATE,
    CoalescedMmio = KVM_CAP_COALESCED_MMIO,
    SyncMmu = KVM_CAP_SYNC_MMU,
    Iommu = KVM_CAP_IOMMU,
    DestroyMemoryRegionWorks = KVM_CAP_DESTROY_MEMORY_REGION_WORKS,
    UserNmi = KVM_CAP_USER_NMI,
    SetGuestDebug = KVM_CAP_SET_GUEST_DEBUG,
    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
    ReinjectControl = KVM_CAP_REINJECT_CONTROL,
    IrqRouting = KVM_CAP_IRQ_ROUTING,
    IrqInjectStatus = KVM_CAP_IRQ_INJECT_STATUS,
    AssignDevIrq = KVM_CAP_ASSIGN_DEV_IRQ,
    JoinMemoryRegionsWorks = KVM_CAP_JOIN_MEMORY_REGIONS_WORKS,
    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] Mce = KVM_CAP_MCE,
    Irqfd = KVM_CAP_IRQFD,
    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] Pit2 = KVM_CAP_PIT2,
    SetBootCpuId = KVM_CAP_SET_BOOT_CPU_ID,
    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] PitState2 = KVM_CAP_PIT_STATE2,
    Ioeventfd = KVM_CAP_IOEVENTFD,
    SetIdentityMapAddr = KVM_CAP_SET_IDENTITY_MAP_ADDR,
    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] XenHvm = KVM_CAP_XEN_HVM,
    AdjustClock = KVM_CAP_ADJUST_CLOCK,
    InternalErrorData = KVM_CAP_INTERNAL_ERROR_DATA,
    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] VcpuEvents = KVM_CAP_VCPU_EVENTS,
    S390Psw = KVM_CAP_S390_PSW,
    PpcSegstate = KVM_CAP_PPC_SEGSTATE,
    Hyperv = KVM_CAP_HYPERV,
    HypervVapic = KVM_CAP_HYPERV_VAPIC,
    HypervSpin = KVM_CAP_HYPERV_SPIN,
    PciSegment = KVM_CAP_PCI_SEGMENT,
    PpcPairedSingles = KVM_CAP_PPC_PAIRED_SINGLES,
    IntrShadow = KVM_CAP_INTR_SHADOW,
    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] Debugregs = KVM_CAP_DEBUGREGS,
    X86RobustSinglestep = KVM_CAP_X86_ROBUST_SINGLESTEP,
    PpcOsi = KVM_CAP_PPC_OSI,
    PpcUnsetIrq = KVM_CAP_PPC_UNSET_IRQ,
    EnableCap = KVM_CAP_ENABLE_CAP,
    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] Xsave = KVM_CAP_XSAVE,
    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] Xcrs = KVM_CAP_XCRS,
    PpcGetPvinfo = KVM_CAP_PPC_GET_PVINFO,
    PpcIrqLevel = KVM_CAP_PPC_IRQ_LEVEL,
    AsyncPf = KVM_CAP_ASYNC_PF,
    TscControl = KVM_CAP_TSC_CONTROL,
    GetTscKhz = KVM_CAP_GET_TSC_KHZ,
    PpcBookeSregs = KVM_CAP_PPC_BOOKE_SREGS,
    SpaprTce = KVM_CAP_SPAPR_TCE,
    PpcSmt = KVM_CAP_PPC_SMT,
    PpcRma = KVM_CAP_PPC_RMA,
    MaxVcpus = KVM_CAP_MAX_VCPUS,
    PpcHior = KVM_CAP_PPC_HIOR,
    PpcPapr = KVM_CAP_PPC_PAPR,
    SwTlb = KVM_CAP_SW_TLB,
    OneReg = KVM_CAP_ONE_REG,
    S390Gmap = KVM_CAP_S390_GMAP,
    TscDeadlineTimer = KVM_CAP_TSC_DEADLINE_TIMER,
    S390Ucontrol = KVM_CAP_S390_UCONTROL,
    SyncRegs = KVM_CAP_SYNC_REGS,
    Pci23 = KVM_CAP_PCI_2_3,
    KvmclockCtrl = KVM_CAP_KVMCLOCK_CTRL,
    SignalMsi = KVM_CAP_SIGNAL_MSI,
    PpcGetSmmuInfo = KVM_CAP_PPC_GET_SMMU_INFO,
    S390Cow = KVM_CAP_S390_COW,
    PpcAllocHtab = KVM_CAP_PPC_ALLOC_HTAB,
    ReadonlyMem = KVM_CAP_READONLY_MEM,
    IrqfdResample = KVM_CAP_IRQFD_RESAMPLE,
    PpcBookeWatchdog = KVM_CAP_PPC_BOOKE_WATCHDOG,
    PpcHtabFd = KVM_CAP_PPC_HTAB_FD,
    S390CssSupport = KVM_CAP_S390_CSS_SUPPORT,
    PpcEpr = KVM_CAP_PPC_EPR,
    ArmPsci = KVM_CAP_ARM_PSCI,
    ArmSetDeviceAddr = KVM_CAP_ARM_SET_DEVICE_ADDR,
    DeviceCtrl = KVM_CAP_DEVICE_CTRL,
    IrqMpic = KVM_CAP_IRQ_MPIC,
    PpcRtas = KVM_CAP_PPC_RTAS,
    IrqXics = KVM_CAP_IRQ_XICS,
    ArmEl132bit = KVM_CAP_ARM_EL1_32BIT,
    SpaprMultitce = KVM_CAP_SPAPR_MULTITCE,
    ExtEmulCpuid = KVM_CAP_EXT_EMUL_CPUID,
    HypervTime = KVM_CAP_HYPERV_TIME,
    IoapicPolarityIgnored = KVM_CAP_IOAPIC_POLARITY_IGNORED,
    EnableCapVm = KVM_CAP_ENABLE_CAP_VM,
    S390Irqchip = KVM_CAP_S390_IRQCHIP,
    IoeventfdNoLength = KVM_CAP_IOEVENTFD_NO_LENGTH,
    VmAttributes = KVM_CAP_VM_ATTRIBUTES,
    ArmPsci02 = KVM_CAP_ARM_PSCI_0_2,
    PpcFixupHcall = KVM_CAP_PPC_FIXUP_HCALL,
    PpcEnableHcall = KVM_CAP_PPC_ENABLE_HCALL,
    CheckExtensionVm = KVM_CAP_CHECK_EXTENSION_VM,
    S390UserSigp = KVM_CAP_S390_USER_SIGP,
}
<commit_msg>kvm: remove Clone, Copy, Debug & PartialEq trait impl as they are not used<commit_after>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use kvm_sys::*;

/// A capability the kernel's KVM interface can possibly expose.
#[repr(u32)]
pub enum Cap {
    Irqchip = KVM_CAP_IRQCHIP,
    Hlt = KVM_CAP_HLT,
    MmuShadowCacheControl = KVM_CAP_MMU_SHADOW_CACHE_CONTROL,
    UserMemory = KVM_CAP_USER_MEMORY,
    SetTssAddr = KVM_CAP_SET_TSS_ADDR,
    Vapic = KVM_CAP_VAPIC,
    ExtCpuid = KVM_CAP_EXT_CPUID,
    Clocksource = KVM_CAP_CLOCKSOURCE,
    NrVcpus = KVM_CAP_NR_VCPUS,
    NrMemslots = KVM_CAP_NR_MEMSLOTS,
    Pit = KVM_CAP_PIT,
    NopIoDelay = KVM_CAP_NOP_IO_DELAY,
    PvMmu = KVM_CAP_PV_MMU,
    MpState = KVM_CAP_MP_STATE,
    CoalescedMmio = KVM_CAP_COALESCED_MMIO,
    SyncMmu = KVM_CAP_SYNC_MMU,
    Iommu = KVM_CAP_IOMMU,
    DestroyMemoryRegionWorks = KVM_CAP_DESTROY_MEMORY_REGION_WORKS,
    UserNmi = KVM_CAP_USER_NMI,
    SetGuestDebug = KVM_CAP_SET_GUEST_DEBUG,
    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
    ReinjectControl = KVM_CAP_REINJECT_CONTROL,
    IrqRouting = KVM_CAP_IRQ_ROUTING,
    IrqInjectStatus = KVM_CAP_IRQ_INJECT_STATUS,
    AssignDevIrq = KVM_CAP_ASSIGN_DEV_IRQ,
    JoinMemoryRegionsWorks = KVM_CAP_JOIN_MEMORY_REGIONS_WORKS,
    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] Mce = KVM_CAP_MCE,
    Irqfd = KVM_CAP_IRQFD,
    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] Pit2 = KVM_CAP_PIT2,
    SetBootCpuId = KVM_CAP_SET_BOOT_CPU_ID,
    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] PitState2 = KVM_CAP_PIT_STATE2,
    Ioeventfd = KVM_CAP_IOEVENTFD,
    SetIdentityMapAddr = KVM_CAP_SET_IDENTITY_MAP_ADDR,
    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] XenHvm = KVM_CAP_XEN_HVM,
    AdjustClock = KVM_CAP_ADJUST_CLOCK,
    InternalErrorData = KVM_CAP_INTERNAL_ERROR_DATA,
    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] VcpuEvents = KVM_CAP_VCPU_EVENTS,
    S390Psw = KVM_CAP_S390_PSW,
    PpcSegstate = KVM_CAP_PPC_SEGSTATE,
    Hyperv = KVM_CAP_HYPERV,
    HypervVapic = KVM_CAP_HYPERV_VAPIC,
    HypervSpin = KVM_CAP_HYPERV_SPIN,
    PciSegment = KVM_CAP_PCI_SEGMENT,
    PpcPairedSingles = KVM_CAP_PPC_PAIRED_SINGLES,
    IntrShadow = KVM_CAP_INTR_SHADOW,
    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] Debugregs = KVM_CAP_DEBUGREGS,
    X86RobustSinglestep = KVM_CAP_X86_ROBUST_SINGLESTEP,
    PpcOsi = KVM_CAP_PPC_OSI,
    PpcUnsetIrq = KVM_CAP_PPC_UNSET_IRQ,
    EnableCap = KVM_CAP_ENABLE_CAP,
    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] Xsave = KVM_CAP_XSAVE,
    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] Xcrs = KVM_CAP_XCRS,
    PpcGetPvinfo = KVM_CAP_PPC_GET_PVINFO,
    PpcIrqLevel = KVM_CAP_PPC_IRQ_LEVEL,
    AsyncPf = KVM_CAP_ASYNC_PF,
    TscControl = KVM_CAP_TSC_CONTROL,
    GetTscKhz = KVM_CAP_GET_TSC_KHZ,
    PpcBookeSregs = KVM_CAP_PPC_BOOKE_SREGS,
    SpaprTce = KVM_CAP_SPAPR_TCE,
    PpcSmt = KVM_CAP_PPC_SMT,
    PpcRma = KVM_CAP_PPC_RMA,
    MaxVcpus = KVM_CAP_MAX_VCPUS,
    PpcHior = KVM_CAP_PPC_HIOR,
    PpcPapr = KVM_CAP_PPC_PAPR,
    SwTlb = KVM_CAP_SW_TLB,
    OneReg = KVM_CAP_ONE_REG,
    S390Gmap = KVM_CAP_S390_GMAP,
    TscDeadlineTimer = KVM_CAP_TSC_DEADLINE_TIMER,
    S390Ucontrol = KVM_CAP_S390_UCONTROL,
    SyncRegs = KVM_CAP_SYNC_REGS,
    Pci23 = KVM_CAP_PCI_2_3,
    KvmclockCtrl = KVM_CAP_KVMCLOCK_CTRL,
    SignalMsi = KVM_CAP_SIGNAL_MSI,
    PpcGetSmmuInfo = KVM_CAP_PPC_GET_SMMU_INFO,
    S390Cow = KVM_CAP_S390_COW,
    PpcAllocHtab = KVM_CAP_PPC_ALLOC_HTAB,
    ReadonlyMem = KVM_CAP_READONLY_MEM,
    IrqfdResample = KVM_CAP_IRQFD_RESAMPLE,
    PpcBookeWatchdog = KVM_CAP_PPC_BOOKE_WATCHDOG,
    PpcHtabFd = KVM_CAP_PPC_HTAB_FD,
    S390CssSupport = KVM_CAP_S390_CSS_SUPPORT,
    PpcEpr = KVM_CAP_PPC_EPR,
    ArmPsci = KVM_CAP_ARM_PSCI,
    ArmSetDeviceAddr = KVM_CAP_ARM_SET_DEVICE_ADDR,
    DeviceCtrl = KVM_CAP_DEVICE_CTRL,
    IrqMpic = KVM_CAP_IRQ_MPIC,
    PpcRtas = KVM_CAP_PPC_RTAS,
    IrqXics = KVM_CAP_IRQ_XICS,
    ArmEl132bit = KVM_CAP_ARM_EL1_32BIT,
    SpaprMultitce = KVM_CAP_SPAPR_MULTITCE,
    ExtEmulCpuid = KVM_CAP_EXT_EMUL_CPUID,
    HypervTime = KVM_CAP_HYPERV_TIME,
    IoapicPolarityIgnored = KVM_CAP_IOAPIC_POLARITY_IGNORED,
    EnableCapVm = KVM_CAP_ENABLE_CAP_VM,
    S390Irqchip = KVM_CAP_S390_IRQCHIP,
    IoeventfdNoLength = KVM_CAP_IOEVENTFD_NO_LENGTH,
    VmAttributes = KVM_CAP_VM_ATTRIBUTES,
    ArmPsci02 = KVM_CAP_ARM_PSCI_0_2,
    PpcFixupHcall = KVM_CAP_PPC_FIXUP_HCALL,
    PpcEnableHcall = KVM_CAP_PPC_ENABLE_HCALL,
    CheckExtensionVm = KVM_CAP_CHECK_EXTENSION_VM,
    S390UserSigp = KVM_CAP_S390_USER_SIGP,
}
<|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/. */

pub use self::interface::{QuirksMode, Quirks, LimitedQuirks, NoQuirks};
pub use self::interface::TreeSink;

use tokenizer;
use tokenizer::{Doctype, Attribute, StartTag, EndTag, Tag};
use tokenizer::TokenSink;
use tokenizer::states::{RawData, RawKind, Rcdata, Rawtext, ScriptData};

use util::atom::Atom;
use util::namespace::HTML;
use util::str::{is_ascii_whitespace, Runs};

use std::default::Default;
use std::mem::replace;

mod interface;
mod states;
mod data;

/// We mostly only work with these tokens. Everything else is handled
/// specially at the beginning of `process_token`.
#[deriving(Eq, TotalEq, Clone, Show)]
enum Token {
    TagToken(Tag),
    CommentToken(StrBuf),
    CharacterTokens(bool, StrBuf),
    EOFToken,
}

/// Tree builder options, with an impl for Default.
#[deriving(Clone)]
pub struct TreeBuilderOpts {
    /// Is scripting enabled?
    pub scripting_enabled: bool,

    /// Is this an iframe srcdoc document?
    pub iframe_srcdoc: bool,

    /// Are we parsing a HTML fragment?
    pub fragment: bool,
}

impl Default for TreeBuilderOpts {
    fn default() -> TreeBuilderOpts {
        TreeBuilderOpts {
            scripting_enabled: true,
            iframe_srcdoc: false,
            fragment: false,
        }
    }
}

pub struct TreeBuilder<'sink, Handle, Sink> {
    /// Options controlling the behavior of the tree builder.
    opts: TreeBuilderOpts,

    /// Consumer of tree modifications.
    sink: &'sink mut Sink,

    /// Insertion mode.
    mode: states::InsertionMode,

    /// Original insertion mode, used by Text and InTableText modes.
    orig_mode: Option<states::InsertionMode>,

    /// The document node, which is created by the sink.
    doc_handle: Handle,

    /// Stack of open elements, most recently added at end.
    open_elems: Vec<Handle>,

    /// Head element pointer.
    head_elem: Option<Handle>,

    /// Next state change for the tokenizer, if any.
    next_tokenizer_state: Option<tokenizer::states::State>,
}

// We use guards, so we can't bind tags by move.  Instead, bind by ref
// mut and take attrs with `replace`.  This is basically fine since
// empty `Vec` doesn't allocate.
fn take_attrs(t: &mut Tag) -> Vec<Attribute> {
    replace(&mut t.attrs, vec!())
}

enum ProcessResult {
    Done,
    Reprocess(states::InsertionMode, Token),
}

macro_rules! tag_pattern (
    ($kind:ident     $var:ident) => ( TagToken(ref     $var @ Tag { kind: $kind, ..}) );
    ($kind:ident mut $var:ident) => ( TagToken(ref mut $var @ Tag { kind: $kind, ..}) );
)

macro_rules! start ( ($($args:tt)*) => ( tag_pattern!(StartTag $($args)*) ))
macro_rules! end   ( ($($args:tt)*) => ( tag_pattern!(EndTag   $($args)*) ))

macro_rules! named ( ($t:expr, $($atom:ident)*) => (
    match_atom!($t.name { $($atom)* => true, _ => false })
))

macro_rules! kind_named ( ($kind:ident $t:expr, $($atom:ident)*) => (
    match $t {
        tag_pattern!($kind t) => named!(t, $($atom)*),
        _ => false,
    }
))

macro_rules! start_named ( ($($args:tt)*) => ( kind_named!(StartTag $($args)*) ))
macro_rules! end_named   ( ($($args:tt)*) => ( kind_named!(EndTag   $($args)*) ))

impl<'sink, Handle: Clone, Sink: TreeSink<Handle>> TreeBuilder<'sink, Handle, Sink> {
    pub fn new(sink: &'sink mut Sink, opts: TreeBuilderOpts) -> TreeBuilder<'sink, Handle, Sink> {
        let doc_handle = sink.get_document();
        TreeBuilder {
            opts: opts,
            sink: sink,
            mode: states::Initial,
            orig_mode: None,
            doc_handle: doc_handle,
            open_elems: vec!(),
            head_elem: None,
            next_tokenizer_state: None,
        }
    }

    // Switch to `Text` insertion mode, save the old mode, and
    // switch the tokenizer to a raw-data state.
    // The latter only takes effect after the current / next
    // `process_token` of a start tag returns!
    fn parse_raw_data(&mut self, k: RawKind) {
        assert!(self.next_tokenizer_state.is_none());
        self.next_tokenizer_state = Some(RawData(k));
        self.orig_mode = Some(self.mode);
        self.mode = states::Text;
    }

    // The "appropriate place for inserting a node".
    fn target(&self) -> Handle {
        // FIXME: foster parenting, templates, other nonsense
        self.open_elems.last().expect("no current element").clone()
    }

    fn push(&mut self, elem: &Handle) {
        self.open_elems.push(elem.clone());
    }

    fn pop(&mut self) -> Handle {
        self.open_elems.pop().expect("no current element")
    }

    fn create_root(&mut self, attrs: Vec<Attribute>) {
        let elem = self.sink.create_element(HTML, atom!(html), attrs);
        self.push(&elem);
        self.sink.append_element(self.doc_handle.clone(), elem);
        // FIXME: application cache selection algorithm
    }

    fn create_element_impl(&mut self, push: bool, name: Atom, attrs: Vec<Attribute>) -> Handle {
        let target = self.target();
        let elem = self.sink.create_element(HTML, name, attrs);
        if push {
            self.push(&elem);
        }
        self.sink.append_element(target, elem.clone());
        // FIXME: Remove from the stack if we can't append?
        elem
    }

    fn create_element(&mut self, name: Atom, attrs: Vec<Attribute>) -> Handle {
        self.create_element_impl(true, name, attrs)
    }

    fn create_element_nopush(&mut self, name: Atom, attrs: Vec<Attribute>) -> Handle {
        self.create_element_impl(false, name, attrs)
    }

    fn create_element_for(&mut self, tag: &mut Tag) -> Handle {
        self.create_element(tag.name.clone(), take_attrs(tag))
    }

    fn process_local_tokens<Iter: Iterator<Token>>
        (&mut self,
         mut mode: states::InsertionMode,
         mut tokens: Iter) {

        for mut token in tokens {
            loop {
                match self.process_local(mode, token) {
                    Done => break,
                    Reprocess(m, t) => {
                        mode = m;
                        token = t;
                    }
                }
            }
        }
    }

    fn process_local(&mut self, mode: states::InsertionMode, mut token: Token) -> ProcessResult {
        debug!("processing {} in insertion mode {:?}", token, mode);

        match mode {
            states::Initial => match token {
                CommentToken(text) => {
                    self.sink.append_comment(self.doc_handle.clone(), text);
                    Done
                }
                token => {
                    if !self.opts.iframe_srcdoc {
                        self.sink.parse_error(format!("Bad token in Initial insertion mode: {}", token));
                        self.sink.set_quirks_mode(Quirks);
                    }
                    Reprocess(states::BeforeHtml, token)
                }
            },

            states::BeforeHtml => match token {
                CommentToken(text) => {
                    self.sink.append_comment(self.doc_handle.clone(), text);
                    Done
                }
                start!(mut t) if named!(t, html) => {
                    self.create_root(take_attrs(t));
                    Done
                }
                end!(t) if !named!(t, head body html br) => {
                    self.sink.parse_error(format!("Unexpected end tag in BeforeHtml mode: {}", t));
                    Done
                }
                token => {
                    self.create_root(vec!());
                    Reprocess(states::BeforeHead, token)
                }
            },

            states::BeforeHead => match token {
                CommentToken(text) => {
                    let target = self.target();
                    self.sink.append_comment(target, text);
                    Done
                }
                end!(t) if !named!(t, head body html br) => {
                    self.sink.parse_error(format!("Unexpected end tag in BeforeHead mode: {}", t));
                    Done
                }
                start!(mut t) if named!(t, head) => {
                    self.head_elem = Some(self.create_element_for(t));
                    self.mode = states::InHead;
                    Done
                }
                token => if start_named!(token, html) {
                    // Do this here because we can't move out of `token` when it's borrowed.
                    self.process_local(states::InBody, token)
                } else {
                    self.head_elem = Some(self.create_element(atom!(head), vec!()));
                    Reprocess(states::InHead, token)
                },
            },

            states::InHead => match token {
                CharacterTokens(true, text) => {
                    let target = self.target();
                    self.sink.append_text(target, text);
                    Done
                }
                CommentToken(text) => {
                    let target = self.target();
                    self.sink.append_comment(target, text);
                    Done
                }
                start!(mut t) if match_atom!(t.name {
                    base basefont bgsound link meta => {
                        self.create_element_nopush(t.name.clone(), take_attrs(t));
                        /* FIXME: handle charset= and http-equiv="Content-Type"
                        if named!(t, meta) {
                            ...
                        }
                        */
                        true
                    }
                    title => {
                        self.parse_raw_data(Rcdata);
                        self.create_element_for(t);
                        true
                    }
                    noframes style noscript => {
                        if (!self.opts.scripting_enabled) && named!(t, noscript) {
                            self.create_element_for(t);
                            self.mode = states::InHeadNoscript;
                        } else {
                            self.parse_raw_data(Rawtext);
                            self.create_element_for(t);
                        }
                        true
                    }
                    script => {
                        let target = self.target();
                        let elem = self.sink.create_element(HTML, atom!(script), take_attrs(t));
                        if self.opts.fragment {
                            self.sink.mark_script_already_started(elem.clone());
                        }
                        self.push(&elem);
                        self.sink.append_element(target, elem);
                        self.parse_raw_data(ScriptData);
                        true
                    }
                    template => fail!("FIXME: <template> not implemented"),
                    head => {
                        self.sink.parse_error("<head> in insertion mode InHead".to_owned());
                        true
                    }
                    _ => false,
                }) => Done,
                end!(mut t) if match_atom!(t.name {
                    head => {
                        self.pop();
                        self.mode = states::AfterHead;
                        true
                    }
                    body html br => false,
                    template => fail!("FIXME: <template> not implemented"),
                    _ => {
                        self.sink.parse_error(format!("Unexpected end tag in InHead mode: {}", t));
                        true
                    }
                }) => Done,
                token => if start_named!(token, html) {
                    // Do this here because we can't move out of `token` when it's borrowed.
                    self.process_local(states::InBody, token)
                } else {
                    self.pop();
                    Reprocess(states::AfterHead, token)
                },
            },

            states::InHeadNoscript => match token {
                CharacterTokens(true, text) => {
                    let target = self.target();
                    self.sink.append_text(target, text);
                    Done
                }
                end!(t) if match_atom!(t.name {
                    noscript => {
                        self.pop();
                        self.mode = states::InHead;
                        true
                    }
                    br => false,
                    _ => {
                        self.sink.parse_error(format!("Unexpected end tag in InHeadNoscript mode: {}", t));
                        true
                    }
                }) => Done,
                start!(t) if named!(t, head noscript) => {
                    self.sink.parse_error(format!("Unexpected start tag in InHeadNoscript mode: {}", t));
                    Done
                }

                token @ CommentToken(_) => self.process_local(states::InHead, token),

                token => if start_named!(token, html) {
                    self.process_local(states::InBody, token)
                } else if start_named!(token, basefont bgsound link meta noframes style) {
                    self.process_local(states::InHead, token)
                } else {
                    self.sink.parse_error(format!("Unexpected token in InHeadNoscript mode: {}", token));
                    self.pop();
                    Reprocess(states::InHead, token)
                },
            },

              states::AfterHead
            | states::InBody
            | states::Text
            | states::InTable
            | states::InTableText
            | states::InCaption
            | states::InColumnGroup
            | states::InTableBody
            | states::InRow
            | states::InCell
            | states::InSelect
            | states::InSelectInTable
            | states::InTemplate
            | states::AfterBody
            | states::InFrameset
            | states::AfterFrameset
            | states::AfterAfterBody
            | states::AfterAfterFrameset
                => fail!("not implemented"),
        }
    }
}

impl<'sink, Handle: Clone, Sink: TreeSink<Handle>> TokenSink for TreeBuilder<'sink, Handle, Sink> {
    fn process_token(&mut self, token: tokenizer::Token) {
        // Handle `ParseError` and `DoctypeToken`; convert everything else to the local `Token` type.
        let token = match token {
            tokenizer::ParseError(e) => {
                self.sink.parse_error(e);
                return;
            }

            tokenizer::DoctypeToken(dt) => if self.mode == states::Initial {
                let (err, quirk) = data::doctype_error_and_quirks(&dt, self.opts.iframe_srcdoc);
                if err {
                    self.sink.parse_error(format!("Bad DOCTYPE: {}", dt));
                }
                let Doctype { name, public_id, system_id, force_quirks: _ } = dt;
                self.sink.append_doctype_to_document(
                    name.unwrap_or(StrBuf::new()),
                    public_id.unwrap_or(StrBuf::new()),
                    system_id.unwrap_or(StrBuf::new())
                );
                self.sink.set_quirks_mode(quirk);

                self.mode = states::BeforeHtml;
                return;
            } else {
                self.sink.parse_error(format!("DOCTYPE in insertion mode {:?}", self.mode));
                return;
            },

            tokenizer::TagToken(x) => TagToken(x),
            tokenizer::CommentToken(x) => CommentToken(x),
            tokenizer::CharacterTokens(x) => CharacterTokens(false, x),
            tokenizer::EOFToken => EOFToken,
        };

        // Do we split the token into whitespace / non-whitespace and, if so,
        // do we keep the whitespace or just drop it?
        let (process_whitespace, keep_whitespace) = match self.mode {
            states::InHead | states::InHeadNoscript
                => (true, true),
            states::Initial | states::BeforeHtml | states::BeforeHead
                => (true, false),
            _ => (false, false)
        };

        match (process_whitespace, token) {
            (true, CharacterTokens(_, buf)) => self.process_local_tokens(self.mode,
                Runs::new(is_ascii_whitespace, buf.as_slice())
                    .filter(|&(m, _)| keep_whitespace || !m)
                    .map(|(m, b)| CharacterTokens(m, b.to_strbuf()))),

            (_, token) => self.process_local_tokens(self.mode, Some(token).move_iter()),
        }
    }

    fn query_state_change(&mut self) -> Option<tokenizer::states::State> {
        self.next_tokenizer_state.take()
    }
}
<commit_msg>Add some macros for concise tree builder actions<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/. */

pub use self::interface::{QuirksMode, Quirks, LimitedQuirks, NoQuirks};
pub use self::interface::TreeSink;

use tokenizer;
use tokenizer::{Doctype, Attribute, StartTag, EndTag, Tag};
use tokenizer::TokenSink;
use tokenizer::states::{RawData, RawKind, Rcdata, Rawtext, ScriptData};

use util::atom::Atom;
use util::namespace::HTML;
use util::str::{is_ascii_whitespace, Runs};

use std::default::Default;
use std::mem::replace;

mod interface;
mod states;
mod data;

/// We mostly only work with these tokens. Everything else is handled
/// specially at the beginning of `process_token`.
#[deriving(Eq, TotalEq, Clone, Show)]
enum Token {
    TagToken(Tag),
    CommentToken(StrBuf),
    CharacterTokens(bool, StrBuf),
    EOFToken,
}

/// Tree builder options, with an impl for Default.
#[deriving(Clone)]
pub struct TreeBuilderOpts {
    /// Is scripting enabled?
    pub scripting_enabled: bool,

    /// Is this an iframe srcdoc document?
    pub iframe_srcdoc: bool,

    /// Are we parsing a HTML fragment?
    pub fragment: bool,
}

impl Default for TreeBuilderOpts {
    fn default() -> TreeBuilderOpts {
        TreeBuilderOpts {
            scripting_enabled: true,
            iframe_srcdoc: false,
            fragment: false,
        }
    }
}

pub struct TreeBuilder<'sink, Handle, Sink> {
    /// Options controlling the behavior of the tree builder.
    opts: TreeBuilderOpts,

    /// Consumer of tree modifications.
    sink: &'sink mut Sink,

    /// Insertion mode.
    mode: states::InsertionMode,

    /// Original insertion mode, used by Text and InTableText modes.
    orig_mode: Option<states::InsertionMode>,

    /// The document node, which is created by the sink.
    doc_handle: Handle,

    /// Stack of open elements, most recently added at end.
    open_elems: Vec<Handle>,

    /// Head element pointer.
    head_elem: Option<Handle>,

    /// Next state change for the tokenizer, if any.
    next_tokenizer_state: Option<tokenizer::states::State>,
}

// We use guards, so we can't bind tags by move.  Instead, bind by ref
// mut and take attrs with `replace`.  This is basically fine since
// empty `Vec` doesn't allocate.
fn take_attrs(t: &mut Tag) -> Vec<Attribute> {
    replace(&mut t.attrs, vec!())
}

enum ProcessResult {
    Done,
    Reprocess(states::InsertionMode, Token),
}

macro_rules! tag_pattern (
    ($kind:ident     $var:ident) => ( TagToken(ref     $var @ Tag { kind: $kind, ..}) );
    ($kind:ident mut $var:ident) => ( TagToken(ref mut $var @ Tag { kind: $kind, ..}) );
)

macro_rules! start ( ($($args:tt)*) => ( tag_pattern!(StartTag $($args)*) ))
macro_rules! end   ( ($($args:tt)*) => ( tag_pattern!(EndTag   $($args)*) ))

macro_rules! named ( ($t:expr, $($atom:ident)*) => (
    match_atom!($t.name { $($atom)* => true, _ => false })
))

macro_rules! kind_named ( ($kind:ident $t:expr, $($atom:ident)*) => (
    match $t {
        tag_pattern!($kind t) => named!(t, $($atom)*),
        _ => false,
    }
))

macro_rules! start_named ( ($($args:tt)*) => ( kind_named!(StartTag $($args)*) ))
macro_rules! end_named   ( ($($args:tt)*) => ( kind_named!(EndTag   $($args)*) ))

macro_rules! append_with ( ( $fun:ident, $target:expr, $($args:expr),* ) => ({
    // two steps to avoid double borrow
    let target = $target;
    self.sink.$fun(target, $($args),*);
    Done
}))

macro_rules! append_text    ( ($target:expr, $text:expr) => ( append_with!(append_text,    $target, $text) ))
macro_rules! append_comment ( ($target:expr, $text:expr) => ( append_with!(append_comment, $target, $text) ))

impl<'sink, Handle: Clone, Sink: TreeSink<Handle>> TreeBuilder<'sink, Handle, Sink> {
    pub fn new(sink: &'sink mut Sink, opts: TreeBuilderOpts) -> TreeBuilder<'sink, Handle, Sink> {
        let doc_handle = sink.get_document();
        TreeBuilder {
            opts: opts,
            sink: sink,
            mode: states::Initial,
            orig_mode: None,
            doc_handle: doc_handle,
            open_elems: vec!(),
            head_elem: None,
            next_tokenizer_state: None,
        }
    }

    // Switch to `Text` insertion mode, save the old mode, and
    // switch the tokenizer to a raw-data state.
    // The latter only takes effect after the current / next
    // `process_token` of a start tag returns!
    fn parse_raw_data(&mut self, k: RawKind) {
        assert!(self.next_tokenizer_state.is_none());
        self.next_tokenizer_state = Some(RawData(k));
        self.orig_mode = Some(self.mode);
        self.mode = states::Text;
    }

    // The "appropriate place for inserting a node".
    fn target(&self) -> Handle {
        // FIXME: foster parenting, templates, other nonsense
        self.open_elems.last().expect("no current element").clone()
    }

    fn push(&mut self, elem: &Handle) {
        self.open_elems.push(elem.clone());
    }

    fn pop(&mut self) -> Handle {
        self.open_elems.pop().expect("no current element")
    }

    fn create_root(&mut self, attrs: Vec<Attribute>) {
        let elem = self.sink.create_element(HTML, atom!(html), attrs);
        self.push(&elem);
        self.sink.append_element(self.doc_handle.clone(), elem);
        // FIXME: application cache selection algorithm
    }

    fn create_element_impl(&mut self, push: bool, name: Atom, attrs: Vec<Attribute>) -> Handle {
        let target = self.target();
        let elem = self.sink.create_element(HTML, name, attrs);
        if push {
            self.push(&elem);
        }
        self.sink.append_element(target, elem.clone());
        // FIXME: Remove from the stack if we can't append?
        elem
    }

    fn create_element(&mut self, name: Atom, attrs: Vec<Attribute>) -> Handle {
        self.create_element_impl(true, name, attrs)
    }

    fn create_element_nopush(&mut self, name: Atom, attrs: Vec<Attribute>) -> Handle {
        self.create_element_impl(false, name, attrs)
    }

    fn create_element_for(&mut self, tag: &mut Tag) -> Handle {
        self.create_element(tag.name.clone(), take_attrs(tag))
    }

    fn process_local_tokens<Iter: Iterator<Token>>
        (&mut self,
         mut mode: states::InsertionMode,
         mut tokens: Iter) {

        for mut token in tokens {
            loop {
                match self.process_local(mode, token) {
                    Done => break,
                    Reprocess(m, t) => {
                        mode = m;
                        token = t;
                    }
                }
            }
        }
    }

    fn process_local(&mut self, mode: states::InsertionMode, mut token: Token) -> ProcessResult {
        debug!("processing {} in insertion mode {:?}", token, mode);

        match mode {
            states::Initial => match token {
                CommentToken(text) => append_comment!(self.doc_handle.clone(), text),
                token => {
                    if !self.opts.iframe_srcdoc {
                        self.sink.parse_error(format!("Bad token in Initial insertion mode: {}", token));
                        self.sink.set_quirks_mode(Quirks);
                    }
                    Reprocess(states::BeforeHtml, token)
                }
            },

            states::BeforeHtml => match token {
                CommentToken(text) => append_comment!(self.doc_handle.clone(), text),
                start!(mut t) if named!(t, html) => {
                    self.create_root(take_attrs(t));
                    Done
                }
                end!(t) if !named!(t, head body html br) => {
                    self.sink.parse_error(format!("Unexpected end tag in BeforeHtml mode: {}", t));
                    Done
                }
                token => {
                    self.create_root(vec!());
                    Reprocess(states::BeforeHead, token)
                }
            },

            states::BeforeHead => match token {
                CommentToken(text) => append_comment!(self.target(), text),
                end!(t) if !named!(t, head body html br) => {
                    self.sink.parse_error(format!("Unexpected end tag in BeforeHead mode: {}", t));
                    Done
                }
                start!(mut t) if named!(t, head) => {
                    self.head_elem = Some(self.create_element_for(t));
                    self.mode = states::InHead;
                    Done
                }
                token => if start_named!(token, html) {
                    // Do this here because we can't move out of `token` when it's borrowed.
                    self.process_local(states::InBody, token)
                } else {
                    self.head_elem = Some(self.create_element(atom!(head), vec!()));
                    Reprocess(states::InHead, token)
                },
            },

            states::InHead => match token {
                CharacterTokens(true, text) => append_text!(self.target(), text),
                CommentToken(text) => append_comment!(self.target(), text),
                start!(mut t) if match_atom!(t.name {
                    base basefont bgsound link meta => {
                        self.create_element_nopush(t.name.clone(), take_attrs(t));
                        /* FIXME: handle charset= and http-equiv="Content-Type"
                        if named!(t, meta) {
                            ...
                        }
                        */
                        true
                    }
                    title => {
                        self.parse_raw_data(Rcdata);
                        self.create_element_for(t);
                        true
                    }
                    noframes style noscript => {
                        if (!self.opts.scripting_enabled) && named!(t, noscript) {
                            self.create_element_for(t);
                            self.mode = states::InHeadNoscript;
                        } else {
                            self.parse_raw_data(Rawtext);
                            self.create_element_for(t);
                        }
                        true
                    }
                    script => {
                        let target = self.target();
                        let elem = self.sink.create_element(HTML, atom!(script), take_attrs(t));
                        if self.opts.fragment {
                            self.sink.mark_script_already_started(elem.clone());
                        }
                        self.push(&elem);
                        self.sink.append_element(target, elem);
                        self.parse_raw_data(ScriptData);
                        true
                    }
                    template => fail!("FIXME: <template> not implemented"),
                    head => {
                        self.sink.parse_error("<head> in insertion mode InHead".to_owned());
                        true
                    }
                    _ => false,
                }) => Done,
                end!(mut t) if match_atom!(t.name {
                    head => {
                        self.pop();
                        self.mode = states::AfterHead;
                        true
                    }
                    body html br => false,
                    template => fail!("FIXME: <template> not implemented"),
                    _ => {
                        self.sink.parse_error(format!("Unexpected end tag in InHead mode: {}", t));
                        true
                    }
                }) => Done,
                token => if start_named!(token, html) {
                    // Do this here because we can't move out of `token` when it's borrowed.
                    self.process_local(states::InBody, token)
                } else {
                    self.pop();
                    Reprocess(states::AfterHead, token)
                },
            },

            states::InHeadNoscript => match token {
                CharacterTokens(true, text) => append_text!(self.target(), text),
                end!(t) if match_atom!(t.name {
                    noscript => {
                        self.pop();
                        self.mode = states::InHead;
                        true
                    }
                    br => false,
                    _ => {
                        self.sink.parse_error(format!("Unexpected end tag in InHeadNoscript mode: {}", t));
                        true
                    }
                }) => Done,
                start!(t) if named!(t, head noscript) => {
                    self.sink.parse_error(format!("Unexpected start tag in InHeadNoscript mode: {}", t));
                    Done
                }

                token @ CommentToken(_) => self.process_local(states::InHead, token),

                token => if start_named!(token, html) {
                    self.process_local(states::InBody, token)
                } else if start_named!(token, basefont bgsound link meta noframes style) {
                    self.process_local(states::InHead, token)
                } else {
                    self.sink.parse_error(format!("Unexpected token in InHeadNoscript mode: {}", token));
                    self.pop();
                    Reprocess(states::InHead, token)
                },
            },

              states::AfterHead
            | states::InBody
            | states::Text
            | states::InTable
            | states::InTableText
            | states::InCaption
            | states::InColumnGroup
            | states::InTableBody
            | states::InRow
            | states::InCell
            | states::InSelect
            | states::InSelectInTable
            | states::InTemplate
            | states::AfterBody
            | states::InFrameset
            | states::AfterFrameset
            | states::AfterAfterBody
            | states::AfterAfterFrameset
                => fail!("not implemented"),
        }
    }
}

impl<'sink, Handle: Clone, Sink: TreeSink<Handle>> TokenSink for TreeBuilder<'sink, Handle, Sink> {
    fn process_token(&mut self, token: tokenizer::Token) {
        // Handle `ParseError` and `DoctypeToken`; convert everything else to the local `Token` type.
        let token = match token {
            tokenizer::ParseError(e) => {
                self.sink.parse_error(e);
                return;
            }

            tokenizer::DoctypeToken(dt) => if self.mode == states::Initial {
                let (err, quirk) = data::doctype_error_and_quirks(&dt, self.opts.iframe_srcdoc);
                if err {
                    self.sink.parse_error(format!("Bad DOCTYPE: {}", dt));
                }
                let Doctype { name, public_id, system_id, force_quirks: _ } = dt;
                self.sink.append_doctype_to_document(
                    name.unwrap_or(StrBuf::new()),
                    public_id.unwrap_or(StrBuf::new()),
                    system_id.unwrap_or(StrBuf::new())
                );
                self.sink.set_quirks_mode(quirk);

                self.mode = states::BeforeHtml;
                return;
            } else {
                self.sink.parse_error(format!("DOCTYPE in insertion mode {:?}", self.mode));
                return;
            },

            tokenizer::TagToken(x) => TagToken(x),
            tokenizer::CommentToken(x) => CommentToken(x),
            tokenizer::CharacterTokens(x) => CharacterTokens(false, x),
            tokenizer::EOFToken => EOFToken,
        };

        // Do we split the token into whitespace / non-whitespace and, if so,
        // do we keep the whitespace or just drop it?
        let (process_whitespace, keep_whitespace) = match self.mode {
            states::InHead | states::InHeadNoscript
                => (true, true),
            states::Initial | states::BeforeHtml | states::BeforeHead
                => (true, false),
            _ => (false, false)
        };

        match (process_whitespace, token) {
            (true, CharacterTokens(_, buf)) => self.process_local_tokens(self.mode,
                Runs::new(is_ascii_whitespace, buf.as_slice())
                    .filter(|&(m, _)| keep_whitespace || !m)
                    .map(|(m, b)| CharacterTokens(m, b.to_strbuf()))),

            (_, token) => self.process_local_tokens(self.mode, Some(token).move_iter()),
        }
    }

    fn query_state_change(&mut self) -> Option<tokenizer::states::State> {
        self.next_tokenizer_state.take()
    }
}
<|endoftext|>