<commit_before>//! Error types.

use std::error;
use std::fmt;

use cssparser::{BasicParseError, BasicParseErrorKind, ParseErrorKind, ToCss};
use markup5ever::QualName;

use crate::node::Node;
use crate::url_resolver::Fragment;

/// A short-lived error.
///
/// The lifetime of the error is the same as the `cssparser::ParserInput` that
/// was used to create a `cssparser::Parser`.  That is, it is the lifetime of
/// the string data that is being parsed.
///
/// The code flow will sometimes require preserving this error as a long-lived struct;
/// see the `impl<'i, O> AttributeResultExt<O> for Result<O, ParseError<'i>>` for that
/// purpose.
pub type ParseError<'i> = cssparser::ParseError<'i, ValueErrorKind>;

/// A simple error which refers to an attribute's value
#[derive(Debug, Clone, PartialEq)]
pub enum ValueErrorKind {
    /// A property with the specified name was not found
    UnknownProperty,

    /// The value could not be parsed
    Parse(String),

    // The value could be parsed, but is invalid
    Value(String),
}

impl ValueErrorKind {
    pub fn parse_error(s: &str) -> ValueErrorKind {
        ValueErrorKind::Parse(s.to_string())
    }

    pub fn value_error(s: &str) -> ValueErrorKind {
        ValueErrorKind::Value(s.to_string())
    }
}

impl fmt::Display for ValueErrorKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            ValueErrorKind::UnknownProperty => write!(f, "unknown property name"),

            ValueErrorKind::Parse(ref s) => write!(f, "parse error: {}", s),

            ValueErrorKind::Value(ref s) => write!(f, "invalid value: {}", s),
        }
    }
}

impl<'a> From<BasicParseError<'a>> for ValueErrorKind {
    fn from(e: BasicParseError<'_>) -> ValueErrorKind {
        let BasicParseError { kind, .. } = e;

        let msg = match kind {
            BasicParseErrorKind::UnexpectedToken(_) => "unexpected token",
            BasicParseErrorKind::EndOfInput => "unexpected end of input",
            BasicParseErrorKind::AtRuleInvalid(_) => "invalid @-rule",
            BasicParseErrorKind::AtRuleBodyInvalid => "invalid @-rule body",
            BasicParseErrorKind::QualifiedRuleInvalid => "invalid qualified rule",
        };

        ValueErrorKind::parse_error(msg)
    }
}

/// A complete error for an attribute and its erroneous value
#[derive(Debug, Clone, PartialEq)]
pub struct ElementError {
    pub attr: QualName,
    pub err: ValueErrorKind,
}

impl error::Error for ElementError {
    fn description(&self) -> &str {
        match self.err {
            ValueErrorKind::UnknownProperty => "unknown property",
            ValueErrorKind::Parse(_) => "parse error",
            ValueErrorKind::Value(_) => "invalid attribute value",
        }
    }
}

impl fmt::Display for ElementError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}: {}", self.attr.expanded(), self.err)
    }
}

/// Errors returned when looking up a resource by URL reference.
#[derive(Debug, Clone, PartialEq)]
pub enum DefsLookupErrorKind {
    /// Error when parsing an [`Href`].
    ///
    /// [`Href`]: allowed_url/enum.Href.html
    HrefError(HrefError),

    /// Used when the public API tries to look up an external URL, which is not allowed.
    ///
    /// This catches the case where a public API wants to be misused to access an external
    /// resource.  For example, `SvgHandle.has_sub("https://evil.com/phone_home#element_id") will
    /// fail with this error.
    CannotLookupExternalReferences,

    /// For internal use only.
    ///
    // FIXME: this is returned internally from Handle.lookup_node(), and gets translated
    // to Ok(false).  Don't expose this internal code in the public API.
    NotFound,
}

/// Errors that can happen while rendering or measuring an SVG document.
#[derive(Debug, Clone, PartialEq)]
pub enum RenderingError {
    /// A Cairo error happened during rendering.
    Cairo(cairo::Status),

    /// There is a circular reference between elements.
    // FIXME: should be internal only.
    CircularReference,

    /// The maximum number of rendered objects was reached.
    ///
    /// Librsvg has a limit on the number of rendered objects, so that malicious
    /// files cannot consume CPU time arbitrarily.
    InstancingLimit,

    /// Tried to reference an SVG element from a fragment identifier that is incorrect.
    InvalidId(DefsLookupErrorKind),

    // FIXME: unused.
    InvalidHref,

    /// Not enough memory was available for rendering.
    // FIXME: right now this is only returned from pixbuf_utils.rs
    OutOfMemory,

    /// Cannot occur from librsvg_crate; this is just for the C API.
    HandleIsNotLoaded,
}

impl error::Error for RenderingError {}

impl fmt::Display for RenderingError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            RenderingError::CircularReference => write!(f, "circular reference"),
            RenderingError::InstancingLimit => write!(f, "instancing limit"),
            RenderingError::InvalidHref => write!(f, "invalid href"),
            RenderingError::OutOfMemory => write!(f, "out of memory"),
            RenderingError::HandleIsNotLoaded => write!(f, "SVG data is not loaded into handle"),
            RenderingError::Cairo(ref status) => write!(f, "cairo error: {:?}", status),
            RenderingError::InvalidId(ref id) => write!(f, "invalid id: {:?}", id),
        }
    }
}

impl From<cairo::Status> for RenderingError {
    fn from(e: cairo::Status) -> RenderingError {
        assert!(e != cairo::Status::Success);

        RenderingError::Cairo(e)
    }
}

pub enum AcquireError {
    LinkNotFound(Fragment),
    InvalidLinkType(Fragment),
    CircularReference(Node),
    MaxReferencesExceeded,
}

impl fmt::Display for AcquireError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            AcquireError::LinkNotFound(ref frag) => write!(f, "link not found: {}", frag),

            AcquireError::InvalidLinkType(ref frag) => {
                write!(f, "link {} is to object of invalid type", frag)
            }

            AcquireError::CircularReference(ref node) => {
                write!(f, "circular reference in node {}", node)
            }

            AcquireError::MaxReferencesExceeded => {
                write!(f, "maximum number of references exceeded")
            }
        }
    }
}

/// Helper for converting `Result<O, E>` into `Result<O, ElementError>`
///
/// A `ElementError` requires a `QualName` that corresponds to the attribute to which the
/// error refers, plus the actual `ValueErrorKind` that describes the error.  However,
/// parsing functions for attribute value types will want to return their own kind of
/// error, instead of `ValueErrorKind`.  If that particular error type has an `impl
/// From<FooError> for ValueErrorKind`, then this trait helps assign attribute values in
/// `set_atts()` methods as follows:
///
/// ```
/// # use librsvg::doctest_only::AttributeResultExt;
/// # use librsvg::doctest_only::ValueErrorKind;
/// # use librsvg::doctest_only::ElementError;
/// # use markup5ever::{QualName, Prefix, Namespace, LocalName};
/// # type FooError = ValueErrorKind;
/// fn parse_foo(value: &str) -> Result<(), FooError>
/// # { Err(ValueErrorKind::value_error("test")) }
///
/// // It is assumed that there is an impl From<FooError> for ValueErrorKind
/// # let attr = QualName::new(
/// #     Some(Prefix::from("")),
/// #     Namespace::from(""),
/// #     LocalName::from(""),
/// # );
/// let result = parse_foo("value").attribute(attr);
/// assert!(result.is_err());
/// # Ok::<(), ElementError>(())
/// ```
///
/// The call to `.attribute(attr)` converts the `Result` from `parse_foo()` into a full
/// `ElementError` with the provided `attr`.
pub trait AttributeResultExt<O> {
    fn attribute(self, attr: QualName) -> Result<O, ElementError>;
}

impl<O, E: Into<ValueErrorKind>> AttributeResultExt<O> for Result<O, E> {
    fn attribute(self, attr: QualName) -> Result<O, ElementError> {
        self.map_err(|e| e.into())
            .map_err(|err| ElementError { attr, err })
    }
}

/// Turns a short-lived `ParseError` into a long-lived `ElementError`
impl<'i, O> AttributeResultExt<O> for Result<O, ParseError<'i>> {
    fn attribute(self, attr: QualName) -> Result<O, ElementError> {
        self.map_err(|e| {
            // FIXME: eventually, here we'll want to preserve the location information

            let ParseError {
                kind,
                location: _location,
            } = e;

            match kind {
                ParseErrorKind::Basic(BasicParseErrorKind::UnexpectedToken(tok)) => {
                    let mut s = String::from("unexpected token '");
                    tok.to_css(&mut s).unwrap(); // FIXME: what do we do with a fmt::Error?
                    s.push_str("'");

                    ElementError {
                        attr,
                        err: ValueErrorKind::Parse(s),
                    }
                }

                ParseErrorKind::Basic(BasicParseErrorKind::EndOfInput) => ElementError {
                    attr,
                    err: ValueErrorKind::parse_error("unexpected end of input"),
                },

                ParseErrorKind::Basic(_) => {
                    unreachable!("attribute parsers should not return errors for CSS rules")
                }

                ParseErrorKind::Custom(err) => ElementError { attr, err },
            }
        })
    }
}

/// Errors returned when creating an `Href` out of a string
#[derive(Debug, Clone, PartialEq)]
pub enum HrefError {
    /// The href is an invalid URI or has empty components.
    ParseError,

    /// A fragment identifier ("`#foo`") is not allowed here
    ///
    /// For example, the SVG `<image>` element only allows referencing
    /// resources without fragment identifiers like
    /// `xlink:href="foo.png"`.
    FragmentForbidden,

    /// A fragment identifier ("`#foo`") was required but not found.  For example,
    /// the SVG `<use>` element requires one, as in `<use xlink:href="foo.svg#bar">`.
    FragmentRequired,
}

impl From<HrefError> for ValueErrorKind {
    fn from(e: HrefError) -> ValueErrorKind {
        match e {
            HrefError::ParseError => ValueErrorKind::parse_error("url parse error"),
            HrefError::FragmentForbidden => {
                ValueErrorKind::value_error("fragment identifier not allowed")
            }
            HrefError::FragmentRequired => {
                ValueErrorKind::value_error("fragment identifier required")
            }
        }
    }
}

/// Errors that can happen while loading an SVG document.
///
/// All of these codes are for unrecoverable errors that keep an SVG document from being
/// fully loaded and parsed.  Note that SVG is very lenient with respect to document
/// structure and the syntax of CSS property values; most errors there will not lead to a
/// `LoadingError`.  To see those errors, you may want to set the `RSVG_LOG=1` environment
/// variable.
///
/// I/O errors get reported in the `Glib` variant, since librsvg uses GIO internally for
/// all input/output.
#[derive(Debug, Clone)]
pub enum LoadingError {
    // FIXME: C API only
    NoDataPassedToParser,

    /// XML syntax error.
    XmlParseError(String),

    // FIXME: this is OOM in libxml2; we shouldn't expose it.
    CouldNotCreateXmlParser,

    /// A malformed or disallowed URL was used.
    BadUrl,

    /// A `data:` URL could not be decoded.
    BadDataUrl,

    // FIXME: used only if XML processing instruction cannot find the stylesheet.
    BadStylesheet,

    /// An invalid stylesheet was used.
    BadCss,

    /// A Cairo error happened during loading.
    Cairo(cairo::Status),

    // FIXME: only used in load_image()
    EmptyData,

    /// There are no SVG elements in the document.
    SvgHasNoElements,

    /// The outermost element in the document is not `<svg>`.
    RootElementIsNotSvg,

    /// Generally an I/O error, or another error from GIO.
    Glib(glib::Error),

    // FIXME: only used internally when loading pixbufs, and temporarily in c_api.
    Unknown,
}

impl error::Error for LoadingError {}

impl fmt::Display for LoadingError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            LoadingError::NoDataPassedToParser => write!(f, "no data passed to parser"),
            LoadingError::XmlParseError(ref s) => write!(f, "XML parse error: {}", s),
            LoadingError::CouldNotCreateXmlParser => write!(f, "could not create XML parser"),
            LoadingError::BadUrl => write!(f, "invalid URL"),
            LoadingError::BadDataUrl => write!(f, "invalid data: URL"),
            LoadingError::BadStylesheet => write!(f, "invalid stylesheet"),
            LoadingError::BadCss => write!(f, "invalid CSS"),
            LoadingError::Cairo(status) => write!(f, "cairo error: {:?}", status),
            LoadingError::EmptyData => write!(f, "empty data"),
            LoadingError::SvgHasNoElements => write!(f, "SVG has no elements"),
            LoadingError::RootElementIsNotSvg => write!(f, "root element is not <svg>"),
            LoadingError::Glib(ref e) => e.fmt(f),
            LoadingError::Unknown => write!(f, "unknown error"),
        }
    }
}

impl From<cairo::Status> for LoadingError {
    fn from(e: cairo::Status) -> LoadingError {
        assert!(e != cairo::Status::Success);

        LoadingError::Cairo(e)
    }
}

impl From<glib::Error> for LoadingError {
    fn from(e: glib::Error) -> LoadingError {
        LoadingError::Glib(e)
    }
}
<commit_msg>Remove unused RenderingError::CircularReference<commit_after>//! Error types.

use std::error;
use std::fmt;

use cssparser::{BasicParseError, BasicParseErrorKind, ParseErrorKind, ToCss};
use markup5ever::QualName;

use crate::node::Node;
use crate::url_resolver::Fragment;

/// A short-lived error.
///
/// The lifetime of the error is the same as the `cssparser::ParserInput` that
/// was used to create a `cssparser::Parser`.  That is, it is the lifetime of
/// the string data that is being parsed.
///
/// The code flow will sometimes require preserving this error as a long-lived struct;
/// see the `impl<'i, O> AttributeResultExt<O> for Result<O, ParseError<'i>>` for that
/// purpose.
pub type ParseError<'i> = cssparser::ParseError<'i, ValueErrorKind>;

/// A simple error which refers to an attribute's value
#[derive(Debug, Clone, PartialEq)]
pub enum ValueErrorKind {
    /// A property with the specified name was not found
    UnknownProperty,

    /// The value could not be parsed
    Parse(String),

    // The value could be parsed, but is invalid
    Value(String),
}

impl ValueErrorKind {
    pub fn parse_error(s: &str) -> ValueErrorKind {
        ValueErrorKind::Parse(s.to_string())
    }

    pub fn value_error(s: &str) -> ValueErrorKind {
        ValueErrorKind::Value(s.to_string())
    }
}

impl fmt::Display for ValueErrorKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            ValueErrorKind::UnknownProperty => write!(f, "unknown property name"),

            ValueErrorKind::Parse(ref s) => write!(f, "parse error: {}", s),

            ValueErrorKind::Value(ref s) => write!(f, "invalid value: {}", s),
        }
    }
}

impl<'a> From<BasicParseError<'a>> for ValueErrorKind {
    fn from(e: BasicParseError<'_>) -> ValueErrorKind {
        let BasicParseError { kind, .. } = e;

        let msg = match kind {
            BasicParseErrorKind::UnexpectedToken(_) => "unexpected token",
            BasicParseErrorKind::EndOfInput => "unexpected end of input",
            BasicParseErrorKind::AtRuleInvalid(_) => "invalid @-rule",
            BasicParseErrorKind::AtRuleBodyInvalid => "invalid @-rule body",
            BasicParseErrorKind::QualifiedRuleInvalid => "invalid qualified rule",
        };

        ValueErrorKind::parse_error(msg)
    }
}

/// A complete error for an attribute and its erroneous value
#[derive(Debug, Clone, PartialEq)]
pub struct ElementError {
    pub attr: QualName,
    pub err: ValueErrorKind,
}

impl error::Error for ElementError {
    fn description(&self) -> &str {
        match self.err {
            ValueErrorKind::UnknownProperty => "unknown property",
            ValueErrorKind::Parse(_) => "parse error",
            ValueErrorKind::Value(_) => "invalid attribute value",
        }
    }
}

impl fmt::Display for ElementError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}: {}", self.attr.expanded(), self.err)
    }
}

/// Errors returned when looking up a resource by URL reference.
#[derive(Debug, Clone, PartialEq)]
pub enum DefsLookupErrorKind {
    /// Error when parsing an [`Href`].
    ///
    /// [`Href`]: allowed_url/enum.Href.html
    HrefError(HrefError),

    /// Used when the public API tries to look up an external URL, which is not allowed.
    ///
    /// This catches the case where a public API wants to be misused to access an external
    /// resource.  For example, `SvgHandle.has_sub("https://evil.com/phone_home#element_id") will
    /// fail with this error.
    CannotLookupExternalReferences,

    /// For internal use only.
    ///
    // FIXME: this is returned internally from Handle.lookup_node(), and gets translated
    // to Ok(false).  Don't expose this internal code in the public API.
    NotFound,
}

/// Errors that can happen while rendering or measuring an SVG document.
#[derive(Debug, Clone, PartialEq)]
pub enum RenderingError {
    /// A Cairo error happened during rendering.
    Cairo(cairo::Status),

    /// The maximum number of rendered objects was reached.
    ///
    /// Librsvg has a limit on the number of rendered objects, so that malicious
    /// files cannot consume CPU time arbitrarily.
    InstancingLimit,

    /// Tried to reference an SVG element from a fragment identifier that is incorrect.
    InvalidId(DefsLookupErrorKind),

    // FIXME: unused.
    InvalidHref,

    /// Not enough memory was available for rendering.
    // FIXME: right now this is only returned from pixbuf_utils.rs
    OutOfMemory,

    /// Cannot occur from librsvg_crate; this is just for the C API.
    HandleIsNotLoaded,
}

impl error::Error for RenderingError {}

impl fmt::Display for RenderingError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            RenderingError::InstancingLimit => write!(f, "instancing limit"),
            RenderingError::InvalidHref => write!(f, "invalid href"),
            RenderingError::OutOfMemory => write!(f, "out of memory"),
            RenderingError::HandleIsNotLoaded => write!(f, "SVG data is not loaded into handle"),
            RenderingError::Cairo(ref status) => write!(f, "cairo error: {:?}", status),
            RenderingError::InvalidId(ref id) => write!(f, "invalid id: {:?}", id),
        }
    }
}

impl From<cairo::Status> for RenderingError {
    fn from(e: cairo::Status) -> RenderingError {
        assert!(e != cairo::Status::Success);

        RenderingError::Cairo(e)
    }
}

pub enum AcquireError {
    LinkNotFound(Fragment),
    InvalidLinkType(Fragment),
    CircularReference(Node),
    MaxReferencesExceeded,
}

impl fmt::Display for AcquireError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            AcquireError::LinkNotFound(ref frag) => write!(f, "link not found: {}", frag),

            AcquireError::InvalidLinkType(ref frag) => {
                write!(f, "link {} is to object of invalid type", frag)
            }

            AcquireError::CircularReference(ref node) => {
                write!(f, "circular reference in node {}", node)
            }

            AcquireError::MaxReferencesExceeded => {
                write!(f, "maximum number of references exceeded")
            }
        }
    }
}

/// Helper for converting `Result<O, E>` into `Result<O, ElementError>`
///
/// A `ElementError` requires a `QualName` that corresponds to the attribute to which the
/// error refers, plus the actual `ValueErrorKind` that describes the error.  However,
/// parsing functions for attribute value types will want to return their own kind of
/// error, instead of `ValueErrorKind`.  If that particular error type has an `impl
/// From<FooError> for ValueErrorKind`, then this trait helps assign attribute values in
/// `set_atts()` methods as follows:
///
/// ```
/// # use librsvg::doctest_only::AttributeResultExt;
/// # use librsvg::doctest_only::ValueErrorKind;
/// # use librsvg::doctest_only::ElementError;
/// # use markup5ever::{QualName, Prefix, Namespace, LocalName};
/// # type FooError = ValueErrorKind;
/// fn parse_foo(value: &str) -> Result<(), FooError>
/// # { Err(ValueErrorKind::value_error("test")) }
///
/// // It is assumed that there is an impl From<FooError> for ValueErrorKind
/// # let attr = QualName::new(
/// #     Some(Prefix::from("")),
/// #     Namespace::from(""),
/// #     LocalName::from(""),
/// # );
/// let result = parse_foo("value").attribute(attr);
/// assert!(result.is_err());
/// # Ok::<(), ElementError>(())
/// ```
///
/// The call to `.attribute(attr)` converts the `Result` from `parse_foo()` into a full
/// `ElementError` with the provided `attr`.
pub trait AttributeResultExt<O> {
    fn attribute(self, attr: QualName) -> Result<O, ElementError>;
}

impl<O, E: Into<ValueErrorKind>> AttributeResultExt<O> for Result<O, E> {
    fn attribute(self, attr: QualName) -> Result<O, ElementError> {
        self.map_err(|e| e.into())
            .map_err(|err| ElementError { attr, err })
    }
}

/// Turns a short-lived `ParseError` into a long-lived `ElementError`
impl<'i, O> AttributeResultExt<O> for Result<O, ParseError<'i>> {
    fn attribute(self, attr: QualName) -> Result<O, ElementError> {
        self.map_err(|e| {
            // FIXME: eventually, here we'll want to preserve the location information

            let ParseError {
                kind,
                location: _location,
            } = e;

            match kind {
                ParseErrorKind::Basic(BasicParseErrorKind::UnexpectedToken(tok)) => {
                    let mut s = String::from("unexpected token '");
                    tok.to_css(&mut s).unwrap(); // FIXME: what do we do with a fmt::Error?
                    s.push_str("'");

                    ElementError {
                        attr,
                        err: ValueErrorKind::Parse(s),
                    }
                }

                ParseErrorKind::Basic(BasicParseErrorKind::EndOfInput) => ElementError {
                    attr,
                    err: ValueErrorKind::parse_error("unexpected end of input"),
                },

                ParseErrorKind::Basic(_) => {
                    unreachable!("attribute parsers should not return errors for CSS rules")
                }

                ParseErrorKind::Custom(err) => ElementError { attr, err },
            }
        })
    }
}

/// Errors returned when creating an `Href` out of a string
#[derive(Debug, Clone, PartialEq)]
pub enum HrefError {
    /// The href is an invalid URI or has empty components.
    ParseError,

    /// A fragment identifier ("`#foo`") is not allowed here
    ///
    /// For example, the SVG `<image>` element only allows referencing
    /// resources without fragment identifiers like
    /// `xlink:href="foo.png"`.
    FragmentForbidden,

    /// A fragment identifier ("`#foo`") was required but not found.  For example,
    /// the SVG `<use>` element requires one, as in `<use xlink:href="foo.svg#bar">`.
    FragmentRequired,
}

impl From<HrefError> for ValueErrorKind {
    fn from(e: HrefError) -> ValueErrorKind {
        match e {
            HrefError::ParseError => ValueErrorKind::parse_error("url parse error"),
            HrefError::FragmentForbidden => {
                ValueErrorKind::value_error("fragment identifier not allowed")
            }
            HrefError::FragmentRequired => {
                ValueErrorKind::value_error("fragment identifier required")
            }
        }
    }
}

/// Errors that can happen while loading an SVG document.
///
/// All of these codes are for unrecoverable errors that keep an SVG document from being
/// fully loaded and parsed.  Note that SVG is very lenient with respect to document
/// structure and the syntax of CSS property values; most errors there will not lead to a
/// `LoadingError`.  To see those errors, you may want to set the `RSVG_LOG=1` environment
/// variable.
///
/// I/O errors get reported in the `Glib` variant, since librsvg uses GIO internally for
/// all input/output.
#[derive(Debug, Clone)]
pub enum LoadingError {
    // FIXME: C API only
    NoDataPassedToParser,

    /// XML syntax error.
    XmlParseError(String),

    // FIXME: this is OOM in libxml2; we shouldn't expose it.
    CouldNotCreateXmlParser,

    /// A malformed or disallowed URL was used.
    BadUrl,

    /// A `data:` URL could not be decoded.
    BadDataUrl,

    // FIXME: used only if XML processing instruction cannot find the stylesheet.
    BadStylesheet,

    /// An invalid stylesheet was used.
    BadCss,

    /// A Cairo error happened during loading.
    Cairo(cairo::Status),

    // FIXME: only used in load_image()
    EmptyData,

    /// There are no SVG elements in the document.
    SvgHasNoElements,

    /// The outermost element in the document is not `<svg>`.
    RootElementIsNotSvg,

    /// Generally an I/O error, or another error from GIO.
    Glib(glib::Error),

    // FIXME: only used internally when loading pixbufs, and temporarily in c_api.
    Unknown,
}

impl error::Error for LoadingError {}

impl fmt::Display for LoadingError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            LoadingError::NoDataPassedToParser => write!(f, "no data passed to parser"),
            LoadingError::XmlParseError(ref s) => write!(f, "XML parse error: {}", s),
            LoadingError::CouldNotCreateXmlParser => write!(f, "could not create XML parser"),
            LoadingError::BadUrl => write!(f, "invalid URL"),
            LoadingError::BadDataUrl => write!(f, "invalid data: URL"),
            LoadingError::BadStylesheet => write!(f, "invalid stylesheet"),
            LoadingError::BadCss => write!(f, "invalid CSS"),
            LoadingError::Cairo(status) => write!(f, "cairo error: {:?}", status),
            LoadingError::EmptyData => write!(f, "empty data"),
            LoadingError::SvgHasNoElements => write!(f, "SVG has no elements"),
            LoadingError::RootElementIsNotSvg => write!(f, "root element is not <svg>"),
            LoadingError::Glib(ref e) => e.fmt(f),
            LoadingError::Unknown => write!(f, "unknown error"),
        }
    }
}

impl From<cairo::Status> for LoadingError {
    fn from(e: cairo::Status) -> LoadingError {
        assert!(e != cairo::Status::Success);

        LoadingError::Cairo(e)
    }
}

impl From<glib::Error> for LoadingError {
    fn from(e: glib::Error) -> LoadingError {
        LoadingError::Glib(e)
    }
}
<|endoftext|>


<commit_before>use crate::libyaml::{emitter, error as libyaml};
use crate::path::Path;
use serde::{de, ser};
use std::error;
use std::fmt::{self, Debug, Display};
use std::io;
use std::result;
use std::string;
use std::sync::Arc;

/// An error that happened serializing or deserializing YAML data.
pub struct Error(Box<ErrorImpl>);

/// Alias for a `Result` with the error type `serde_yaml::Error`.
pub type Result<T> = result::Result<T, Error>;

#[derive(Debug)]
pub(crate) enum ErrorImpl {
    Message(String, Option<Pos>),

    Libyaml(libyaml::Error),
    Io(io::Error),
    FromUtf8(string::FromUtf8Error),

    EndOfStream,
    MoreThanOneDocument,
    RecursionLimitExceeded(libyaml::Mark),
    RepetitionLimitExceeded,
    BytesUnsupported,
    UnknownAnchor(libyaml::Mark),
    SerializeNestedEnum,
    ScalarInMerge,
    TaggedInMerge,
    ScalarInMergeElement,
    SequenceInMergeElement,

    Shared(Arc<ErrorImpl>),
}

#[derive(Debug)]
pub(crate) struct Pos {
    mark: libyaml::Mark,
    path: String,
}

/// The input location that an error occured.
#[derive(Debug)]
pub struct Location {
    index: usize,
    line: usize,
    column: usize,
}

impl Location {
    /// The byte index of the error
    pub fn index(&self) -> usize {
        self.index
    }

    /// The line of the error
    pub fn line(&self) -> usize {
        self.line
    }

    /// The column of the error
    pub fn column(&self) -> usize {
        self.column
    }

    // This is to keep decoupled with the yaml crate
    #[doc(hidden)]
    fn from_mark(mark: libyaml::Mark) -> Self {
        Location {
            index: mark.index() as usize,
            // `line` and `column` returned from libyaml are 0-indexed but all error messages add +1 to this value
            line: mark.line() as usize + 1,
            column: mark.column() as usize + 1,
        }
    }
}

impl Error {
    /// Returns the Location from the error if one exists.
    ///
    /// Not all types of errors have a location so this can return `None`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use serde_yaml::{Value, Error};
    /// #
    /// // The `@` character as the first character makes this invalid yaml
    /// let invalid_yaml: Result<Value, Error> = serde_yaml::from_str("@invalid_yaml");
    ///
    /// let location = invalid_yaml.unwrap_err().location().unwrap();
    ///
    /// assert_eq!(location.line(), 1);
    /// assert_eq!(location.column(), 1);
    /// ```
    pub fn location(&self) -> Option<Location> {
        self.0.location()
    }
}

pub(crate) fn new(inner: ErrorImpl) -> Error {
    Error(Box::new(inner))
}

pub(crate) fn shared(shared: Arc<ErrorImpl>) -> Error {
    Error(Box::new(ErrorImpl::Shared(shared)))
}

pub(crate) fn fix_mark(mut error: Error, mark: libyaml::Mark, path: Path) -> Error {
    if let ErrorImpl::Message(_, none @ None) = error.0.as_mut() {
        *none = Some(Pos {
            mark,
            path: path.to_string(),
        });
    }
    error
}

impl Error {
    pub(crate) fn shared(self) -> Arc<ErrorImpl> {
        if let ErrorImpl::Shared(err) = *self.0 {
            err
        } else {
            Arc::from(self.0)
        }
    }
}

impl From<libyaml::Error> for Error {
    fn from(err: libyaml::Error) -> Self {
        Error(Box::new(ErrorImpl::Libyaml(err)))
    }
}

impl From<emitter::Error> for Error {
    fn from(err: emitter::Error) -> Self {
        match err {
            emitter::Error::Libyaml(err) => Self::from(err),
            emitter::Error::Io(err) => new(ErrorImpl::Io(err)),
        }
    }
}

impl error::Error for Error {
    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
        self.0.source()
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.display(f)
    }
}

// Remove two layers of verbosity from the debug representation. Humans often
// end up seeing this representation because it is what unwrap() shows.
impl Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.debug(f)
    }
}

impl ser::Error for Error {
    fn custom<T: Display>(msg: T) -> Self {
        Error(Box::new(ErrorImpl::Message(msg.to_string(), None)))
    }
}

impl de::Error for Error {
    fn custom<T: Display>(msg: T) -> Self {
        Error(Box::new(ErrorImpl::Message(msg.to_string(), None)))
    }
}

impl ErrorImpl {
    fn location(&self) -> Option<Location> {
        self.mark().map(Location::from_mark)
    }

    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
        match self {
            ErrorImpl::Io(err) => Some(err),
            ErrorImpl::FromUtf8(err) => Some(err),
            ErrorImpl::Shared(err) => err.source(),
            _ => None,
        }
    }

    fn mark(&self) -> Option<libyaml::Mark> {
        match self {
            ErrorImpl::Message(_, Some(Pos { mark, path: _ }))
            | ErrorImpl::RecursionLimitExceeded(mark)
            | ErrorImpl::UnknownAnchor(mark) => Some(*mark),
            ErrorImpl::Libyaml(err) => Some(err.mark()),
            ErrorImpl::Shared(err) => err.mark(),
            _ => None,
        }
    }

    fn message_no_mark(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            ErrorImpl::Message(msg, None) => f.write_str(msg),
            ErrorImpl::Message(msg, Some(Pos { mark: _, path })) => {
                if path != "." {
                    write!(f, "{}: ", path)?;
                }
                f.write_str(msg)
            }
            ErrorImpl::Libyaml(_) => unreachable!(),
            ErrorImpl::Io(err) => Display::fmt(err, f),
            ErrorImpl::FromUtf8(err) => Display::fmt(err, f),
            ErrorImpl::EndOfStream => f.write_str("EOF while parsing a value"),
            ErrorImpl::MoreThanOneDocument => f.write_str(
                "deserializing from YAML containing more than one document is not supported",
            ),
            ErrorImpl::RecursionLimitExceeded(_mark) => f.write_str("recursion limit exceeded"),
            ErrorImpl::RepetitionLimitExceeded => f.write_str("repetition limit exceeded"),
            ErrorImpl::BytesUnsupported => {
                f.write_str("serialization and deserialization of bytes in YAML is not implemented")
            }
            ErrorImpl::UnknownAnchor(_mark) => f.write_str("unknown anchor"),
            ErrorImpl::SerializeNestedEnum => {
                f.write_str("serializing nested enums in YAML is not supported yet")
            }
            ErrorImpl::ScalarInMerge => {
                f.write_str("expected a mapping or list of mappings for merging, but found scalar")
            }
            ErrorImpl::TaggedInMerge => f.write_str("unexpected tagged value in merge"),
            ErrorImpl::ScalarInMergeElement => {
                f.write_str("expected a mapping for merging, but found scalar")
            }
            ErrorImpl::SequenceInMergeElement => {
                f.write_str("expected a mapping for merging, but found sequence")
            }
            ErrorImpl::Shared(_) => unreachable!(),
        }
    }

    fn display(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            ErrorImpl::Libyaml(err) => Display::fmt(err, f),
            ErrorImpl::Shared(err) => err.display(f),
            _ => {
                self.message_no_mark(f)?;
                if let Some(mark) = self.mark() {
                    if mark.line() != 0 || mark.column() != 0 {
                        write!(f, " at {}", mark)?;
                    }
                }
                Ok(())
            }
        }
    }

    fn debug(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            ErrorImpl::Message(msg, pos) => f.debug_tuple("Message").field(msg).field(pos).finish(),
            ErrorImpl::Libyaml(err) => f.debug_tuple("Libyaml").field(err).finish(),
            ErrorImpl::Io(io) => f.debug_tuple("Io").field(io).finish(),
            ErrorImpl::FromUtf8(from_utf8) => f.debug_tuple("FromUtf8").field(from_utf8).finish(),
            ErrorImpl::EndOfStream => f.write_str("EndOfStream"),
            ErrorImpl::MoreThanOneDocument => f.write_str("MoreThanOneDocument"),
            ErrorImpl::RecursionLimitExceeded(mark) => {
                f.debug_tuple("RecursionLimitExceeded").field(mark).finish()
            }
            ErrorImpl::RepetitionLimitExceeded => f.write_str("RepetitionLimitExceeded"),
            ErrorImpl::BytesUnsupported => f.write_str("BytesUnsupported"),
            ErrorImpl::UnknownAnchor(mark) => f.debug_tuple("UnknownAnchor").field(mark).finish(),
            ErrorImpl::SerializeNestedEnum => f.write_str("SerializeNestedEnum"),
            ErrorImpl::ScalarInMerge => f.write_str("ScalarInMerge"),
            ErrorImpl::TaggedInMerge => f.write_str("TaggedInMerge"),
            ErrorImpl::ScalarInMergeElement => f.write_str("ScalarInMergeElement"),
            ErrorImpl::SequenceInMergeElement => f.write_str("SequenceInMergeElement"),
            ErrorImpl::Shared(err) => err.debug(f),
        }
    }
}
<commit_msg>Condense Error's Debug format in a way to include whole message<commit_after>use crate::libyaml::{emitter, error as libyaml};
use crate::path::Path;
use serde::{de, ser};
use std::error;
use std::fmt::{self, Debug, Display};
use std::io;
use std::result;
use std::string;
use std::sync::Arc;

/// An error that happened serializing or deserializing YAML data.
pub struct Error(Box<ErrorImpl>);

/// Alias for a `Result` with the error type `serde_yaml::Error`.
pub type Result<T> = result::Result<T, Error>;

#[derive(Debug)]
pub(crate) enum ErrorImpl {
    Message(String, Option<Pos>),

    Libyaml(libyaml::Error),
    Io(io::Error),
    FromUtf8(string::FromUtf8Error),

    EndOfStream,
    MoreThanOneDocument,
    RecursionLimitExceeded(libyaml::Mark),
    RepetitionLimitExceeded,
    BytesUnsupported,
    UnknownAnchor(libyaml::Mark),
    SerializeNestedEnum,
    ScalarInMerge,
    TaggedInMerge,
    ScalarInMergeElement,
    SequenceInMergeElement,

    Shared(Arc<ErrorImpl>),
}

#[derive(Debug)]
pub(crate) struct Pos {
    mark: libyaml::Mark,
    path: String,
}

/// The input location that an error occured.
#[derive(Debug)]
pub struct Location {
    index: usize,
    line: usize,
    column: usize,
}

impl Location {
    /// The byte index of the error
    pub fn index(&self) -> usize {
        self.index
    }

    /// The line of the error
    pub fn line(&self) -> usize {
        self.line
    }

    /// The column of the error
    pub fn column(&self) -> usize {
        self.column
    }

    // This is to keep decoupled with the yaml crate
    #[doc(hidden)]
    fn from_mark(mark: libyaml::Mark) -> Self {
        Location {
            index: mark.index() as usize,
            // `line` and `column` returned from libyaml are 0-indexed but all error messages add +1 to this value
            line: mark.line() as usize + 1,
            column: mark.column() as usize + 1,
        }
    }
}

impl Error {
    /// Returns the Location from the error if one exists.
    ///
    /// Not all types of errors have a location so this can return `None`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use serde_yaml::{Value, Error};
    /// #
    /// // The `@` character as the first character makes this invalid yaml
    /// let invalid_yaml: Result<Value, Error> = serde_yaml::from_str("@invalid_yaml");
    ///
    /// let location = invalid_yaml.unwrap_err().location().unwrap();
    ///
    /// assert_eq!(location.line(), 1);
    /// assert_eq!(location.column(), 1);
    /// ```
    pub fn location(&self) -> Option<Location> {
        self.0.location()
    }
}

pub(crate) fn new(inner: ErrorImpl) -> Error {
    Error(Box::new(inner))
}

pub(crate) fn shared(shared: Arc<ErrorImpl>) -> Error {
    Error(Box::new(ErrorImpl::Shared(shared)))
}

pub(crate) fn fix_mark(mut error: Error, mark: libyaml::Mark, path: Path) -> Error {
    if let ErrorImpl::Message(_, none @ None) = error.0.as_mut() {
        *none = Some(Pos {
            mark,
            path: path.to_string(),
        });
    }
    error
}

impl Error {
    pub(crate) fn shared(self) -> Arc<ErrorImpl> {
        if let ErrorImpl::Shared(err) = *self.0 {
            err
        } else {
            Arc::from(self.0)
        }
    }
}

impl From<libyaml::Error> for Error {
    fn from(err: libyaml::Error) -> Self {
        Error(Box::new(ErrorImpl::Libyaml(err)))
    }
}

impl From<emitter::Error> for Error {
    fn from(err: emitter::Error) -> Self {
        match err {
            emitter::Error::Libyaml(err) => Self::from(err),
            emitter::Error::Io(err) => new(ErrorImpl::Io(err)),
        }
    }
}

impl error::Error for Error {
    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
        self.0.source()
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.display(f)
    }
}

// Remove two layers of verbosity from the debug representation. Humans often
// end up seeing this representation because it is what unwrap() shows.
impl Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.debug(f)
    }
}

impl ser::Error for Error {
    fn custom<T: Display>(msg: T) -> Self {
        Error(Box::new(ErrorImpl::Message(msg.to_string(), None)))
    }
}

impl de::Error for Error {
    fn custom<T: Display>(msg: T) -> Self {
        Error(Box::new(ErrorImpl::Message(msg.to_string(), None)))
    }
}

impl ErrorImpl {
    fn location(&self) -> Option<Location> {
        self.mark().map(Location::from_mark)
    }

    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
        match self {
            ErrorImpl::Io(err) => Some(err),
            ErrorImpl::FromUtf8(err) => Some(err),
            ErrorImpl::Shared(err) => err.source(),
            _ => None,
        }
    }

    fn mark(&self) -> Option<libyaml::Mark> {
        match self {
            ErrorImpl::Message(_, Some(Pos { mark, path: _ }))
            | ErrorImpl::RecursionLimitExceeded(mark)
            | ErrorImpl::UnknownAnchor(mark) => Some(*mark),
            ErrorImpl::Libyaml(err) => Some(err.mark()),
            ErrorImpl::Shared(err) => err.mark(),
            _ => None,
        }
    }

    fn message_no_mark(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            ErrorImpl::Message(msg, None) => f.write_str(msg),
            ErrorImpl::Message(msg, Some(Pos { mark: _, path })) => {
                if path != "." {
                    write!(f, "{}: ", path)?;
                }
                f.write_str(msg)
            }
            ErrorImpl::Libyaml(_) => unreachable!(),
            ErrorImpl::Io(err) => Display::fmt(err, f),
            ErrorImpl::FromUtf8(err) => Display::fmt(err, f),
            ErrorImpl::EndOfStream => f.write_str("EOF while parsing a value"),
            ErrorImpl::MoreThanOneDocument => f.write_str(
                "deserializing from YAML containing more than one document is not supported",
            ),
            ErrorImpl::RecursionLimitExceeded(_mark) => f.write_str("recursion limit exceeded"),
            ErrorImpl::RepetitionLimitExceeded => f.write_str("repetition limit exceeded"),
            ErrorImpl::BytesUnsupported => {
                f.write_str("serialization and deserialization of bytes in YAML is not implemented")
            }
            ErrorImpl::UnknownAnchor(_mark) => f.write_str("unknown anchor"),
            ErrorImpl::SerializeNestedEnum => {
                f.write_str("serializing nested enums in YAML is not supported yet")
            }
            ErrorImpl::ScalarInMerge => {
                f.write_str("expected a mapping or list of mappings for merging, but found scalar")
            }
            ErrorImpl::TaggedInMerge => f.write_str("unexpected tagged value in merge"),
            ErrorImpl::ScalarInMergeElement => {
                f.write_str("expected a mapping for merging, but found scalar")
            }
            ErrorImpl::SequenceInMergeElement => {
                f.write_str("expected a mapping for merging, but found sequence")
            }
            ErrorImpl::Shared(_) => unreachable!(),
        }
    }

    fn display(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            ErrorImpl::Libyaml(err) => Display::fmt(err, f),
            ErrorImpl::Shared(err) => err.display(f),
            _ => {
                self.message_no_mark(f)?;
                if let Some(mark) = self.mark() {
                    if mark.line() != 0 || mark.column() != 0 {
                        write!(f, " at {}", mark)?;
                    }
                }
                Ok(())
            }
        }
    }

    fn debug(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            ErrorImpl::Libyaml(err) => Debug::fmt(err, f),
            ErrorImpl::Shared(err) => err.debug(f),
            _ => {
                f.write_str("Error(")?;
                struct MessageNoMark<'a>(&'a ErrorImpl);
                impl<'a> Display for MessageNoMark<'a> {
                    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                        self.0.message_no_mark(f)
                    }
                }
                let msg = MessageNoMark(self).to_string();
                Debug::fmt(&msg, f)?;
                if let Some(mark) = self.mark() {
                    write!(
                        f,
                        ", line: {}, column: {}",
                        mark.line() + 1,
                        mark.column() + 1,
                    )?;
                }
                f.write_str(")")
            }
        }
    }
}
<|endoftext|>


<commit_before>use crate::builtins::Blob;
use crate::io::{DecodeError, Wasmbin, WasmbinDecode, WasmbinEncode};
use crate::sections::{Section, StdPayload};
use crate::visit::WasmbinVisit;
use arbitrary::Arbitrary;
use std::cmp::Ordering;

const MAGIC_AND_VERSION: [u8; 8] = [b'\0', b'a', b's', b'm', 0x01, 0x00, 0x00, 0x00];

#[derive(Debug, Default, Arbitrary, PartialEq, Eq, Hash, Clone, WasmbinVisit)]
struct MagicAndVersion;

impl WasmbinEncode for MagicAndVersion {
    fn encode(&self, w: &mut impl std::io::Write) -> std::io::Result<()> {
        w.write_all(&MAGIC_AND_VERSION)
    }
}

impl WasmbinDecode for MagicAndVersion {
    fn decode(r: &mut impl std::io::Read) -> Result<Self, DecodeError> {
        let mut magic_and_version = [0; 8];
        r.read_exact(&mut magic_and_version)?;
        if magic_and_version != MAGIC_AND_VERSION {
            return Err(DecodeError::InvalidMagic);
        }
        Ok(MagicAndVersion)
    }
}

#[derive(Wasmbin, Debug, Default, Arbitrary, PartialEq, Eq, Hash, Clone, WasmbinVisit)]
pub struct Module {
    magic_and_version: MagicAndVersion,
    pub sections: Vec<Section>,
}

impl Module {
    pub fn find_std_section<T: StdPayload>(&self) -> Option<&Blob<T>> {
        self.sections.iter().find_map(|section| section.try_as())
    }

    pub fn find_std_section_mut<T: StdPayload>(&mut self) -> Option<&mut Blob<T>> {
        self.sections
            .iter_mut()
            .find_map(|section| section.try_as_mut())
    }

    pub fn find_or_insert_std_section<T: StdPayload>(
        &mut self,
        insert_callback: impl FnOnce() -> T,
    ) -> &mut Blob<T> {
        let mut index = self.sections.len();
        let mut insert = true;
        for (i, section) in self.sections.iter_mut().enumerate() {
            match section.kind().cmp(&T::KIND) {
                Ordering::Less => continue,
                Ordering::Equal => {
                    // We can't just `return` here due to a bug in rustc:
                    // https://github.com/rust-lang/rust/issues/70255
                    insert = false;
                }
                Ordering::Greater => {}
            }
            index = i;
            break;
        }
        if insert {
            self.sections.insert(index, insert_callback().into());
        }
        unsafe { self.sections.get_unchecked_mut(index) }
            .try_as_mut()
            .unwrap_or_else(|| unsafe { std::hint::unreachable_unchecked() })
    }
}
<commit_msg>Expose MagicAndVersion<commit_after>use crate::builtins::Blob;
use crate::io::{DecodeError, Wasmbin, WasmbinDecode, WasmbinEncode};
use crate::sections::{Section, StdPayload};
use crate::visit::WasmbinVisit;
use arbitrary::Arbitrary;
use std::cmp::Ordering;

const MAGIC_AND_VERSION: [u8; 8] = [b'\0', b'a', b's', b'm', 0x01, 0x00, 0x00, 0x00];

#[derive(Debug, Default, Arbitrary, PartialEq, Eq, Hash, Clone, WasmbinVisit)]
pub struct MagicAndVersion;

impl WasmbinEncode for MagicAndVersion {
    fn encode(&self, w: &mut impl std::io::Write) -> std::io::Result<()> {
        w.write_all(&MAGIC_AND_VERSION)
    }
}

impl WasmbinDecode for MagicAndVersion {
    fn decode(r: &mut impl std::io::Read) -> Result<Self, DecodeError> {
        let mut magic_and_version = [0; 8];
        r.read_exact(&mut magic_and_version)?;
        if magic_and_version != MAGIC_AND_VERSION {
            return Err(DecodeError::InvalidMagic);
        }
        Ok(MagicAndVersion)
    }
}

#[derive(Wasmbin, Debug, Default, Arbitrary, PartialEq, Eq, Hash, Clone, WasmbinVisit)]
pub struct Module {
    magic_and_version: MagicAndVersion,
    pub sections: Vec<Section>,
}

impl Module {
    pub fn find_std_section<T: StdPayload>(&self) -> Option<&Blob<T>> {
        self.sections.iter().find_map(|section| section.try_as())
    }

    pub fn find_std_section_mut<T: StdPayload>(&mut self) -> Option<&mut Blob<T>> {
        self.sections
            .iter_mut()
            .find_map(|section| section.try_as_mut())
    }

    pub fn find_or_insert_std_section<T: StdPayload>(
        &mut self,
        insert_callback: impl FnOnce() -> T,
    ) -> &mut Blob<T> {
        let mut index = self.sections.len();
        let mut insert = true;
        for (i, section) in self.sections.iter_mut().enumerate() {
            match section.kind().cmp(&T::KIND) {
                Ordering::Less => continue,
                Ordering::Equal => {
                    // We can't just `return` here due to a bug in rustc:
                    // https://github.com/rust-lang/rust/issues/70255
                    insert = false;
                }
                Ordering::Greater => {}
            }
            index = i;
            break;
        }
        if insert {
            self.sections.insert(index, insert_callback().into());
        }
        unsafe { self.sections.get_unchecked_mut(index) }
            .try_as_mut()
            .unwrap_or_else(|| unsafe { std::hint::unreachable_unchecked() })
    }
}
<|endoftext|>


<commit_before>//! Items in the scene heirarchy.

use std::fmt;
use std::hash::{Hash, Hasher};
use std::sync::mpsc;

use mint;

use audio;
use camera::Camera;
use hub::{Hub, Message, Operation, SubLight, SubNode};
use light;
use mesh::Mesh;
use node::NodePointer;
use scene::SyncGuard;
use skeleton::{Bone, Skeleton};
use sprite::Sprite;
use text::Text;

//Note: no local state should be here, only remote links
/// `Base` represents a concrete entity that can be added to the scene.
///
/// One cannot construct `Base` directly. Wrapper types such as [`Camera`],
/// [`Mesh`], and [`Group`] are provided instead.
///
/// Any type that implements [`Object`] may be converted to its concrete
/// `Base` type with the method [`Object::upcast`]. This is useful for
/// storing generic objects in containers.
///
/// [`Camera`]: ../camera/struct.Camera.html
/// [`Mesh`]: ../mesh/struct.Mesh.html
/// [`Group`]: ../object/struct.Group.html
/// [`Object`]: ../object/trait.Object.html
/// [`Object::upcast`]: ../object/trait.Object.html#method.upcast
#[derive(Clone)]
pub struct Base {
    pub(crate) node: NodePointer,
    pub(crate) tx: mpsc::Sender<Message>,
}

/// Marks data structures that are able to added to the scene graph.
pub trait Object: AsRef<Base> {
    /// The internal data for the object.
    ///
    /// Three-rs objects normally expose a write-only interface, making it possible to change
    /// an object's internal values but not possible to read those values.
    /// [`SyncGuard::resolve_data`] allows for that data to be read in a controlled way, with.
    /// the data for the specific object type determined by the `Data` trait member.
    ///
    /// Each object type has its own internal data, and not all object types can provide access
    /// to meaningful data. Types that cannot provide user-facing data will specify `()`
    /// for `Data`.
    ///
    /// [`SyncGuard::resolve_data`]: ./scene/struct.SyncGuard.html#method.resolve_data
    type Data;

    /// Retrieves the internal data for the object.
    ///
    /// Prefer to use [`SyncGuard::resolve_data`] over calling this directly.
    ///
    /// [`SyncGuard::resolve_data`]: ./scene/struct.SyncGuard.html#method.resolve_data
    fn resolve_data(&self, sync_guard: &SyncGuard) -> Self::Data;

    /// Converts into the base type.
    fn upcast(&self) -> Base {
        self.as_ref().clone()
    }

    /// Invisible objects are not rendered by cameras.
    fn set_visible(
        &self,
        visible: bool,
    ) {
        self.as_ref().send(Operation::SetVisible(visible));
    }

    /// Sets the name of the object.
    fn set_name<S: Into<String>>(
        &self,
        name: S,
    ) {
        self.as_ref().send(Operation::SetName(name.into()));
    }

    /// Set both position, orientation and scale.
    fn set_transform<P, Q>(
        &self,
        pos: P,
        rot: Q,
        scale: f32,
    ) where
        Self: Sized,
        P: Into<mint::Point3<f32>>,
        Q: Into<mint::Quaternion<f32>>,
    {
        self.as_ref().send(Operation::SetTransform(Some(pos.into()), Some(rot.into()), Some(scale)));
    }

    /// Set position.
    fn set_position<P>(
        &self,
        pos: P,
    ) where
        Self: Sized,
        P: Into<mint::Point3<f32>>,
    {
        self.as_ref().send(Operation::SetTransform(Some(pos.into()), None, None));
    }

    /// Set orientation.
    fn set_orientation<Q>(
        &self,
        rot: Q,
    ) where
        Self: Sized,
        Q: Into<mint::Quaternion<f32>>,
    {
        self.as_ref().send(Operation::SetTransform(None, Some(rot.into()), None));
    }

    /// Set scale.
    fn set_scale(
        &self,
        scale: f32,
    ) {
        self.as_ref().send(Operation::SetTransform(None, None, Some(scale)));
    }

    /// Set weights.
    //Note: needed for animations
    fn set_weights(
        &self,
        weights: Vec<f32>,
    ) {
        self.as_ref().send(Operation::SetWeights(weights));
    }

    /// Rotates object in the specific direction of `target`.
    fn look_at<E, T>(
        &self,
        eye: E,
        target: T,
        up: Option<mint::Vector3<f32>>,
    ) where
        Self: Sized,
        E: Into<mint::Point3<f32>>,
        T: Into<mint::Point3<f32>>,
    {
        use cgmath::{InnerSpace, Point3, Quaternion, Rotation, Vector3};
        let p: [mint::Point3<f32>; 2] = [eye.into(), target.into()];
        let dir = (Point3::from(p[0]) - Point3::from(p[1])).normalize();
        let z = Vector3::unit_z();
        let up = match up {
            Some(v) => Vector3::from(v).normalize(),
            None if dir.dot(z).abs() < 0.99 => z,
            None => Vector3::unit_y(),
        };
        let q = Quaternion::look_at(dir, up).invert();
        self.set_transform(p[0], q, 1.0);
    }
}

impl PartialEq for Base {
    fn eq(
        &self,
        other: &Base,
    ) -> bool {
        self.node == other.node
    }
}

impl Eq for Base {}

impl Hash for Base {
    fn hash<H: Hasher>(
        &self,
        state: &mut H,
    ) {
        self.node.hash(state);
    }
}

impl fmt::Debug for Base {
    fn fmt(
        &self,
        f: &mut fmt::Formatter,
    ) -> fmt::Result {
        self.node.fmt(f)
    }
}

impl Base {
    pub(crate) fn send(
        &self,
        operation: Operation,
    ) {
        let _ = self.tx.send((self.node.downgrade(), operation));
    }
}

// Required for `Base` to implement `trait Object`.
impl AsRef<Base> for Base {
    fn as_ref(&self) -> &Base {
        self
    }
}

impl Object for Base {
    type Data = ObjectType;

    fn resolve_data(&self, sync_guard: &SyncGuard) -> Self::Data {
        let node = &sync_guard.hub[self];
        match &node.sub_node {
            // TODO: Handle resolving cameras better (`Empty` is only used for cameras).
            SubNode::Camera(..) => ObjectType::Camera(Camera {
                object: self.clone(),
            }),

            SubNode::Group { .. } => ObjectType::Group(Group {
                object: self.clone(),
            }),

            SubNode::Audio(..) => ObjectType::AudioSource(audio::Source {
                object: self.clone(),
            }),

            SubNode::UiText(..) => ObjectType::Text(Text {
                object: self.clone(),
            }),

            // TODO: Differentiate between `Mesh` and `DynamicMesh`.
            SubNode::Visual(..) => ObjectType::Mesh(Mesh {
                object: self.clone(),
            }),

            SubNode::Bone { .. } => ObjectType::Bone(Bone {
                object: self.clone(),
            }),

            SubNode::Skeleton(..) => ObjectType::Skeleton(Skeleton {
                object: self.clone(),
            }),

            SubNode::Light(light) => match light.sub_light {
                SubLight::Ambient => ObjectType::AmbientLight(light::Ambient {
                    object: self.clone(),
                }),

                SubLight::Directional => ObjectType::DirectionalLight(light::Directional {
                    object: self.clone(),
                }),

                SubLight::Point => ObjectType::PointLight(light::Point {
                    object: self.clone(),
                }),

                SubLight::Hemisphere { .. } => ObjectType::HemisphereLight(light::Hemisphere {
                    object: self.clone(),
                }),
            },
        }
    }
}

/// The possible concrete types that a [`Base`] can be resolved to.
///
/// When using [`SyncGuard::resolve_data`] with a [`Base`], it returns an `ObjectType`
/// containing the concrete object for the [`Base`].
///
/// [`Base`]: ./struct.Base.html
/// [`SyncGuard::resolve_data`]: ../scene/struct.SyncGuard.html#method.resolve_data
#[derive(Debug, Clone)]
pub enum ObjectType {
    /// An audio source.
    AudioSource(audio::Source),

    /// An ambient light.
    AmbientLight(light::Ambient),

    /// A directional light.
    DirectionalLight(light::Directional),

    /// A hemisphere light.
    HemisphereLight(light::Hemisphere),

    /// A point light.
    PointLight(light::Point),

    /// A mesh.
    Mesh(Mesh),

    /// A group.
    Group(Group),

    /// A skeleton.
    Skeleton(Skeleton),

    /// A bone in a skeleton.
    Bone(Bone),

    /// A 2D sprite.
    Sprite(Sprite),

    /// A UI text object.
    Text(Text),

    /// A camera.
    Camera(Camera),
}

/// Marks an object type that can be downcast from a [`Base`].
///
/// See [`SyncGuard::downcast`] for information on how this trait is used.
///
/// [`Base`]: ./struct.Base.html
/// [`SyncGuard::downcast`]: ../scene/struct.SyncGuard.html#method.downcast
pub trait DowncastObject: Sized {
    /// Attempts to extract the concrete type of the object from an [`ObjectType`].
    ///
    /// Prefer to use [`SyncGuard::downcast`] over calling this directly.
    ///
    /// [`ObjectType`]: ./enum.ObjectType.html
    /// [`SyncGuard::downcast`]: ../scene/struct.SyncGuard.html#method.downcast
    fn downcast(object: ObjectType) -> Option<Self>;
}

/// Groups are used to combine several other objects or groups to work with them
/// as with a single entity.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Group {
    object: Base,
}

impl AsRef<Base> for Group {
    fn as_ref(&self) -> &Base { &self.object }
}

impl Object for Group {
    type Data = Vec<Base>;

    fn resolve_data(&self, sync_guard: &SyncGuard) -> Vec<Base> {
        let mut children = Vec::new();
        let node = &sync_guard.hub[self];

        let mut child = match node.sub_node {
            SubNode::Group { ref first_child } => first_child.clone(),
            _ => panic!("`Group` had a bad sub node type: {:?}", node.sub_node),
        };

        while let Some(child_pointer) = child {
            child = sync_guard.hub.nodes[&child_pointer].next_sibling.clone();

            children.push(Base {
                node: child_pointer,
                tx: sync_guard.hub.message_tx.clone(),
            });
        }

        children
    }
}

derive_DowncastObject!(Group => ObjectType::Group);

impl Group {
    pub(crate) fn new(hub: &mut Hub) -> Self {
        let sub = SubNode::Group { first_child: None };
        Group {
            object: hub.spawn(sub),
        }
    }

    /// Add new [`Object`](trait.Object.html) to the group.
    pub fn add<T: Object>(
        &self,
        child: &T,
    ) {
        let node = child.as_ref().node.clone();
        self.as_ref().send(Operation::AddChild(node));
    }

    /// Removes a child [`Object`](trait.Object.html) from the group.
    pub fn remove<T: Object>(
        &self,
        child: &T,
    ) {
        let node = child.as_ref().node.clone();
        self.as_ref().send(Operation::RemoveChild(node));
    }
}
<commit_msg>Make Object a super-trait for DowncastObject<commit_after>//! Items in the scene heirarchy.

use std::fmt;
use std::hash::{Hash, Hasher};
use std::sync::mpsc;

use mint;

use audio;
use camera::Camera;
use hub::{Hub, Message, Operation, SubLight, SubNode};
use light;
use mesh::Mesh;
use node::NodePointer;
use scene::SyncGuard;
use skeleton::{Bone, Skeleton};
use sprite::Sprite;
use text::Text;

//Note: no local state should be here, only remote links
/// `Base` represents a concrete entity that can be added to the scene.
///
/// One cannot construct `Base` directly. Wrapper types such as [`Camera`],
/// [`Mesh`], and [`Group`] are provided instead.
///
/// Any type that implements [`Object`] may be converted to its concrete
/// `Base` type with the method [`Object::upcast`]. This is useful for
/// storing generic objects in containers.
///
/// [`Camera`]: ../camera/struct.Camera.html
/// [`Mesh`]: ../mesh/struct.Mesh.html
/// [`Group`]: ../object/struct.Group.html
/// [`Object`]: ../object/trait.Object.html
/// [`Object::upcast`]: ../object/trait.Object.html#method.upcast
#[derive(Clone)]
pub struct Base {
    pub(crate) node: NodePointer,
    pub(crate) tx: mpsc::Sender<Message>,
}

/// Marks data structures that are able to added to the scene graph.
pub trait Object: AsRef<Base> {
    /// The internal data for the object.
    ///
    /// Three-rs objects normally expose a write-only interface, making it possible to change
    /// an object's internal values but not possible to read those values.
    /// [`SyncGuard::resolve_data`] allows for that data to be read in a controlled way, with.
    /// the data for the specific object type determined by the `Data` trait member.
    ///
    /// Each object type has its own internal data, and not all object types can provide access
    /// to meaningful data. Types that cannot provide user-facing data will specify `()`
    /// for `Data`.
    ///
    /// [`SyncGuard::resolve_data`]: ./scene/struct.SyncGuard.html#method.resolve_data
    type Data;

    /// Retrieves the internal data for the object.
    ///
    /// Prefer to use [`SyncGuard::resolve_data`] over calling this directly.
    ///
    /// [`SyncGuard::resolve_data`]: ./scene/struct.SyncGuard.html#method.resolve_data
    fn resolve_data(&self, sync_guard: &SyncGuard) -> Self::Data;

    /// Converts into the base type.
    fn upcast(&self) -> Base {
        self.as_ref().clone()
    }

    /// Invisible objects are not rendered by cameras.
    fn set_visible(
        &self,
        visible: bool,
    ) {
        self.as_ref().send(Operation::SetVisible(visible));
    }

    /// Sets the name of the object.
    fn set_name<S: Into<String>>(
        &self,
        name: S,
    ) {
        self.as_ref().send(Operation::SetName(name.into()));
    }

    /// Set both position, orientation and scale.
    fn set_transform<P, Q>(
        &self,
        pos: P,
        rot: Q,
        scale: f32,
    ) where
        Self: Sized,
        P: Into<mint::Point3<f32>>,
        Q: Into<mint::Quaternion<f32>>,
    {
        self.as_ref().send(Operation::SetTransform(Some(pos.into()), Some(rot.into()), Some(scale)));
    }

    /// Set position.
    fn set_position<P>(
        &self,
        pos: P,
    ) where
        Self: Sized,
        P: Into<mint::Point3<f32>>,
    {
        self.as_ref().send(Operation::SetTransform(Some(pos.into()), None, None));
    }

    /// Set orientation.
    fn set_orientation<Q>(
        &self,
        rot: Q,
    ) where
        Self: Sized,
        Q: Into<mint::Quaternion<f32>>,
    {
        self.as_ref().send(Operation::SetTransform(None, Some(rot.into()), None));
    }

    /// Set scale.
    fn set_scale(
        &self,
        scale: f32,
    ) {
        self.as_ref().send(Operation::SetTransform(None, None, Some(scale)));
    }

    /// Set weights.
    //Note: needed for animations
    fn set_weights(
        &self,
        weights: Vec<f32>,
    ) {
        self.as_ref().send(Operation::SetWeights(weights));
    }

    /// Rotates object in the specific direction of `target`.
    fn look_at<E, T>(
        &self,
        eye: E,
        target: T,
        up: Option<mint::Vector3<f32>>,
    ) where
        Self: Sized,
        E: Into<mint::Point3<f32>>,
        T: Into<mint::Point3<f32>>,
    {
        use cgmath::{InnerSpace, Point3, Quaternion, Rotation, Vector3};
        let p: [mint::Point3<f32>; 2] = [eye.into(), target.into()];
        let dir = (Point3::from(p[0]) - Point3::from(p[1])).normalize();
        let z = Vector3::unit_z();
        let up = match up {
            Some(v) => Vector3::from(v).normalize(),
            None if dir.dot(z).abs() < 0.99 => z,
            None => Vector3::unit_y(),
        };
        let q = Quaternion::look_at(dir, up).invert();
        self.set_transform(p[0], q, 1.0);
    }
}

impl PartialEq for Base {
    fn eq(
        &self,
        other: &Base,
    ) -> bool {
        self.node == other.node
    }
}

impl Eq for Base {}

impl Hash for Base {
    fn hash<H: Hasher>(
        &self,
        state: &mut H,
    ) {
        self.node.hash(state);
    }
}

impl fmt::Debug for Base {
    fn fmt(
        &self,
        f: &mut fmt::Formatter,
    ) -> fmt::Result {
        self.node.fmt(f)
    }
}

impl Base {
    pub(crate) fn send(
        &self,
        operation: Operation,
    ) {
        let _ = self.tx.send((self.node.downgrade(), operation));
    }
}

// Required for `Base` to implement `trait Object`.
impl AsRef<Base> for Base {
    fn as_ref(&self) -> &Base {
        self
    }
}

impl Object for Base {
    type Data = ObjectType;

    fn resolve_data(&self, sync_guard: &SyncGuard) -> Self::Data {
        let node = &sync_guard.hub[self];
        match &node.sub_node {
            // TODO: Handle resolving cameras better (`Empty` is only used for cameras).
            SubNode::Camera(..) => ObjectType::Camera(Camera {
                object: self.clone(),
            }),

            SubNode::Group { .. } => ObjectType::Group(Group {
                object: self.clone(),
            }),

            SubNode::Audio(..) => ObjectType::AudioSource(audio::Source {
                object: self.clone(),
            }),

            SubNode::UiText(..) => ObjectType::Text(Text {
                object: self.clone(),
            }),

            // TODO: Differentiate between `Mesh` and `DynamicMesh`.
            SubNode::Visual(..) => ObjectType::Mesh(Mesh {
                object: self.clone(),
            }),

            SubNode::Bone { .. } => ObjectType::Bone(Bone {
                object: self.clone(),
            }),

            SubNode::Skeleton(..) => ObjectType::Skeleton(Skeleton {
                object: self.clone(),
            }),

            SubNode::Light(light) => match light.sub_light {
                SubLight::Ambient => ObjectType::AmbientLight(light::Ambient {
                    object: self.clone(),
                }),

                SubLight::Directional => ObjectType::DirectionalLight(light::Directional {
                    object: self.clone(),
                }),

                SubLight::Point => ObjectType::PointLight(light::Point {
                    object: self.clone(),
                }),

                SubLight::Hemisphere { .. } => ObjectType::HemisphereLight(light::Hemisphere {
                    object: self.clone(),
                }),
            },
        }
    }
}

/// The possible concrete types that a [`Base`] can be resolved to.
///
/// When using [`SyncGuard::resolve_data`] with a [`Base`], it returns an `ObjectType`
/// containing the concrete object for the [`Base`].
///
/// [`Base`]: ./struct.Base.html
/// [`SyncGuard::resolve_data`]: ../scene/struct.SyncGuard.html#method.resolve_data
#[derive(Debug, Clone)]
pub enum ObjectType {
    /// An audio source.
    AudioSource(audio::Source),

    /// An ambient light.
    AmbientLight(light::Ambient),

    /// A directional light.
    DirectionalLight(light::Directional),

    /// A hemisphere light.
    HemisphereLight(light::Hemisphere),

    /// A point light.
    PointLight(light::Point),

    /// A mesh.
    Mesh(Mesh),

    /// A group.
    Group(Group),

    /// A skeleton.
    Skeleton(Skeleton),

    /// A bone in a skeleton.
    Bone(Bone),

    /// A 2D sprite.
    Sprite(Sprite),

    /// A UI text object.
    Text(Text),

    /// A camera.
    Camera(Camera),
}

/// Marks an object type that can be downcast from a [`Base`].
///
/// See [`SyncGuard::downcast`] for information on how this trait is used.
///
/// [`Base`]: ./struct.Base.html
/// [`SyncGuard::downcast`]: ../scene/struct.SyncGuard.html#method.downcast
pub trait DowncastObject: Object + Sized {
    /// Attempts to extract the concrete type of the object from an [`ObjectType`].
    ///
    /// Prefer to use [`SyncGuard::downcast`] over calling this directly.
    ///
    /// [`ObjectType`]: ./enum.ObjectType.html
    /// [`SyncGuard::downcast`]: ../scene/struct.SyncGuard.html#method.downcast
    fn downcast(object: ObjectType) -> Option<Self>;
}

/// Groups are used to combine several other objects or groups to work with them
/// as with a single entity.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Group {
    object: Base,
}

impl AsRef<Base> for Group {
    fn as_ref(&self) -> &Base { &self.object }
}

impl Object for Group {
    type Data = Vec<Base>;

    fn resolve_data(&self, sync_guard: &SyncGuard) -> Vec<Base> {
        let mut children = Vec::new();
        let node = &sync_guard.hub[self];

        let mut child = match node.sub_node {
            SubNode::Group { ref first_child } => first_child.clone(),
            _ => panic!("`Group` had a bad sub node type: {:?}", node.sub_node),
        };

        while let Some(child_pointer) = child {
            child = sync_guard.hub.nodes[&child_pointer].next_sibling.clone();

            children.push(Base {
                node: child_pointer,
                tx: sync_guard.hub.message_tx.clone(),
            });
        }

        children
    }
}

derive_DowncastObject!(Group => ObjectType::Group);

impl Group {
    pub(crate) fn new(hub: &mut Hub) -> Self {
        let sub = SubNode::Group { first_child: None };
        Group {
            object: hub.spawn(sub),
        }
    }

    /// Add new [`Object`](trait.Object.html) to the group.
    pub fn add<T: Object>(
        &self,
        child: &T,
    ) {
        let node = child.as_ref().node.clone();
        self.as_ref().send(Operation::AddChild(node));
    }

    /// Removes a child [`Object`](trait.Object.html) from the group.
    pub fn remove<T: Object>(
        &self,
        child: &T,
    ) {
        let node = child.as_ref().node.clone();
        self.as_ref().send(Operation::RemoveChild(node));
    }
}
<|endoftext|>


<commit_before>extern crate num;
extern crate nalgebra as na;

pub const TOTAL_FLUIDS: usize = 8;
pub const NORMAL_DIFFUSION: [f64; TOTAL_FLUIDS] = [0.0004, 4.0, 0.2, 2.0, 0.5, 0.5, 0.5, 0.5];
pub const KILL_FLUID_NORMAL: f64 = 0.05;
pub const KILL_FLUID_DECAY: f64 = 0.01;
pub const KILL_FLUID_UPPER_THRESHOLD: f64 = 0.052;
pub const KILL_FLUID_LOWER_THRESHOLD: f64 = 0.048;
pub const SIGNAL_FLUID_NORMAL: f64 = 0.5;
pub const SIGNAL_FLUID_DECAY: f64 = 0.001;
pub const B_FOOD_RATE: f64 = 0.02;

const TIMESTEP: f64 = 0.2;

#[derive(Default, Debug)]
pub struct Solution {
    pub fluids: [f64; TOTAL_FLUIDS],
    pub coefficients: [f64; TOTAL_FLUIDS],
    pub diffuse: [f64; TOTAL_FLUIDS],
}

impl Solution {
    pub fn new(fluids: [f64; TOTAL_FLUIDS], coefficients: [f64; TOTAL_FLUIDS]) -> Self {
        Solution {
            fluids: fluids,
            coefficients: coefficients,
            diffuse: [0.0; TOTAL_FLUIDS],
        }
    }

    pub fn react_deltas(&self) -> [f64; TOTAL_FLUIDS] {
        let a = self.fluids[1];
        let b = self.fluids[3];
        let kill = self.fluids[2];
        let f = 0.029;
        let k = 0.057;
        [B_FOOD_RATE * b,
         -a * b * b + f * (1.0 - a),
         KILL_FLUID_DECAY * (KILL_FLUID_NORMAL - kill),
         a * b * b - (k + f) * b,
         SIGNAL_FLUID_DECAY * (SIGNAL_FLUID_NORMAL - self.fluids[4]),
         SIGNAL_FLUID_DECAY * (SIGNAL_FLUID_NORMAL - self.fluids[5]),
         SIGNAL_FLUID_DECAY * (SIGNAL_FLUID_NORMAL - self.fluids[6]),
         SIGNAL_FLUID_DECAY * (SIGNAL_FLUID_NORMAL - self.fluids[7])]
    }

    pub fn diffuse_from(&mut self, other: &Solution) {
        for i in 0..TOTAL_FLUIDS {
            self.diffuse[i] += other.fluids[i] * other.coefficients[i] / 6.0;
        }
    }

    pub fn end_cycle(&mut self) {
        let reacts = self.react_deltas();
        for i in 0..TOTAL_FLUIDS {
            self.fluids[i] += TIMESTEP *
                              (reacts[i] + self.diffuse[i] - self.coefficients[i] * self.fluids[i]);
            self.diffuse[i] = 0.0;
        }
    }
}
<commit_msg>increase difficulty<commit_after>extern crate num;
extern crate nalgebra as na;

pub const TOTAL_FLUIDS: usize = 8;
pub const NORMAL_DIFFUSION: [f64; TOTAL_FLUIDS] = [0.0004, 4.0, 0.2, 2.0, 0.5, 0.5, 0.5, 0.5];
pub const KILL_FLUID_NORMAL: f64 = 0.05;
pub const KILL_FLUID_DECAY: f64 = 0.01;
pub const KILL_FLUID_UPPER_THRESHOLD: f64 = 0.052;
pub const KILL_FLUID_LOWER_THRESHOLD: f64 = 0.048;
pub const SIGNAL_FLUID_NORMAL: f64 = 0.5;
pub const SIGNAL_FLUID_DECAY: f64 = 0.001;
pub const B_FOOD_RATE: f64 = 0.015;

const TIMESTEP: f64 = 0.2;

#[derive(Default, Debug)]
pub struct Solution {
    pub fluids: [f64; TOTAL_FLUIDS],
    pub coefficients: [f64; TOTAL_FLUIDS],
    pub diffuse: [f64; TOTAL_FLUIDS],
}

impl Solution {
    pub fn new(fluids: [f64; TOTAL_FLUIDS], coefficients: [f64; TOTAL_FLUIDS]) -> Self {
        Solution {
            fluids: fluids,
            coefficients: coefficients,
            diffuse: [0.0; TOTAL_FLUIDS],
        }
    }

    pub fn react_deltas(&self) -> [f64; TOTAL_FLUIDS] {
        let a = self.fluids[1];
        let b = self.fluids[3];
        let kill = self.fluids[2];
        let f = 0.029;
        let k = 0.057;
        [B_FOOD_RATE * b,
         -a * b * b + f * (1.0 - a),
         KILL_FLUID_DECAY * (KILL_FLUID_NORMAL - kill),
         a * b * b - (k + f) * b,
         SIGNAL_FLUID_DECAY * (SIGNAL_FLUID_NORMAL - self.fluids[4]),
         SIGNAL_FLUID_DECAY * (SIGNAL_FLUID_NORMAL - self.fluids[5]),
         SIGNAL_FLUID_DECAY * (SIGNAL_FLUID_NORMAL - self.fluids[6]),
         SIGNAL_FLUID_DECAY * (SIGNAL_FLUID_NORMAL - self.fluids[7])]
    }

    pub fn diffuse_from(&mut self, other: &Solution) {
        for i in 0..TOTAL_FLUIDS {
            self.diffuse[i] += other.fluids[i] * other.coefficients[i] / 6.0;
        }
    }

    pub fn end_cycle(&mut self) {
        let reacts = self.react_deltas();
        for i in 0..TOTAL_FLUIDS {
            self.fluids[i] += TIMESTEP *
                              (reacts[i] + self.diffuse[i] - self.coefficients[i] * self.fluids[i]);
            self.diffuse[i] = 0.0;
        }
    }
}
<|endoftext|>


<commit_before>use color::Color;

/// To be used as a parameter for defining the aesthetic
/// of the widget frame.
#[derive(Copy, Clone)]
pub enum Framing {
    /// Frame width and color.
    Frame(f64, Color),
    NoFrame,
}

/// A trait used for "colorable" widget context types.
pub trait Frameable {
    fn frame(self, width: f64) -> Self;
    fn frame_color(self, color: Color) -> Self;
    fn frame_rgba(self, r: f32, g: f32, b: f32, a: f32) -> Self;
}

/// Frame width property.
#[derive(Copy, Clone)]
pub struct FrameWidth(pub f64);

/// Frame color property.
#[derive(Copy, Clone)]
pub struct FrameColor(pub Color);

/*
impl<T> Frameable for T
    where
        (FrameWidth, T): Pair<Data = FrameWidth, Object = T> + SetAt,
        (FrameColor, T): Pair<Data = FrameColor, Object = T> + SetAt
{
    fn frame(self, width: f64) -> Self {
        self.set(FrameWidth(width))
    }

    fn frame_color(self, color: Color) -> Self {
        self.set(FrameColor(color))
    }

    fn frame_rgba(self, r: f32, g: f32, b: f32, a: f32) -> Self {
        self.set(FrameColor(Color([r, g, b, a])))
    }
}
*/
<commit_msg>Made `Frame::frame_rgba` a provided trait method<commit_after>use color::Color;

/// To be used as a parameter for defining the aesthetic
/// of the widget frame.
#[derive(Copy, Clone)]
pub enum Framing {
    /// Frame width and color.
    Frame(f64, Color),
    NoFrame,
}

/// A trait used for "colorable" widget context types.
pub trait Frameable: Sized {
    fn frame(self, width: f64) -> Self;
    fn frame_color(self, color: Color) -> Self;
    fn frame_rgba(self, r: f32, g: f32, b: f32, a: f32) -> Self {
        self.frame_color(Color([r, g, b, a]))
    }
}

/// Frame width property.
#[derive(Copy, Clone)]
pub struct FrameWidth(pub f64);

/// Frame color property.
#[derive(Copy, Clone)]
pub struct FrameColor(pub Color);

/*
impl<T> Frameable for T
    where
        (FrameWidth, T): Pair<Data = FrameWidth, Object = T> + SetAt,
        (FrameColor, T): Pair<Data = FrameColor, Object = T> + SetAt
{
    fn frame(self, width: f64) -> Self {
        self.set(FrameWidth(width))
    }

    fn frame_color(self, color: Color) -> Self {
        self.set(FrameColor(color))
    }

    fn frame_rgba(self, r: f32, g: f32, b: f32, a: f32) -> Self {
        self.set(FrameColor(Color([r, g, b, a])))
    }
}
*/
<|endoftext|>