<commit_before>//! Various helpers for Actix applications to use during testing.
use std::cell::RefCell;
use std::rc::Rc;

use actix_http::http::header::{Header, HeaderName, IntoHeaderValue};
use actix_http::http::{HttpTryFrom, Method, StatusCode, Version};
use actix_http::test::TestRequest as HttpTestRequest;
use actix_http::{Extensions, PayloadStream, Request};
use actix_router::{Path, ResourceDef, Url};
use actix_rt::Runtime;
use actix_server_config::ServerConfig;
use actix_service::{FnService, IntoNewService, NewService, Service};
use bytes::Bytes;
#[cfg(feature = "cookies")]
use cookie::Cookie;
use futures::future::{lazy, Future};

use crate::config::{AppConfig, AppConfigInner};
use crate::data::RouteData;
use crate::dev::Body;
use crate::rmap::ResourceMap;
use crate::service::{ServiceFromRequest, ServiceRequest, ServiceResponse};
use crate::{Error, HttpRequest, HttpResponse};

thread_local! {
    static RT: RefCell<Runtime> = {
        RefCell::new(Runtime::new().unwrap())
    };
}

/// Runs the provided future, blocking the current thread until the future
/// completes.
///
/// This function can be used to synchronously block the current thread
/// until the provided `future` has resolved either successfully or with an
/// error. The result of the future is then returned from this function
/// call.
///
/// Note that this function is intended to be used only for testing purpose.
/// This function panics on nested call.
pub fn block_on<F>(f: F) -> Result<F::Item, F::Error>
where
    F: Future,
{
    RT.with(move |rt| rt.borrow_mut().block_on(f))
}

/// Runs the provided function, with runtime enabled.
///
/// Note that this function is intended to be used only for testing purpose.
/// This function panics on nested call.
pub fn run_on<F, I, E>(f: F) -> Result<I, E>
where
    F: Fn() -> Result<I, E>,
{
    RT.with(move |rt| rt.borrow_mut().block_on(lazy(f)))
}

pub fn ok_service() -> impl Service<
    Request = ServiceRequest<PayloadStream>,
    Response = ServiceResponse<Body>,
    Error = Error,
> {
    default_service(StatusCode::OK)
}

pub fn default_service(
    status_code: StatusCode,
) -> impl Service<
    Request = ServiceRequest<PayloadStream>,
    Response = ServiceResponse<Body>,
    Error = Error,
> {
    FnService::new(move |req: ServiceRequest<PayloadStream>| {
        req.into_response(HttpResponse::build(status_code).finish())
    })
}

/// This method accepts application builder instance, and constructs
/// service.
///
/// ```rust,ignore
/// use actix_web::{test, App, HttpResponse, http::StatusCode};
/// use actix_service::Service;
///
/// fn main() {
///     let mut app = test::init_service(
///         App::new()
///             .resource("/test", |r| r.to(|| HttpResponse::Ok()))
///     );
///
///     // Create request object
///     let req = test::TestRequest::with_uri("/test").to_request();
///
///     // Execute application
///     let resp = test::block_on(app.call(req)).unwrap();
///     assert_eq!(resp.status(), StatusCode::OK);
/// }
/// ```
pub fn init_service<R, S, B, E>(
    app: R,
) -> impl Service<Request = Request, Response = ServiceResponse<B>, Error = E>
where
    R: IntoNewService<S, ServerConfig>,
    S: NewService<
        ServerConfig,
        Request = Request,
        Response = ServiceResponse<B>,
        Error = E,
    >,
    S::InitError: std::fmt::Debug,
{
    let cfg = ServerConfig::new("127.0.0.1:8080".parse().unwrap());
    block_on(app.into_new_service().new_service(&cfg)).unwrap()
}

/// Calls service and waits for response future completion.
///
/// ```rust,ignore
/// use actix_web::{test, App, HttpResponse, http::StatusCode};
/// use actix_service::Service;
///
/// fn main() {
///     let mut app = test::init_service(
///         App::new()
///             .resource("/test", |r| r.to(|| HttpResponse::Ok()))
///     );
///
///     // Create request object
///     let req = test::TestRequest::with_uri("/test").to_request();
///
///     // Call application
///     let resp = test::call_succ_service(&mut app, req);
///     assert_eq!(resp.status(), StatusCode::OK);
/// }
/// ```
pub fn call_success<S, R, B, E>(app: &mut S, req: R) -> S::Response
where
    S: Service<Request = R, Response = ServiceResponse<B>, Error = E>,
    E: std::fmt::Debug,
{
    block_on(app.call(req)).unwrap()
}

/// Test `Request` builder.
///
/// For unit testing, actix provides a request builder type and a simple handler runner. TestRequest implements a builder-like pattern.
/// You can generate various types of request via TestRequest's methods:
///  * `TestRequest::to_request` creates `actix_http::Request` instance.
///  * `TestRequest::to_service` creates `ServiceRequest` instance, which is used for testing middlewares and chain adapters.
///  * `TestRequest::to_from` creates `ServiceFromRequest` instance, which is used for testing extractors.
///  * `TestRequest::to_http_request` creates `HttpRequest` instance, which is used for testing handlers.
///
/// ```rust,ignore
/// # use futures::IntoFuture;
/// use actix_web::{test, HttpRequest, HttpResponse, HttpMessage};
/// use actix_web::http::{header, StatusCode};
///
/// fn index(req: HttpRequest) -> HttpResponse {
///     if let Some(hdr) = req.headers().get(header::CONTENT_TYPE) {
///         HttpResponse::Ok().into()
///     } else {
///         HttpResponse::BadRequest().into()
///     }
/// }
///
/// fn main() {
///     let req = test::TestRequest::with_header("content-type", "text/plain")
///         .to_http_request();
///
///     let resp = test::block_on(index(req).into_future()).unwrap();
///     assert_eq!(resp.status(), StatusCode::OK);
///
///     let req = test::TestRequest::default().to_http_request();
///     let resp = test::block_on(index(req).into_future()).unwrap();
///     assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
/// }
/// ```
pub struct TestRequest {
    req: HttpTestRequest,
    rmap: ResourceMap,
    config: AppConfigInner,
    route_data: Extensions,
}

impl Default for TestRequest {
    fn default() -> TestRequest {
        TestRequest {
            req: HttpTestRequest::default(),
            rmap: ResourceMap::new(ResourceDef::new("")),
            config: AppConfigInner::default(),
            route_data: Extensions::new(),
        }
    }
}

#[allow(clippy::wrong_self_convention)]
impl TestRequest {
    /// Create TestRequest and set request uri
    pub fn with_uri(path: &str) -> TestRequest {
        TestRequest {
            req: HttpTestRequest::default().uri(path).take(),
            rmap: ResourceMap::new(ResourceDef::new("")),
            config: AppConfigInner::default(),
            route_data: Extensions::new(),
        }
    }

    /// Create TestRequest and set header
    pub fn with_hdr<H: Header>(hdr: H) -> TestRequest {
        TestRequest {
            req: HttpTestRequest::default().set(hdr).take(),
            config: AppConfigInner::default(),
            rmap: ResourceMap::new(ResourceDef::new("")),
            route_data: Extensions::new(),
        }
    }

    /// Create TestRequest and set header
    pub fn with_header<K, V>(key: K, value: V) -> TestRequest
    where
        HeaderName: HttpTryFrom<K>,
        V: IntoHeaderValue,
    {
        TestRequest {
            req: HttpTestRequest::default().header(key, value).take(),
            config: AppConfigInner::default(),
            rmap: ResourceMap::new(ResourceDef::new("")),
            route_data: Extensions::new(),
        }
    }

    /// Create TestRequest and set method to `Method::GET`
    pub fn get() -> TestRequest {
        TestRequest {
            req: HttpTestRequest::default().method(Method::GET).take(),
            config: AppConfigInner::default(),
            rmap: ResourceMap::new(ResourceDef::new("")),
            route_data: Extensions::new(),
        }
    }

    /// Create TestRequest and set method to `Method::POST`
    pub fn post() -> TestRequest {
        TestRequest {
            req: HttpTestRequest::default().method(Method::POST).take(),
            config: AppConfigInner::default(),
            rmap: ResourceMap::new(ResourceDef::new("")),
            route_data: Extensions::new(),
        }
    }

    /// Set HTTP version of this request
    pub fn version(mut self, ver: Version) -> Self {
        self.req.version(ver);
        self
    }

    /// Set HTTP method of this request
    pub fn method(mut self, meth: Method) -> Self {
        self.req.method(meth);
        self
    }

    /// Set HTTP Uri of this request
    pub fn uri(mut self, path: &str) -> Self {
        self.req.uri(path);
        self
    }

    /// Set a header
    pub fn set<H: Header>(mut self, hdr: H) -> Self {
        self.req.set(hdr);
        self
    }

    /// Set a header
    pub fn header<K, V>(mut self, key: K, value: V) -> Self
    where
        HeaderName: HttpTryFrom<K>,
        V: IntoHeaderValue,
    {
        self.req.header(key, value);
        self
    }

    #[cfg(feature = "cookies")]
    /// Set cookie for this request
    pub fn cookie(mut self, cookie: Cookie) -> Self {
        self.req.cookie(cookie);
        self
    }

    /// Set request payload
    pub fn set_payload<B: Into<Bytes>>(mut self, data: B) -> Self {
        self.req.set_payload(data);
        self
    }

    /// Set application data. This is equivalent of `App::data()` method
    /// for testing purpose.
    pub fn app_data<T: 'static>(self, data: T) -> Self {
        self.config.extensions.borrow_mut().insert(data);
        self
    }

    /// Set route data. This is equivalent of `Route::data()` method
    /// for testing purpose.
    pub fn route_data<T: 'static>(mut self, data: T) -> Self {
        self.route_data.insert(RouteData::new(data));
        self
    }

    #[cfg(test)]
    /// Set request config
    pub(crate) fn rmap(mut self, rmap: ResourceMap) -> Self {
        self.rmap = rmap;
        self
    }

    /// Complete request creation and generate `ServiceRequest` instance
    pub fn to_service(mut self) -> ServiceRequest<PayloadStream> {
        let req = self.req.finish();

        ServiceRequest::new(
            Path::new(Url::new(req.uri().clone())),
            req,
            Rc::new(self.rmap),
            AppConfig::new(self.config),
        )
    }

    /// Complete request creation and generate `Request` instance
    pub fn to_request(mut self) -> Request<PayloadStream> {
        self.req.finish()
    }

    /// Complete request creation and generate `ServiceResponse` instance
    pub fn to_response<B>(self, res: HttpResponse<B>) -> ServiceResponse<B> {
        self.to_service().into_response(res)
    }

    /// Complete request creation and generate `HttpRequest` instance
    pub fn to_http_request(mut self) -> HttpRequest {
        let req = self.req.finish();

        ServiceRequest::new(
            Path::new(Url::new(req.uri().clone())),
            req,
            Rc::new(self.rmap),
            AppConfig::new(self.config),
        )
        .into_request()
    }

    /// Complete request creation and generate `ServiceFromRequest` instance
    pub fn to_from(mut self) -> ServiceFromRequest<PayloadStream> {
        let req = self.req.finish();

        let req = ServiceRequest::new(
            Path::new(Url::new(req.uri().clone())),
            req,
            Rc::new(self.rmap),
            AppConfig::new(self.config),
        );
        ServiceFromRequest::new(req, Some(Rc::new(self.route_data)))
    }

    /// Runs the provided future, blocking the current thread until the future
    /// completes.
    ///
    /// This function can be used to synchronously block the current thread
    /// until the provided `future` has resolved either successfully or with an
    /// error. The result of the future is then returned from this function
    /// call.
    ///
    /// Note that this function is intended to be used only for testing purpose.
    /// This function panics on nested call.
    pub fn block_on<F>(f: F) -> Result<F::Item, F::Error>
    where
        F: Future,
    {
        block_on(f)
    }
}
<commit_msg>update test doc string<commit_after>//! Various helpers for Actix applications to use during testing.
use std::cell::RefCell;
use std::rc::Rc;

use actix_http::http::header::{Header, HeaderName, IntoHeaderValue};
use actix_http::http::{HttpTryFrom, Method, StatusCode, Version};
use actix_http::test::TestRequest as HttpTestRequest;
use actix_http::{Extensions, PayloadStream, Request};
use actix_router::{Path, ResourceDef, Url};
use actix_rt::Runtime;
use actix_server_config::ServerConfig;
use actix_service::{FnService, IntoNewService, NewService, Service};
use bytes::Bytes;
#[cfg(feature = "cookies")]
use cookie::Cookie;
use futures::future::{lazy, Future};

use crate::config::{AppConfig, AppConfigInner};
use crate::data::RouteData;
use crate::dev::Body;
use crate::rmap::ResourceMap;
use crate::service::{ServiceFromRequest, ServiceRequest, ServiceResponse};
use crate::{Error, HttpRequest, HttpResponse};

thread_local! {
    static RT: RefCell<Runtime> = {
        RefCell::new(Runtime::new().unwrap())
    };
}

/// Runs the provided future, blocking the current thread until the future
/// completes.
///
/// This function can be used to synchronously block the current thread
/// until the provided `future` has resolved either successfully or with an
/// error. The result of the future is then returned from this function
/// call.
///
/// Note that this function is intended to be used only for testing purpose.
/// This function panics on nested call.
pub fn block_on<F>(f: F) -> Result<F::Item, F::Error>
where
    F: Future,
{
    RT.with(move |rt| rt.borrow_mut().block_on(f))
}

/// Runs the provided function, with runtime enabled.
///
/// Note that this function is intended to be used only for testing purpose.
/// This function panics on nested call.
pub fn run_on<F, I, E>(f: F) -> Result<I, E>
where
    F: Fn() -> Result<I, E>,
{
    RT.with(move |rt| rt.borrow_mut().block_on(lazy(f)))
}

pub fn ok_service() -> impl Service<
    Request = ServiceRequest<PayloadStream>,
    Response = ServiceResponse<Body>,
    Error = Error,
> {
    default_service(StatusCode::OK)
}

pub fn default_service(
    status_code: StatusCode,
) -> impl Service<
    Request = ServiceRequest<PayloadStream>,
    Response = ServiceResponse<Body>,
    Error = Error,
> {
    FnService::new(move |req: ServiceRequest<PayloadStream>| {
        req.into_response(HttpResponse::build(status_code).finish())
    })
}

/// This method accepts application builder instance, and constructs
/// service.
///
/// ```rust,ignore
/// use actix_service::Service;
/// use actix_web::{test, web, App, HttpResponse, http::StatusCode};
///
/// fn main() {
///     let mut app = test::init_service(
///         App::new()
///             .service(web::resource("/test").to(|| HttpResponse::Ok()))
///     );
///
///     // Create request object
///     let req = test::TestRequest::with_uri("/test").to_request();
///
///     // Execute application
///     let resp = test::block_on(app.call(req)).unwrap();
///     assert_eq!(resp.status(), StatusCode::OK);
/// }
/// ```
pub fn init_service<R, S, B, E>(
    app: R,
) -> impl Service<Request = Request, Response = ServiceResponse<B>, Error = E>
where
    R: IntoNewService<S, ServerConfig>,
    S: NewService<
        ServerConfig,
        Request = Request,
        Response = ServiceResponse<B>,
        Error = E,
    >,
    S::InitError: std::fmt::Debug,
{
    let cfg = ServerConfig::new("127.0.0.1:8080".parse().unwrap());
    block_on(app.into_new_service().new_service(&cfg)).unwrap()
}

/// Calls service and waits for response future completion.
///
/// ```rust,ignore
/// use actix_web::{test, App, HttpResponse, http::StatusCode};
/// use actix_service::Service;
///
/// fn main() {
///     let mut app = test::init_service(
///         App::new()
///             .service(web::resource("/test").to(|| HttpResponse::Ok()))
///     );
///
///     // Create request object
///     let req = test::TestRequest::with_uri("/test").to_request();
///
///     // Call application
///     let resp = test::call_succ_service(&mut app, req);
///     assert_eq!(resp.status(), StatusCode::OK);
/// }
/// ```
pub fn call_success<S, R, B, E>(app: &mut S, req: R) -> S::Response
where
    S: Service<Request = R, Response = ServiceResponse<B>, Error = E>,
    E: std::fmt::Debug,
{
    block_on(app.call(req)).unwrap()
}

/// Test `Request` builder.
///
/// For unit testing, actix provides a request builder type and a simple handler runner. TestRequest implements a builder-like pattern.
/// You can generate various types of request via TestRequest's methods:
///  * `TestRequest::to_request` creates `actix_http::Request` instance.
///  * `TestRequest::to_service` creates `ServiceRequest` instance, which is used for testing middlewares and chain adapters.
///  * `TestRequest::to_from` creates `ServiceFromRequest` instance, which is used for testing extractors.
///  * `TestRequest::to_http_request` creates `HttpRequest` instance, which is used for testing handlers.
///
/// ```rust,ignore
/// # use futures::IntoFuture;
/// use actix_web::{test, HttpRequest, HttpResponse, HttpMessage};
/// use actix_web::http::{header, StatusCode};
///
/// fn index(req: HttpRequest) -> HttpResponse {
///     if let Some(hdr) = req.headers().get(header::CONTENT_TYPE) {
///         HttpResponse::Ok().into()
///     } else {
///         HttpResponse::BadRequest().into()
///     }
/// }
///
/// fn main() {
///     let req = test::TestRequest::with_header("content-type", "text/plain")
///         .to_http_request();
///
///     let resp = test::block_on(index(req).into_future()).unwrap();
///     assert_eq!(resp.status(), StatusCode::OK);
///
///     let req = test::TestRequest::default().to_http_request();
///     let resp = test::block_on(index(req).into_future()).unwrap();
///     assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
/// }
/// ```
pub struct TestRequest {
    req: HttpTestRequest,
    rmap: ResourceMap,
    config: AppConfigInner,
    route_data: Extensions,
}

impl Default for TestRequest {
    fn default() -> TestRequest {
        TestRequest {
            req: HttpTestRequest::default(),
            rmap: ResourceMap::new(ResourceDef::new("")),
            config: AppConfigInner::default(),
            route_data: Extensions::new(),
        }
    }
}

#[allow(clippy::wrong_self_convention)]
impl TestRequest {
    /// Create TestRequest and set request uri
    pub fn with_uri(path: &str) -> TestRequest {
        TestRequest {
            req: HttpTestRequest::default().uri(path).take(),
            rmap: ResourceMap::new(ResourceDef::new("")),
            config: AppConfigInner::default(),
            route_data: Extensions::new(),
        }
    }

    /// Create TestRequest and set header
    pub fn with_hdr<H: Header>(hdr: H) -> TestRequest {
        TestRequest {
            req: HttpTestRequest::default().set(hdr).take(),
            config: AppConfigInner::default(),
            rmap: ResourceMap::new(ResourceDef::new("")),
            route_data: Extensions::new(),
        }
    }

    /// Create TestRequest and set header
    pub fn with_header<K, V>(key: K, value: V) -> TestRequest
    where
        HeaderName: HttpTryFrom<K>,
        V: IntoHeaderValue,
    {
        TestRequest {
            req: HttpTestRequest::default().header(key, value).take(),
            config: AppConfigInner::default(),
            rmap: ResourceMap::new(ResourceDef::new("")),
            route_data: Extensions::new(),
        }
    }

    /// Create TestRequest and set method to `Method::GET`
    pub fn get() -> TestRequest {
        TestRequest {
            req: HttpTestRequest::default().method(Method::GET).take(),
            config: AppConfigInner::default(),
            rmap: ResourceMap::new(ResourceDef::new("")),
            route_data: Extensions::new(),
        }
    }

    /// Create TestRequest and set method to `Method::POST`
    pub fn post() -> TestRequest {
        TestRequest {
            req: HttpTestRequest::default().method(Method::POST).take(),
            config: AppConfigInner::default(),
            rmap: ResourceMap::new(ResourceDef::new("")),
            route_data: Extensions::new(),
        }
    }

    /// Set HTTP version of this request
    pub fn version(mut self, ver: Version) -> Self {
        self.req.version(ver);
        self
    }

    /// Set HTTP method of this request
    pub fn method(mut self, meth: Method) -> Self {
        self.req.method(meth);
        self
    }

    /// Set HTTP Uri of this request
    pub fn uri(mut self, path: &str) -> Self {
        self.req.uri(path);
        self
    }

    /// Set a header
    pub fn set<H: Header>(mut self, hdr: H) -> Self {
        self.req.set(hdr);
        self
    }

    /// Set a header
    pub fn header<K, V>(mut self, key: K, value: V) -> Self
    where
        HeaderName: HttpTryFrom<K>,
        V: IntoHeaderValue,
    {
        self.req.header(key, value);
        self
    }

    #[cfg(feature = "cookies")]
    /// Set cookie for this request
    pub fn cookie(mut self, cookie: Cookie) -> Self {
        self.req.cookie(cookie);
        self
    }

    /// Set request payload
    pub fn set_payload<B: Into<Bytes>>(mut self, data: B) -> Self {
        self.req.set_payload(data);
        self
    }

    /// Set application data. This is equivalent of `App::data()` method
    /// for testing purpose.
    pub fn app_data<T: 'static>(self, data: T) -> Self {
        self.config.extensions.borrow_mut().insert(data);
        self
    }

    /// Set route data. This is equivalent of `Route::data()` method
    /// for testing purpose.
    pub fn route_data<T: 'static>(mut self, data: T) -> Self {
        self.route_data.insert(RouteData::new(data));
        self
    }

    #[cfg(test)]
    /// Set request config
    pub(crate) fn rmap(mut self, rmap: ResourceMap) -> Self {
        self.rmap = rmap;
        self
    }

    /// Complete request creation and generate `ServiceRequest` instance
    pub fn to_service(mut self) -> ServiceRequest<PayloadStream> {
        let req = self.req.finish();

        ServiceRequest::new(
            Path::new(Url::new(req.uri().clone())),
            req,
            Rc::new(self.rmap),
            AppConfig::new(self.config),
        )
    }

    /// Complete request creation and generate `Request` instance
    pub fn to_request(mut self) -> Request<PayloadStream> {
        self.req.finish()
    }

    /// Complete request creation and generate `ServiceResponse` instance
    pub fn to_response<B>(self, res: HttpResponse<B>) -> ServiceResponse<B> {
        self.to_service().into_response(res)
    }

    /// Complete request creation and generate `HttpRequest` instance
    pub fn to_http_request(mut self) -> HttpRequest {
        let req = self.req.finish();

        ServiceRequest::new(
            Path::new(Url::new(req.uri().clone())),
            req,
            Rc::new(self.rmap),
            AppConfig::new(self.config),
        )
        .into_request()
    }

    /// Complete request creation and generate `ServiceFromRequest` instance
    pub fn to_from(mut self) -> ServiceFromRequest<PayloadStream> {
        let req = self.req.finish();

        let req = ServiceRequest::new(
            Path::new(Url::new(req.uri().clone())),
            req,
            Rc::new(self.rmap),
            AppConfig::new(self.config),
        );
        ServiceFromRequest::new(req, Some(Rc::new(self.route_data)))
    }

    /// Runs the provided future, blocking the current thread until the future
    /// completes.
    ///
    /// This function can be used to synchronously block the current thread
    /// until the provided `future` has resolved either successfully or with an
    /// error. The result of the future is then returned from this function
    /// call.
    ///
    /// Note that this function is intended to be used only for testing purpose.
    /// This function panics on nested call.
    pub fn block_on<F>(f: F) -> Result<F::Item, F::Error>
    where
        F: Future,
    {
        block_on(f)
    }
}
<|endoftext|>


<commit_before>//! Undo API
use line_buffer::{ChangeListener, Direction, LineBuffer};
use std_unicode::str::UnicodeStr;
use unicode_segmentation::UnicodeSegmentation;

enum Action {
    Insert(String), // QuotedInsert, SelfInsert, Yank
    Delete(String), /* BackwardDeleteChar, BackwardKillWord, DeleteChar, KillLine, KillWholeLine, KillWord, UnixLikeDiscard, ViDeleteTo */
                    //Replace(String, String), /* CapitalizeWord, Complete, DowncaseWord, Replace, TransposeChars, TransposeWords, UpcaseWord, YankPop */
}

struct Change {
    idx: usize, // where the change happens
    action: Action,
}

impl Change {
    fn undo(&self, line: &mut LineBuffer) {
        match self.action {
            Action::Insert(ref text) => {
                line.delete_range(self.idx..self.idx + text.len());
            }
            Action::Delete(ref text) => {
                line.insert_str(self.idx, text);
                line.set_pos(self.idx + text.len());
            }
            /*Action::Replace(ref old, ref new) => {
                line.replace(self.idx..self.idx + new.len(), old);
            }*/
        }
    }

    #[cfg(test)]
    fn redo(&self, line: &mut LineBuffer) {
        match self.action {
            Action::Insert(ref text) => {
                line.insert_str(self.idx, text);
            }
            Action::Delete(ref text) => {
                line.delete_range(self.idx..self.idx + text.len());
            }
            /*Action::Replace(ref old, ref new) => {
                line.replace(self.idx..self.idx + old.len(), new);
            }*/
        }
    }

    fn insert_seq(&self, idx: usize) -> bool {
        if let Action::Insert(ref text) = self.action {
            self.idx + text.len() == idx
        } else {
            false
        }
    }

    fn delete_seq(&self, idx: usize, len: usize) -> bool {
        if let Action::Delete(_) = self.action {
            // delete or backspace
            self.idx == idx || self.idx == idx + len
        } else {
            false
        }
    }
}

pub struct Changeset {
    undos: Vec<Change>, // undoable changes
    redos: Vec<Change>, // undone changes, redoable
}

impl Changeset {
    pub fn new() -> Changeset {
        Changeset {
            undos: Vec::new(),
            redos: Vec::new(),
        }
    }

    fn insert_char(idx: usize, c: char) -> Change {
        let mut text = String::new();
        text.push(c);
        Change {
            idx: idx,
            action: Action::Insert(text),
        }
    }

    pub fn insert(&mut self, idx: usize, c: char) {
        self.redos.clear();
        if !c.is_alphanumeric() {
            self.undos.push(Self::insert_char(idx, c));
            return;
        }
        let last_change = self.undos.pop();
        match last_change {
            Some(last_change) => {
                // merge consecutive char insertions when char is alphanumeric
                if last_change.insert_seq(idx) {
                    let mut last_change = last_change;
                    if let Action::Insert(ref mut text) = last_change.action {
                        text.push(c);
                    } else {
                        unreachable!();
                    }
                    self.undos.push(last_change);
                } else {
                    self.undos.push(last_change);
                    self.undos.push(Self::insert_char(idx, c));
                }
            }
            None => {
                self.undos.push(Self::insert_char(idx, c));
            }
        };
    }

    pub fn insert_str<S: Into<String>>(&mut self, idx: usize, string: S) {
        self.redos.clear();
        self.undos.push(Change {
            idx: idx,
            action: Action::Insert(string.into()),
        });
    }

    pub fn delete<S: AsRef<str> + Into<String>>(&mut self, idx: usize, string: S) {
        self.redos.clear();

        if !Self::single_char(string.as_ref()) {
            self.undos.push(Change {
                idx: idx,
                action: Action::Delete(string.into()),
            });
            return;
        }
        let last_change = self.undos.pop();
        match last_change {
            Some(last_change) => {
                // merge consecutive char deletions when char is alphanumeric
                if last_change.delete_seq(idx, string.as_ref().len()) {
                    let mut last_change = last_change;
                    if let Action::Delete(ref mut text) = last_change.action {
                        if last_change.idx == idx {
                            text.push_str(string.as_ref());
                        } else {
                            text.insert_str(0, string.as_ref());
                            last_change.idx = idx;
                        }
                    } else {
                        unreachable!();
                    }
                    self.undos.push(last_change);
                } else {
                    self.undos.push(last_change);
                    self.undos.push(Change {
                        idx: idx,
                        action: Action::Delete(string.into()),
                    });
                }
            }
            None => {
                self.undos.push(Change {
                    idx: idx,
                    action: Action::Delete(string.into()),
                });
            }
        };
    }

    fn single_char(s: &str) -> bool {
        let mut graphemes = s.graphemes(true);
        graphemes.next().map_or(false, |grapheme| grapheme.is_alphanumeric()) &&
        graphemes.next().is_none()
    }

    /*pub fn replace<S: Into<String>>(&mut self, idx: usize, old: String, new: S) {
        self.redos.clear();
        self.undos.push(Change {
            idx: idx,
            action: Action::Replace(old.into(), new.into()),
        });
    }*/

    pub fn undo(&mut self, line: &mut LineBuffer) -> bool {
        match self.undos.pop() {
            Some(change) => {
                change.undo(line);
                self.redos.push(change);
                true
            }
            None => false,
        }
    }

    #[cfg(test)]
    pub fn redo(&mut self, line: &mut LineBuffer) -> bool {
        match self.redos.pop() {
            Some(change) => {
                change.redo(line);
                self.undos.push(change);
                true
            }
            None => false,
        }
    }
}

impl ChangeListener for Changeset {
    fn insert_char(&mut self, idx: usize, c: char) {
        self.insert(idx, c);
    }
    fn insert_str(&mut self, idx: usize, string: &str) {
        self.insert_str(idx, string);
    }
    fn delete(&mut self, idx: usize, string: &str, _: Direction) {
        self.delete(idx, string);
    }
}

#[cfg(test)]
mod tests {
    use super::Changeset;
    use line_buffer::LineBuffer;

    #[test]
    fn test_insert_chars() {
        let mut cs = Changeset::new();
        cs.insert(0, 'H');
        cs.insert(1, 'i');
        assert_eq!(1, cs.undos.len());
        assert_eq!(0, cs.redos.len());
        cs.insert(0, ' ');
        assert_eq!(2, cs.undos.len());
    }

    #[test]
    fn test_insert_strings() {
        let mut cs = Changeset::new();
        cs.insert_str(0, "Hello");
        cs.insert_str(5, ", ");
        assert_eq!(2, cs.undos.len());
        assert_eq!(0, cs.redos.len());
    }

    #[test]
    fn test_undo_insert() {
        let mut buf = LineBuffer::init("", 0, None);
        buf.insert_str(0, "Hello");
        buf.insert_str(5, ", world!");
        let mut cs = Changeset::new();
        assert_eq!(buf.as_str(), "Hello, world!");

        cs.insert_str(5, ", world!");

        cs.undo(&mut buf);
        assert_eq!(0, cs.undos.len());
        assert_eq!(1, cs.redos.len());
        assert_eq!(buf.as_str(), "Hello");

        cs.redo(&mut buf);
        assert_eq!(1, cs.undos.len());
        assert_eq!(0, cs.redos.len());
        assert_eq!(buf.as_str(), "Hello, world!");
    }

    #[test]
    fn test_undo_delete() {
        let mut buf = LineBuffer::init("", 0, None);
        buf.insert_str(0, "Hello");
        let mut cs = Changeset::new();
        assert_eq!(buf.as_str(), "Hello");

        cs.delete(5, ", world!".to_owned());

        cs.undo(&mut buf);
        assert_eq!(buf.as_str(), "Hello, world!");

        cs.redo(&mut buf);
        assert_eq!(buf.as_str(), "Hello");
    }

    #[test]
    fn test_delete_chars() {
        let mut buf = LineBuffer::init("", 0, None);
        buf.insert_str(0, "Hlo");

        let mut cs = Changeset::new();
        cs.delete(1, "e".to_owned());
        cs.delete(1, "l".to_owned());
        assert_eq!(1, cs.undos.len());

        cs.undo(&mut buf);
        assert_eq!(buf.as_str(), "Hello");
    }

    #[test]
    fn test_backspace_chars() {
        let mut buf = LineBuffer::init("", 0, None);
        buf.insert_str(0, "Hlo");

        let mut cs = Changeset::new();
        cs.delete(2, "l".to_owned());
        cs.delete(1, "e".to_owned());
        assert_eq!(1, cs.undos.len());

        cs.undo(&mut buf);
        assert_eq!(buf.as_str(), "Hello");
    }

    /*#[test]
    fn test_undo_replace() {
        let mut buf = LineBuffer::init("", 0, None);
        buf.insert_str(0, "Hello, world!");
        let mut cs = Changeset::new();
        assert_eq!(buf.as_str(), "Hello, world!");

        buf.replace(1..5, "i");
        assert_eq!(buf.as_str(), "Hi, world!");
        cs.replace(1, "ello".to_owned(), "i");

        cs.undo(&mut buf);
        assert_eq!(buf.as_str(), "Hello, world!");

        cs.redo(&mut buf);
        assert_eq!(buf.as_str(), "Hi, world!");
    }*/
}
<commit_msg>Introduce undo group (begin..end)<commit_after>//! Undo API
use line_buffer::{ChangeListener, Direction, LineBuffer};
use std_unicode::str::UnicodeStr;
use unicode_segmentation::UnicodeSegmentation;

enum Change {
    Begin,
    End,
    Insert { idx: usize, text: String }, // QuotedInsert, SelfInsert, Yank
    Delete { idx: usize, text: String }, /* BackwardDeleteChar, BackwardKillWord, DeleteChar, KillLine, KillWholeLine, KillWord, UnixLikeDiscard, ViDeleteTo */
                                         //  Replace {idx: usize, old: String, new: String}, /* CapitalizeWord, Complete, DowncaseWord, Replace, TransposeChars, TransposeWords, UpcaseWord, YankPop */
}

impl Change {
    fn undo(&self, line: &mut LineBuffer) {
        match *self {
            Change::Begin | Change::End => {
                unreachable!();
            }
            Change::Insert { idx, ref text } => {
                line.delete_range(idx..idx + text.len());
            }
            Change::Delete { idx, ref text } => {
                line.insert_str(idx, text);
                line.set_pos(idx + text.len());
            }
            /*Change::Replace{idx, ref old, ref new} => {
                line.replace(idx..idx + new.len(), old);
            }*/
        }
    }

    #[cfg(test)]
    fn redo(&self, line: &mut LineBuffer) {
        match *self {
            Change::Begin | Change::End => {
                unreachable!();
            }
            Change::Insert { idx, ref text } => {
                line.insert_str(idx, text);
            }
            Change::Delete { idx, ref text } => {
                line.delete_range(idx..idx + text.len());
            }
            /*Change::Replace{idx, ref old, ref new} => {
                line.replace(idx..idx + old.len(), new);
            }*/
        }
    }

    fn insert_seq(&self, indx: usize) -> bool {
        if let Change::Insert { idx, ref text } = *self {
            idx + text.len() == indx
        } else {
            false
        }
    }

    fn delete_seq(&self, indx: usize, len: usize) -> bool {
        if let Change::Delete { idx, .. } = *self {
            // delete or backspace
            idx == indx || idx == indx + len
        } else {
            false
        }
    }
}

pub struct Changeset {
    undos: Vec<Change>, // undoable changes
    redos: Vec<Change>, // undone changes, redoable
}

impl Changeset {
    pub fn new() -> Changeset {
        Changeset {
            undos: Vec::new(),
            redos: Vec::new(),
        }
    }

    pub fn begin(&mut self) {
        self.redos.clear();
        self.undos.push(Change::Begin);
    }

    pub fn end(&mut self) {
        self.redos.clear();
        self.undos.push(Change::End);
    }

    fn insert_char(idx: usize, c: char) -> Change {
        let mut text = String::new();
        text.push(c);
        Change::Insert {
            idx: idx,
            text: text,
        }
    }

    pub fn insert(&mut self, idx: usize, c: char) {
        self.redos.clear();
        if !c.is_alphanumeric() {
            self.undos.push(Self::insert_char(idx, c));
            return;
        }
        let last_change = self.undos.pop();
        match last_change {
            Some(last_change) => {
                // merge consecutive char insertions when char is alphanumeric
                if last_change.insert_seq(idx) {
                    let mut last_change = last_change;
                    if let Change::Insert { ref mut text, .. } = last_change {
                        text.push(c);
                    } else {
                        unreachable!();
                    }
                    self.undos.push(last_change);
                } else {
                    self.undos.push(last_change);
                    self.undos.push(Self::insert_char(idx, c));
                }
            }
            None => {
                self.undos.push(Self::insert_char(idx, c));
            }
        };
    }

    pub fn insert_str<S: Into<String>>(&mut self, idx: usize, string: S) {
        self.redos.clear();
        self.undos.push(Change::Insert {
            idx: idx,
            text: string.into(),
        });
    }

    pub fn delete<S: AsRef<str> + Into<String>>(&mut self, indx: usize, string: S) {
        self.redos.clear();

        if !Self::single_char(string.as_ref()) {
            self.undos.push(Change::Delete {
                idx: indx,
                text: string.into(),
            });
            return;
        }
        let last_change = self.undos.pop();
        match last_change {
            Some(last_change) => {
                // merge consecutive char deletions when char is alphanumeric
                if last_change.delete_seq(indx, string.as_ref().len()) {
                    let mut last_change = last_change;
                    if let Change::Delete { ref mut idx, ref mut text } = last_change {
                        if *idx == indx {
                            text.push_str(string.as_ref());
                        } else {
                            text.insert_str(0, string.as_ref());
                            *idx = indx;
                        }
                    } else {
                        unreachable!();
                    }
                    self.undos.push(last_change);
                } else {
                    self.undos.push(last_change);
                    self.undos.push(Change::Delete {
                        idx: indx,
                        text: string.into(),
                    });
                }
            }
            None => {
                self.undos.push(Change::Delete {
                    idx: indx,
                    text: string.into(),
                });
            }
        };
    }

    fn single_char(s: &str) -> bool {
        let mut graphemes = s.graphemes(true);
        graphemes.next().map_or(false, |grapheme| grapheme.is_alphanumeric()) &&
        graphemes.next().is_none()
    }

    /*pub fn replace<S: Into<String>>(&mut self, idx: usize, old: String, new: S) {
        self.redos.clear();
        self.undos.push(Change::Replace {
            idx: idx,
            old: old.into(),
            new: new.into(),
        });
    }*/

    pub fn undo(&mut self, line: &mut LineBuffer) -> bool {
        let mut waiting_for_begin = 0;
        let mut undone = false;
        loop {
            if let Some(change) = self.undos.pop() {
                match change {
                    Change::Begin => {
                        waiting_for_begin -= 1;
                    }
                    Change::End => {
                        waiting_for_begin += 1;
                    }
                    _ => {
                        change.undo(line);
                        self.redos.push(change);
                        undone = true;
                    }
                };
            }
            if waiting_for_begin == 0 {
                break;
            }
        }
        undone
    }

    #[cfg(test)]
    pub fn redo(&mut self, line: &mut LineBuffer) -> bool {
        let mut waiting_for_end = 0;
        let mut redone = false;
        loop {
            if let Some(change) = self.redos.pop() {
                match change {
                    Change::Begin => {
                        waiting_for_end += 1;
                    }
                    Change::End => {
                        waiting_for_end -= 1;
                    }
                    _ => {
                        change.redo(line);
                        self.undos.push(change);
                        redone = true;
                    }
                };
            }
            if waiting_for_end == 0 {
                break;
            }
        }
        redone
    }
}

impl ChangeListener for Changeset {
    fn insert_char(&mut self, idx: usize, c: char) {
        self.insert(idx, c);
    }
    fn insert_str(&mut self, idx: usize, string: &str) {
        self.insert_str(idx, string);
    }
    fn delete(&mut self, idx: usize, string: &str, _: Direction) {
        self.delete(idx, string);
    }
}

#[cfg(test)]
mod tests {
    use super::Changeset;
    use line_buffer::LineBuffer;

    #[test]
    fn test_insert_chars() {
        let mut cs = Changeset::new();
        cs.insert(0, 'H');
        cs.insert(1, 'i');
        assert_eq!(1, cs.undos.len());
        assert_eq!(0, cs.redos.len());
        cs.insert(0, ' ');
        assert_eq!(2, cs.undos.len());
    }

    #[test]
    fn test_insert_strings() {
        let mut cs = Changeset::new();
        cs.insert_str(0, "Hello");
        cs.insert_str(5, ", ");
        assert_eq!(2, cs.undos.len());
        assert_eq!(0, cs.redos.len());
    }

    #[test]
    fn test_undo_insert() {
        let mut buf = LineBuffer::init("", 0, None);
        buf.insert_str(0, "Hello");
        buf.insert_str(5, ", world!");
        let mut cs = Changeset::new();
        assert_eq!(buf.as_str(), "Hello, world!");

        cs.insert_str(5, ", world!");

        cs.undo(&mut buf);
        assert_eq!(0, cs.undos.len());
        assert_eq!(1, cs.redos.len());
        assert_eq!(buf.as_str(), "Hello");

        cs.redo(&mut buf);
        assert_eq!(1, cs.undos.len());
        assert_eq!(0, cs.redos.len());
        assert_eq!(buf.as_str(), "Hello, world!");
    }

    #[test]
    fn test_undo_delete() {
        let mut buf = LineBuffer::init("", 0, None);
        buf.insert_str(0, "Hello");
        let mut cs = Changeset::new();
        assert_eq!(buf.as_str(), "Hello");

        cs.delete(5, ", world!".to_owned());

        cs.undo(&mut buf);
        assert_eq!(buf.as_str(), "Hello, world!");

        cs.redo(&mut buf);
        assert_eq!(buf.as_str(), "Hello");
    }

    #[test]
    fn test_delete_chars() {
        let mut buf = LineBuffer::init("", 0, None);
        buf.insert_str(0, "Hlo");

        let mut cs = Changeset::new();
        cs.delete(1, "e".to_owned());
        cs.delete(1, "l".to_owned());
        assert_eq!(1, cs.undos.len());

        cs.undo(&mut buf);
        assert_eq!(buf.as_str(), "Hello");
    }

    #[test]
    fn test_backspace_chars() {
        let mut buf = LineBuffer::init("", 0, None);
        buf.insert_str(0, "Hlo");

        let mut cs = Changeset::new();
        cs.delete(2, "l".to_owned());
        cs.delete(1, "e".to_owned());
        assert_eq!(1, cs.undos.len());

        cs.undo(&mut buf);
        assert_eq!(buf.as_str(), "Hello");
    }

    /*#[test]
    fn test_undo_replace() {
        let mut buf = LineBuffer::init("", 0, None);
        buf.insert_str(0, "Hello, world!");
        let mut cs = Changeset::new();
        assert_eq!(buf.as_str(), "Hello, world!");

        buf.replace(1..5, "i");
        assert_eq!(buf.as_str(), "Hi, world!");
        cs.replace(1, "ello".to_owned(), "i");

        cs.undo(&mut buf);
        assert_eq!(buf.as_str(), "Hello, world!");

        cs.redo(&mut buf);
        assert_eq!(buf.as_str(), "Hi, world!");
    }*/
}
<|endoftext|>


<commit_before>/// unit creates a type representing a single unit.
///
/// # Examples
///
/// ```
/// #[macro_use(unit)]
/// extern crate fiz_math;
/// use std::fmt::Debug;
///
/// // GoldCoins are golden!
/// unit!(GoldCoins);
///
/// // SilverCoins are like gold coins, only worse!
/// unit!(SilverCoins);
///
/// fn collect<T: Debug>(coins: GoldCoins<T>) {
///     println!("We've collected {:?} golden coins!", coins.0);
/// }
///
/// fn main() {
///     let x = GoldCoins(5);
///     collect(x);
///
///     let y = SilverCoins(6);
///
///     // Try uncommenting the line below and see:
///     //
///     // error: mismatched types: expected `GoldCoins<_>`, found `SilverCoins<_>`"
///     //
///     //collect(y);
///
///     // add, subtract, multiply, divide:
///     assert_eq!(y + SilverCoins(4), SilverCoins(10));
///     assert_eq!(y - SilverCoins(3), SilverCoins(3));
///     assert_eq!(y * SilverCoins(3), SilverCoins(18));
///     assert_eq!(y / SilverCoins(2), SilverCoins(3));
///
///     // ordering and equality:
///     assert!(y < SilverCoins(7));
///     assert!(y > SilverCoins(5));
///     assert!(y <= SilverCoins(6));
///     assert!(y >= SilverCoins(6));
///     assert!(y == SilverCoins(6));
/// }
/// ```
///
#[macro_export]
macro_rules! unit {
    ( $ident:ident ) => {
        #[derive(Copy, Clone, Debug)]
        pub struct $ident<T>(pub T);

        unit!(impl_std_ops, $ident);
        unit!(impl_std_cmp, $ident);
        unit!(impl_num_traits, $ident);
    };

    (impl_std_ops, $ident:ident ) => {
        // addition
        impl<T: ::std::ops::Add<Output = T>> ::std::ops::Add for $ident<T> {
            type Output = Self;

            fn add(self, _rhs: Self) -> Self {
                $ident(self.0 + _rhs.0)
            }
        }

        // subtraction
        impl<T: ::std::ops::Sub<Output = T>> ::std::ops::Sub for $ident<T> {
            type Output = Self;

            fn sub(self, _rhs: Self) -> Self {
                $ident(self.0 - _rhs.0)
            }
        }

        // multiplication
        impl<T: ::std::ops::Mul<Output = T>> ::std::ops::Mul for $ident<T> {
            type Output = Self;

            fn mul(self, _rhs: Self) -> Self {
                $ident(self.0 * _rhs.0)
            }
        }

        // division
        impl<T: ::std::ops::Div<Output = T>> ::std::ops::Div for $ident<T> {
            type Output = Self;

            fn div(self, _rhs: Self) -> Self {
                $ident(self.0 / _rhs.0)
            }
        }

        // remainder
        impl<T: ::std::ops::Rem<Output = T>> ::std::ops::Rem for $ident<T> {
            type Output = Self;

            fn rem(self, rhs: Self) -> Self { $ident(self.0 % rhs.0) }
        }

        // negation
        impl<T: ::std::ops::Neg<Output = T>> ::std::ops::Neg for $ident<T> {
            type Output = Self;

            fn neg(self) -> Self::Output { $ident(-self.0) }
        }

        // not
        impl<T: ::std::ops::Not<Output = T>> ::std::ops::Not for $ident<T> {
            type Output = Self;

            fn not(self) -> Self::Output { $ident(!self.0) }
        }

        // bitwise and
        impl<T: ::std::ops::BitAnd<Output = T>> ::std::ops::BitAnd for $ident<T> {
            type Output = Self;

            fn bitand(self, rhs: Self) -> Self::Output { $ident(self.0 & rhs.0) }
        }

        // bitwise or
        impl<T: ::std::ops::BitOr<Output = T>> ::std::ops::BitOr for $ident<T> {
            type Output = Self;

            fn bitor(self, rhs: Self) -> Self::Output { $ident(self.0 | rhs.0) }
        }

        // bitwise xor
        impl<T: ::std::ops::BitXor<Output = T>> ::std::ops::BitXor for $ident<T> {
            type Output = Self;

            fn bitxor(self, rhs: Self) -> Self::Output { $ident(self.0 ^ rhs.0) }
        }

        // shift left
        impl<T: ::std::ops::Shl<usize>> ::std::ops::Shl<usize> for $ident<T> {
            type Output = $ident<T::Output>;

            fn shl(self, rhs: usize) -> Self::Output { $ident(self.0 << rhs) }
        }

        // shift right
        impl<T: ::std::ops::Shr<usize>> ::std::ops::Shr<usize> for $ident<T> {
            type Output = $ident<T::Output>;

            fn shr(self, rhs: usize) -> Self::Output { $ident(self.0 >> rhs) }
        }
    };

    (impl_std_cmp, $ident:ident ) => {
        // partial equality
        impl<T: ::std::cmp::PartialEq> ::std::cmp::PartialEq for $ident<T> {
            fn eq(&self, _rhs: &Self) -> bool {
                self.0 == _rhs.0
            }
        }

        // equality
        impl<T: ::std::cmp::Eq> ::std::cmp::Eq for $ident<T> {}

        // partial ordering
        impl<T: ::std::cmp::PartialOrd> ::std::cmp::PartialOrd for $ident<T> {
            fn partial_cmp(&self, other: &Self) -> Option<::std::cmp::Ordering> {
                if self.0 < other.0 {
                    Some(::std::cmp::Ordering::Less)
                } else if self.0 > other.0 {
                    Some(::std::cmp::Ordering::Greater)
                } else if self == other {
                    Some(::std::cmp::Ordering::Equal)
                } else {
                    None
                }
            }
        }

        // total ordering
        impl<T: ::std::cmp::Ord> ::std::cmp::Ord for $ident<T> {
            fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
                if self.0 < other.0 {
                    ::std::cmp::Ordering::Less
                } else if self.0 > other.0 {
                    ::std::cmp::Ordering::Greater
                } else {
                    ::std::cmp::Ordering::Equal
                }
            }
        }
    };

    (impl_num_traits, $ident:ident ) => {
        impl<T: $crate::num_export::traits::Zero> $crate::num_export::traits::Zero for $ident<T> {
            fn zero() -> Self { $ident(T::zero()) }
            fn is_zero(&self) -> bool { self.0.is_zero() }
        }

        impl<T: $crate::num_export::traits::One> $crate::num_export::traits::One for $ident<T> {
            fn one() -> Self { $ident(T::one()) }
        }

        impl<T: $crate::num_export::traits::Num> $crate::num_export::traits::Num for $ident<T> {
            type FromStrRadixErr = T::FromStrRadixErr;
            fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
                match T::from_str_radix(str, radix) {
                    Ok(x) => { Ok($ident(x)) }
                    Err(e) => { Err(e) }
                }
            }
        }

        impl<T: $crate::num_export::traits::ToPrimitive> $crate::num_export::traits::ToPrimitive for $ident<T> {
            fn to_i64(&self) -> Option<i64> { self.0.to_i64() }
            fn to_u64(&self) -> Option<u64> { self.0.to_u64() }
            fn to_isize(&self) -> Option<isize> { self.0.to_isize() }
            fn to_i8(&self) -> Option<i8> { self.0.to_i8() }
            fn to_i16(&self) -> Option<i16> { self.0.to_i16() }
            fn to_i32(&self) -> Option<i32> { self.0.to_i32() }
            fn to_usize(&self) -> Option<usize> { self.0.to_usize() }
            fn to_u8(&self) -> Option<u8> { self.0.to_u8() }
            fn to_u16(&self) -> Option<u16> { self.0.to_u16() }
            fn to_u32(&self) -> Option<u32> { self.0.to_u32() }
            fn to_f32(&self) -> Option<f32> { self.0.to_f32() }
            fn to_f64(&self) -> Option<f64> { self.0.to_f64() }
        }

        impl<T: $crate::num_export::traits::NumCast> $crate::num_export::traits::NumCast for $ident<T> {
            fn from<X: $crate::num_export::traits::ToPrimitive>(n: X) -> Option<Self> {
                match T::from(n) {
                    Some(x) => { Some($ident(x)) }
                    None => { None }
                }
            }
        }

        impl<T: $crate::num_export::traits::Bounded> $crate::num_export::traits::Bounded for $ident<T> {
            fn min_value() -> Self { $ident(T::min_value()) }
            fn max_value() -> Self { $ident(T::max_value()) }
        }

        // checked addition
        impl<T: $crate::num_export::traits::CheckedAdd<Output = T>> $crate::num_export::traits::CheckedAdd for $ident<T> {
            fn checked_add(&self, _rhs: &Self) -> Option<Self> {
                match self.0.checked_add(&_rhs.0) {
                    Some(x) => { Some($ident(x)) }
                    None => { None }
                }
            }
        }

        // checked subtraction
        impl<T: $crate::num_export::traits::CheckedSub<Output = T>> $crate::num_export::traits::CheckedSub for $ident<T> {
            fn checked_sub(&self, _rhs: &Self) -> Option<Self> {
                match self.0.checked_sub(&_rhs.0) {
                    Some(x) => { Some($ident(x)) }
                    None => { None }
                }
            }
        }

        // checked multiplication
        impl<T: $crate::num_export::traits::CheckedMul<Output = T>> $crate::num_export::traits::CheckedMul for $ident<T> {
            fn checked_mul(&self, _rhs: &Self) -> Option<Self> {
                match self.0.checked_mul(&_rhs.0) {
                    Some(x) => { Some($ident(x)) }
                    None => { None }
                }
            }
        }
    };
}
<commit_msg>unit! impl num::traits::CheckedDiv<commit_after>/// unit creates a type representing a single unit.
///
/// # Examples
///
/// ```
/// #[macro_use(unit)]
/// extern crate fiz_math;
/// use std::fmt::Debug;
///
/// // GoldCoins are golden!
/// unit!(GoldCoins);
///
/// // SilverCoins are like gold coins, only worse!
/// unit!(SilverCoins);
///
/// fn collect<T: Debug>(coins: GoldCoins<T>) {
///     println!("We've collected {:?} golden coins!", coins.0);
/// }
///
/// fn main() {
///     let x = GoldCoins(5);
///     collect(x);
///
///     let y = SilverCoins(6);
///
///     // Try uncommenting the line below and see:
///     //
///     // error: mismatched types: expected `GoldCoins<_>`, found `SilverCoins<_>`"
///     //
///     //collect(y);
///
///     // add, subtract, multiply, divide:
///     assert_eq!(y + SilverCoins(4), SilverCoins(10));
///     assert_eq!(y - SilverCoins(3), SilverCoins(3));
///     assert_eq!(y * SilverCoins(3), SilverCoins(18));
///     assert_eq!(y / SilverCoins(2), SilverCoins(3));
///
///     // ordering and equality:
///     assert!(y < SilverCoins(7));
///     assert!(y > SilverCoins(5));
///     assert!(y <= SilverCoins(6));
///     assert!(y >= SilverCoins(6));
///     assert!(y == SilverCoins(6));
/// }
/// ```
///
#[macro_export]
macro_rules! unit {
    ( $ident:ident ) => {
        #[derive(Copy, Clone, Debug)]
        pub struct $ident<T>(pub T);

        unit!(impl_std_ops, $ident);
        unit!(impl_std_cmp, $ident);
        unit!(impl_num_traits, $ident);
    };

    (impl_std_ops, $ident:ident ) => {
        // addition
        impl<T: ::std::ops::Add<Output = T>> ::std::ops::Add for $ident<T> {
            type Output = Self;

            fn add(self, _rhs: Self) -> Self {
                $ident(self.0 + _rhs.0)
            }
        }

        // subtraction
        impl<T: ::std::ops::Sub<Output = T>> ::std::ops::Sub for $ident<T> {
            type Output = Self;

            fn sub(self, _rhs: Self) -> Self {
                $ident(self.0 - _rhs.0)
            }
        }

        // multiplication
        impl<T: ::std::ops::Mul<Output = T>> ::std::ops::Mul for $ident<T> {
            type Output = Self;

            fn mul(self, _rhs: Self) -> Self {
                $ident(self.0 * _rhs.0)
            }
        }

        // division
        impl<T: ::std::ops::Div<Output = T>> ::std::ops::Div for $ident<T> {
            type Output = Self;

            fn div(self, _rhs: Self) -> Self {
                $ident(self.0 / _rhs.0)
            }
        }

        // remainder
        impl<T: ::std::ops::Rem<Output = T>> ::std::ops::Rem for $ident<T> {
            type Output = Self;

            fn rem(self, rhs: Self) -> Self { $ident(self.0 % rhs.0) }
        }

        // negation
        impl<T: ::std::ops::Neg<Output = T>> ::std::ops::Neg for $ident<T> {
            type Output = Self;

            fn neg(self) -> Self::Output { $ident(-self.0) }
        }

        // not
        impl<T: ::std::ops::Not<Output = T>> ::std::ops::Not for $ident<T> {
            type Output = Self;

            fn not(self) -> Self::Output { $ident(!self.0) }
        }

        // bitwise and
        impl<T: ::std::ops::BitAnd<Output = T>> ::std::ops::BitAnd for $ident<T> {
            type Output = Self;

            fn bitand(self, rhs: Self) -> Self::Output { $ident(self.0 & rhs.0) }
        }

        // bitwise or
        impl<T: ::std::ops::BitOr<Output = T>> ::std::ops::BitOr for $ident<T> {
            type Output = Self;

            fn bitor(self, rhs: Self) -> Self::Output { $ident(self.0 | rhs.0) }
        }

        // bitwise xor
        impl<T: ::std::ops::BitXor<Output = T>> ::std::ops::BitXor for $ident<T> {
            type Output = Self;

            fn bitxor(self, rhs: Self) -> Self::Output { $ident(self.0 ^ rhs.0) }
        }

        // shift left
        impl<T: ::std::ops::Shl<usize>> ::std::ops::Shl<usize> for $ident<T> {
            type Output = $ident<T::Output>;

            fn shl(self, rhs: usize) -> Self::Output { $ident(self.0 << rhs) }
        }

        // shift right
        impl<T: ::std::ops::Shr<usize>> ::std::ops::Shr<usize> for $ident<T> {
            type Output = $ident<T::Output>;

            fn shr(self, rhs: usize) -> Self::Output { $ident(self.0 >> rhs) }
        }
    };

    (impl_std_cmp, $ident:ident ) => {
        // partial equality
        impl<T: ::std::cmp::PartialEq> ::std::cmp::PartialEq for $ident<T> {
            fn eq(&self, _rhs: &Self) -> bool {
                self.0 == _rhs.0
            }
        }

        // equality
        impl<T: ::std::cmp::Eq> ::std::cmp::Eq for $ident<T> {}

        // partial ordering
        impl<T: ::std::cmp::PartialOrd> ::std::cmp::PartialOrd for $ident<T> {
            fn partial_cmp(&self, other: &Self) -> Option<::std::cmp::Ordering> {
                if self.0 < other.0 {
                    Some(::std::cmp::Ordering::Less)
                } else if self.0 > other.0 {
                    Some(::std::cmp::Ordering::Greater)
                } else if self == other {
                    Some(::std::cmp::Ordering::Equal)
                } else {
                    None
                }
            }
        }

        // total ordering
        impl<T: ::std::cmp::Ord> ::std::cmp::Ord for $ident<T> {
            fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
                if self.0 < other.0 {
                    ::std::cmp::Ordering::Less
                } else if self.0 > other.0 {
                    ::std::cmp::Ordering::Greater
                } else {
                    ::std::cmp::Ordering::Equal
                }
            }
        }
    };

    (impl_num_traits, $ident:ident ) => {
        impl<T: $crate::num_export::traits::Zero> $crate::num_export::traits::Zero for $ident<T> {
            fn zero() -> Self { $ident(T::zero()) }
            fn is_zero(&self) -> bool { self.0.is_zero() }
        }

        impl<T: $crate::num_export::traits::One> $crate::num_export::traits::One for $ident<T> {
            fn one() -> Self { $ident(T::one()) }
        }

        impl<T: $crate::num_export::traits::Num> $crate::num_export::traits::Num for $ident<T> {
            type FromStrRadixErr = T::FromStrRadixErr;
            fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
                match T::from_str_radix(str, radix) {
                    Ok(x) => { Ok($ident(x)) }
                    Err(e) => { Err(e) }
                }
            }
        }

        impl<T: $crate::num_export::traits::ToPrimitive> $crate::num_export::traits::ToPrimitive for $ident<T> {
            fn to_i64(&self) -> Option<i64> { self.0.to_i64() }
            fn to_u64(&self) -> Option<u64> { self.0.to_u64() }
            fn to_isize(&self) -> Option<isize> { self.0.to_isize() }
            fn to_i8(&self) -> Option<i8> { self.0.to_i8() }
            fn to_i16(&self) -> Option<i16> { self.0.to_i16() }
            fn to_i32(&self) -> Option<i32> { self.0.to_i32() }
            fn to_usize(&self) -> Option<usize> { self.0.to_usize() }
            fn to_u8(&self) -> Option<u8> { self.0.to_u8() }
            fn to_u16(&self) -> Option<u16> { self.0.to_u16() }
            fn to_u32(&self) -> Option<u32> { self.0.to_u32() }
            fn to_f32(&self) -> Option<f32> { self.0.to_f32() }
            fn to_f64(&self) -> Option<f64> { self.0.to_f64() }
        }

        impl<T: $crate::num_export::traits::NumCast> $crate::num_export::traits::NumCast for $ident<T> {
            fn from<X: $crate::num_export::traits::ToPrimitive>(n: X) -> Option<Self> {
                match T::from(n) {
                    Some(x) => { Some($ident(x)) }
                    None => { None }
                }
            }
        }

        impl<T: $crate::num_export::traits::Bounded> $crate::num_export::traits::Bounded for $ident<T> {
            fn min_value() -> Self { $ident(T::min_value()) }
            fn max_value() -> Self { $ident(T::max_value()) }
        }

        // checked addition
        impl<T: $crate::num_export::traits::CheckedAdd<Output = T>> $crate::num_export::traits::CheckedAdd for $ident<T> {
            fn checked_add(&self, _rhs: &Self) -> Option<Self> {
                match self.0.checked_add(&_rhs.0) {
                    Some(x) => { Some($ident(x)) }
                    None => { None }
                }
            }
        }

        // checked subtraction
        impl<T: $crate::num_export::traits::CheckedSub<Output = T>> $crate::num_export::traits::CheckedSub for $ident<T> {
            fn checked_sub(&self, _rhs: &Self) -> Option<Self> {
                match self.0.checked_sub(&_rhs.0) {
                    Some(x) => { Some($ident(x)) }
                    None => { None }
                }
            }
        }

        // checked multiplication
        impl<T: $crate::num_export::traits::CheckedMul<Output = T>> $crate::num_export::traits::CheckedMul for $ident<T> {
            fn checked_mul(&self, _rhs: &Self) -> Option<Self> {
                match self.0.checked_mul(&_rhs.0) {
                    Some(x) => { Some($ident(x)) }
                    None => { None }
                }
            }
        }

        // checked division
        impl<T: $crate::num_export::traits::CheckedDiv<Output = T>> $crate::num_export::traits::CheckedDiv for $ident<T> {
            fn checked_div(&self, _rhs: &Self) -> Option<Self> {
                match self.0.checked_div(&_rhs.0) {
                    Some(x) => { Some($ident(x)) }
                    None => { None }
                }
            }
        }
    };
}
<|endoftext|>


<commit_before>use rocket::Outcome;
use rocket::request::{self, FromRequest, Request};

#[derive(Clone, Eq, PartialEq, Serialize)]
pub struct User {
    name: String,
}

impl User {
    pub fn name(&self) -> &str {
        &self.name
    }
}

impl<'a, 'r> FromRequest<'a, 'r> for User {
    type Error = ();

    fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
        // TODO: this implementation is obviously ridiculous and intended for
        // testing only!

        match request.cookies().find("user_name") {
            Some(cookie) => Outcome::Success(Self { name: cookie.value().into() }),
            None => Outcome::Forward(()),
        }
    }
}
<commit_msg>Fix warnings<commit_after>use rocket::Outcome;
use rocket::request::{self, FromRequest, Request};

#[derive(Clone, Eq, PartialEq, Serialize)]
pub struct User {
    name: String,
}

impl<'a, 'r> FromRequest<'a, 'r> for User {
    type Error = ();

    fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
        // TODO: this implementation is obviously ridiculous and intended for
        // testing only!

        match request.cookies().find("user_name") {
            Some(cookie) => Outcome::Success(Self { name: cookie.value().into() }),
            None => Outcome::Forward(()),
        }
    }
}
<|endoftext|>


<commit_before>
pub struct Todo {
        id: int,
        todo: ~str,
        priority: char,
        finished: bool,
        raw_todo: ~str,
        contexts: & 'static [~str],
        projects: & 'static [~str]
}

impl Todo {
        pub fn to_str(&self) -> ~str {
                return format!("{:d} {:b} ({:c}) '{:s}' \"{:s}\"",
                                self.id, self.finished, self.priority,
                                self.todo, self.raw_todo)
        }

        pub fn create(todo: ~str, id: int) -> Todo {
                let mut task = Todo{id: id, raw_todo: todo.clone(), todo: todo.clone(),
                                        finished: false, priority: '^',
                                        contexts: &[], projects: &[]};

                if (todo[0] == "x".as_bytes()[0]) {
                        task.finished = true;
                        task.todo = todo.slice(2, todo.len()).to_owned()
                }

                return task;
        }
}

#[test]
fn simple_todo_create_test() {
        let t = Todo::create(~"some important task", 1);

        assert!(t.id == 1);
        assert!(t.priority == '^');
        assert!(t.finished == false);
        assert!(t.todo == ~"some important task");
        assert!(t.raw_todo == ~"some important task");
}

#[test]
fn todo_to_str_test() {
        let t = Todo::create(~"some important task", 1);

        assert_eq!(t.to_str(), ~"1 false (^) 'some important task' \"some important task\"")

        let x = Todo::create(~"x some important task", 1);
        assert_eq!(x.to_str(), ~"1 true (^) 'some important task' \"x some important task\"")
}
<commit_msg>better str comparison<commit_after>
pub struct Todo {
        id: int,
        todo: ~str,
        priority: char,
        finished: bool,
        raw_todo: ~str,
        contexts: & 'static [~str],
        projects: & 'static [~str]
}

impl Todo {
        pub fn to_str(&self) -> ~str {
                return format!("{:d} {:b} ({:c}) '{:s}' \"{:s}\"",
                                self.id, self.finished, self.priority,
                                self.todo, self.raw_todo)
        }

        pub fn create(todo: ~str, id: int) -> Todo {
                let mut task = Todo{id: id, raw_todo: todo.clone(), todo: todo.clone(),
                                        finished: false, priority: '^',
                                        contexts: &[], projects: &[]};

                if (todo.slice(0, 2) == "x ") {
                        task.finished = true;
                        task.todo = todo.slice(2, todo.len()).to_owned()
                }

                return task;
        }
}

#[test]
fn simple_todo_create_test() {
        let t = Todo::create(~"some important task", 1);

        assert!(t.id == 1);
        assert!(t.priority == '^');
        assert!(t.finished == false);
        assert!(t.todo == ~"some important task");
        assert!(t.raw_todo == ~"some important task");
}

#[test]
fn todo_to_str_test() {
        let t = Todo::create(~"some important task", 1);

        assert_eq!(t.to_str(), ~"1 false (^) 'some important task' \"some important task\"")

        let x = Todo::create(~"x some important task", 1);
        assert_eq!(x.to_str(), ~"1 true (^) 'some important task' \"x some important task\"")
}
<|endoftext|>


<commit_before>use std::io::Read;

use crate::common::read_single_input;
use crate::Solution;

type Answers = u32;

fn count(answers: Answers) -> u32 {
    answers.count_ones()
}

fn compute_answers(group: &str) -> Answers {
    let mut questions = 0;

    for question in group.chars().filter(char::is_ascii_lowercase) {
        questions |= 1 << (question as usize - 'a' as usize);
    }

    questions
}

fn count_answers_all(group: &str) -> u32 {
    let mut combined = 0xffff_ffff;

    for line in group.split('\n') {
        let single = compute_answers(line);

        combined &= single;
    }

    count(combined)
}

#[derive(Default)]
pub struct Day06;

impl Solution for Day06 {
    fn part1(&mut self, input: &mut dyn Read) -> String {
        let input: String = read_single_input(input);

        let total: u32 = input.split("\n\n").map(compute_answers).map(count).sum();

        total.to_string()
    }

    fn part2(&mut self, input: &mut dyn Read) -> String {
        let input: String = read_single_input(input);

        let total: u32 = input.split("\n\n").map(count_answers_all).sum();

        total.to_string()
    }
}

#[cfg(test)]
mod tests {
    use crate::test_implementation;

    use super::*;

    const SAMPLE: &[u8] = include_bytes!("../samples/06.txt");

    #[test]
    fn sample_part1() {
        test_implementation!(Day06, 1, SAMPLE, 11);
    }

    #[test]
    fn sample_part2() {
        test_implementation!(Day06, 2, SAMPLE, 6);
    }
}
<commit_msg>Rewrite using iterators<commit_after>use std::io::Read;

use crate::common::read_single_input;
use crate::Solution;

type Answers = u32;

fn count(answers: Answers) -> u32 {
    answers.count_ones()
}

fn compute_answers(group: &str) -> Answers {
    group
        .chars()
        .filter(char::is_ascii_lowercase)
        .map(|q| 1 << (q as usize - 'a' as usize))
        .fold(0, |a, b| a | b)
}

fn count_answers_all(group: &str) -> u32 {
    let combined = group
        .split('\n')
        .map(compute_answers)
        .fold(0xffff_ffff, |a, b| a & b);

    count(combined)
}

#[derive(Default)]
pub struct Day06;

impl Solution for Day06 {
    fn part1(&mut self, input: &mut dyn Read) -> String {
        let input: String = read_single_input(input);

        let total: u32 = input.split("\n\n").map(|g| count(compute_answers(g))).sum();

        total.to_string()
    }

    fn part2(&mut self, input: &mut dyn Read) -> String {
        let input: String = read_single_input(input);

        let total: u32 = input.split("\n\n").map(count_answers_all).sum();

        total.to_string()
    }
}

#[cfg(test)]
mod tests {
    use crate::test_implementation;

    use super::*;

    const SAMPLE: &[u8] = include_bytes!("../samples/06.txt");

    #[test]
    fn sample_part1() {
        test_implementation!(Day06, 1, SAMPLE, 11);
    }

    #[test]
    fn sample_part2() {
        test_implementation!(Day06, 2, SAMPLE, 6);
    }
}
<|endoftext|>


<commit_before>use cssparser::Parser;
use markup5ever::{expanded_name, local_name, namespace_url, ns, QualName};
use nalgebra::{DMatrix, Dynamic, VecStorage};

use crate::document::AcquiredNodes;
use crate::drawing_ctx::DrawingCtx;
use crate::element::{set_attribute, ElementResult, SetAttributes};
use crate::error::*;
use crate::node::{CascadedValues, Node};
use crate::parsers::{NonNegative, NumberList, NumberOptionalNumber, Parse, ParseValue};
use crate::properties::ColorInterpolationFilters;
use crate::rect::IRect;
use crate::session::Session;
use crate::surface_utils::{
    iterators::{PixelRectangle, Pixels},
    shared_surface::ExclusiveImageSurface,
    EdgeMode, ImageSurfaceDataExt, Pixel,
};
use crate::util::clamp;
use crate::xml::Attributes;

use super::bounds::BoundsBuilder;
use super::context::{FilterContext, FilterOutput};
use super::{
    FilterEffect, FilterError, FilterResolveError, Input, Primitive, PrimitiveParams,
    ResolvedPrimitive,
};

/// The `feConvolveMatrix` filter primitive.
#[derive(Default)]
pub struct FeConvolveMatrix {
    base: Primitive,
    params: ConvolveMatrix,
}

/// Resolved `feConvolveMatrix` primitive for rendering.
#[derive(Clone)]
pub struct ConvolveMatrix {
    in1: Input,
    order: NumberOptionalNumber<u32>,
    kernel_matrix: Option<DMatrix<f64>>,
    divisor: f64,
    bias: f64,
    target_x: Option<u32>,
    target_y: Option<u32>,
    edge_mode: EdgeMode,
    kernel_unit_length: Option<(f64, f64)>,
    preserve_alpha: bool,
    color_interpolation_filters: ColorInterpolationFilters,
}

impl Default for ConvolveMatrix {
    /// Constructs a new `ConvolveMatrix` with empty properties.
    #[inline]
    fn default() -> ConvolveMatrix {
        ConvolveMatrix {
            in1: Default::default(),
            order: NumberOptionalNumber(3, 3),
            kernel_matrix: None,
            divisor: 0.0,
            bias: 0.0,
            target_x: None,
            target_y: None,
            edge_mode: EdgeMode::Duplicate,
            kernel_unit_length: None,
            preserve_alpha: false,
            color_interpolation_filters: Default::default(),
        }
    }
}

impl SetAttributes for FeConvolveMatrix {
    fn set_attributes(&mut self, attrs: &Attributes, session: &Session) -> ElementResult {
        self.params.in1 = self.base.parse_one_input(attrs, session);

        for (attr, value) in attrs.iter() {
            match attr.expanded() {
                expanded_name!("", "order") => {
                    set_attribute(&mut self.params.order, attr.parse(value), session)
                }
                expanded_name!("", "divisor") => {
                    set_attribute(&mut self.params.divisor, attr.parse(value), session)
                }
                expanded_name!("", "bias") => {
                    set_attribute(&mut self.params.bias, attr.parse(value), session)
                }
                expanded_name!("", "targetX") => {
                    set_attribute(&mut self.params.target_x, attr.parse(value), session)
                }
                expanded_name!("", "targetY") => {
                    set_attribute(&mut self.params.target_y, attr.parse(value), session)
                }
                expanded_name!("", "edgeMode") => {
                    set_attribute(&mut self.params.edge_mode, attr.parse(value), session)
                }
                expanded_name!("", "kernelUnitLength") => {
                    let NumberOptionalNumber(NonNegative(x), NonNegative(y)) = attr.parse(value)?;
                    self.params.kernel_unit_length = Some((x, y))
                }
                expanded_name!("", "preserveAlpha") => {
                    set_attribute(&mut self.params.preserve_alpha, attr.parse(value), session);
                }

                _ => (),
            }
        }

        // Finally, parse the kernel matrix.
        for (attr, value) in attrs
            .iter()
            .filter(|(attr, _)| attr.expanded() == expanded_name!("", "kernelMatrix"))
        {
            self.params.kernel_matrix = Some({
                let cols = self.params.order.0 as usize;
                let rows = self.params.order.1 as usize;

                let number_of_elements = cols * rows;

                // #691: Limit list to 400 (20x20) to mitigate malicious SVGs
                let NumberList::<0, 400>(v) = attr.parse(value)?;
                // #691: Update check as v.len can be different than number of elements because
                //       of the above limit (and will = 400 if that happens)
                if v.len() != number_of_elements && v.len() != 400 {
                    return Err(ValueErrorKind::value_error(&format!(
                        "incorrect number of elements: expected {}",
                        number_of_elements
                    )))
                    .attribute(attr);
                }

                DMatrix::from_data(VecStorage::new(
                    Dynamic::new(self.params.order.1 as usize),
                    Dynamic::new(self.params.order.0 as usize),
                    v,
                ))
            });
        }

        // kernel_matrix must have been specified.
        if self.params.kernel_matrix.is_none() {
            return Err(ValueErrorKind::value_error("the value must be set"))
                .attribute(QualName::new(None, ns!(svg), local_name!("kernelMatrix")));
        }

        Ok(())
    }
}

impl ConvolveMatrix {
    pub fn render(
        &self,
        bounds_builder: BoundsBuilder,
        ctx: &FilterContext,
        acquired_nodes: &mut AcquiredNodes<'_>,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<FilterOutput, FilterError> {
        #![allow(clippy::many_single_char_names)]

        let input_1 = ctx.get_input(
            acquired_nodes,
            draw_ctx,
            &self.in1,
            self.color_interpolation_filters,
        )?;
        let mut bounds: IRect = bounds_builder
            .add_input(&input_1)
            .compute(ctx)
            .clipped
            .into();
        let original_bounds = bounds;

        let target_x = match self.target_x {
            Some(x) if x >= self.order.0 => {
                return Err(FilterError::InvalidParameter(
                    "targetX must be less than orderX".to_string(),
                ))
            }
            Some(x) => x,
            None => self.order.0 / 2,
        };

        let target_y = match self.target_y {
            Some(y) if y >= self.order.1 => {
                return Err(FilterError::InvalidParameter(
                    "targetY must be less than orderY".to_string(),
                ))
            }
            Some(y) => y,
            None => self.order.1 / 2,
        };

        let mut input_surface = if self.preserve_alpha {
            // preserve_alpha means we need to premultiply and unpremultiply the values.
            input_1.surface().unpremultiply(bounds)?
        } else {
            input_1.surface().clone()
        };

        let scale = self
            .kernel_unit_length
            .map(|(dx, dy)| ctx.paffine().transform_distance(dx, dy));

        if let Some((ox, oy)) = scale {
            // Scale the input surface to match kernel_unit_length.
            let (new_surface, new_bounds) = input_surface.scale(bounds, 1.0 / ox, 1.0 / oy)?;

            input_surface = new_surface;
            bounds = new_bounds;
        }

        let matrix = self.kernel_matrix.as_ref().unwrap();

        let divisor = if self.divisor != 0.0 {
            self.divisor
        } else {
            let d = matrix.iter().sum();

            if d != 0.0 {
                d
            } else {
                1.0
            }
        };

        let mut surface = ExclusiveImageSurface::new(
            input_surface.width(),
            input_surface.height(),
            input_1.surface().surface_type(),
        )?;

        surface.modify(&mut |data, stride| {
            for (x, y, pixel) in Pixels::within(&input_surface, bounds) {
                // Compute the convolution rectangle bounds.
                let kernel_bounds = IRect::new(
                    x as i32 - target_x as i32,
                    y as i32 - target_y as i32,
                    x as i32 - target_x as i32 + self.order.0 as i32,
                    y as i32 - target_y as i32 + self.order.1 as i32,
                );

                // Do the convolution.
                let mut r = 0.0;
                let mut g = 0.0;
                let mut b = 0.0;
                let mut a = 0.0;

                for (x, y, pixel) in
                    PixelRectangle::within(&input_surface, bounds, kernel_bounds, self.edge_mode)
                {
                    let kernel_x = (kernel_bounds.x1 - x - 1) as usize;
                    let kernel_y = (kernel_bounds.y1 - y - 1) as usize;

                    r += f64::from(pixel.r) / 255.0 * matrix[(kernel_y, kernel_x)];
                    g += f64::from(pixel.g) / 255.0 * matrix[(kernel_y, kernel_x)];
                    b += f64::from(pixel.b) / 255.0 * matrix[(kernel_y, kernel_x)];

                    if !self.preserve_alpha {
                        a += f64::from(pixel.a) / 255.0 * matrix[(kernel_y, kernel_x)];
                    }
                }

                // If preserve_alpha is true, set a to the source alpha value.
                if self.preserve_alpha {
                    a = f64::from(pixel.a) / 255.0;
                } else {
                    a = a / divisor + self.bias;
                }

                let clamped_a = clamp(a, 0.0, 1.0);

                let compute = |x| {
                    let x = x / divisor + self.bias * a;

                    let x = if self.preserve_alpha {
                        // Premultiply the output value.
                        clamp(x, 0.0, 1.0) * clamped_a
                    } else {
                        clamp(x, 0.0, clamped_a)
                    };

                    ((x * 255.0) + 0.5) as u8
                };

                let output_pixel = Pixel {
                    r: compute(r),
                    g: compute(g),
                    b: compute(b),
                    a: ((clamped_a * 255.0) + 0.5) as u8,
                };

                data.set_pixel(stride, output_pixel, x, y);
            }
        });

        let mut surface = surface.share()?;

        if let Some((ox, oy)) = scale {
            // Scale the output surface back.
            surface = surface.scale_to(
                ctx.source_graphic().width(),
                ctx.source_graphic().height(),
                original_bounds,
                ox,
                oy,
            )?;

            bounds = original_bounds;
        }

        Ok(FilterOutput { surface, bounds })
    }
}

impl FilterEffect for FeConvolveMatrix {
    fn resolve(
        &self,
        _acquired_nodes: &mut AcquiredNodes<'_>,
        node: &Node,
    ) -> Result<ResolvedPrimitive, FilterResolveError> {
        let cascaded = CascadedValues::new_from_node(node);
        let values = cascaded.get();

        let mut params = self.params.clone();
        params.color_interpolation_filters = values.color_interpolation_filters();

        Ok(ResolvedPrimitive {
            primitive: self.base.clone(),
            params: PrimitiveParams::ConvolveMatrix(params),
        })
    }
}

impl Parse for EdgeMode {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
        Ok(parse_identifiers!(
            parser,
            "duplicate" => EdgeMode::Duplicate,
            "wrap" => EdgeMode::Wrap,
            "none" => EdgeMode::None,
        )?)
    }
}

// Used for the preserveAlpha attribute
impl Parse for bool {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
        Ok(parse_identifiers!(
            parser,
            "false" => false,
            "true" => true,
        )?)
    }
}
<commit_msg>feConvolveMatrix: check the kernel_unit_length at render time, not at parse time<commit_after>use cssparser::Parser;
use markup5ever::{expanded_name, local_name, namespace_url, ns, QualName};
use nalgebra::{DMatrix, Dynamic, VecStorage};

use crate::document::AcquiredNodes;
use crate::drawing_ctx::DrawingCtx;
use crate::element::{set_attribute, ElementResult, SetAttributes};
use crate::error::*;
use crate::node::{CascadedValues, Node};
use crate::parsers::{NumberList, NumberOptionalNumber, Parse, ParseValue};
use crate::properties::ColorInterpolationFilters;
use crate::rect::IRect;
use crate::session::Session;
use crate::surface_utils::{
    iterators::{PixelRectangle, Pixels},
    shared_surface::ExclusiveImageSurface,
    EdgeMode, ImageSurfaceDataExt, Pixel,
};
use crate::util::clamp;
use crate::xml::Attributes;

use super::bounds::BoundsBuilder;
use super::context::{FilterContext, FilterOutput};
use super::{
    FilterEffect, FilterError, FilterResolveError, Input, Primitive, PrimitiveParams,
    ResolvedPrimitive,
};

/// The `feConvolveMatrix` filter primitive.
#[derive(Default)]
pub struct FeConvolveMatrix {
    base: Primitive,
    params: ConvolveMatrix,
}

/// Resolved `feConvolveMatrix` primitive for rendering.
#[derive(Clone)]
pub struct ConvolveMatrix {
    in1: Input,
    order: NumberOptionalNumber<u32>,
    kernel_matrix: Option<DMatrix<f64>>,
    divisor: f64,
    bias: f64,
    target_x: Option<u32>,
    target_y: Option<u32>,
    edge_mode: EdgeMode,
    kernel_unit_length: Option<(f64, f64)>,
    preserve_alpha: bool,
    color_interpolation_filters: ColorInterpolationFilters,
}

impl Default for ConvolveMatrix {
    /// Constructs a new `ConvolveMatrix` with empty properties.
    #[inline]
    fn default() -> ConvolveMatrix {
        ConvolveMatrix {
            in1: Default::default(),
            order: NumberOptionalNumber(3, 3),
            kernel_matrix: None,
            divisor: 0.0,
            bias: 0.0,
            target_x: None,
            target_y: None,
            edge_mode: EdgeMode::Duplicate,
            kernel_unit_length: None,
            preserve_alpha: false,
            color_interpolation_filters: Default::default(),
        }
    }
}

impl SetAttributes for FeConvolveMatrix {
    fn set_attributes(&mut self, attrs: &Attributes, session: &Session) -> ElementResult {
        self.params.in1 = self.base.parse_one_input(attrs, session);

        for (attr, value) in attrs.iter() {
            match attr.expanded() {
                expanded_name!("", "order") => {
                    set_attribute(&mut self.params.order, attr.parse(value), session)
                }
                expanded_name!("", "divisor") => {
                    set_attribute(&mut self.params.divisor, attr.parse(value), session)
                }
                expanded_name!("", "bias") => {
                    set_attribute(&mut self.params.bias, attr.parse(value), session)
                }
                expanded_name!("", "targetX") => {
                    set_attribute(&mut self.params.target_x, attr.parse(value), session)
                }
                expanded_name!("", "targetY") => {
                    set_attribute(&mut self.params.target_y, attr.parse(value), session)
                }
                expanded_name!("", "edgeMode") => {
                    set_attribute(&mut self.params.edge_mode, attr.parse(value), session)
                }
                expanded_name!("", "kernelUnitLength") => {
                    let v: Result<NumberOptionalNumber<f64>, _> = attr.parse(value);
                    match v {
                        Ok(NumberOptionalNumber(x, y)) => {
                            self.params.kernel_unit_length = Some((x, y));
                        }

                        Err(e) => {
                            rsvg_log!(session, "ignoring attribute with invalid value: {}", e);
                        }
                    }
                }
                expanded_name!("", "preserveAlpha") => {
                    set_attribute(&mut self.params.preserve_alpha, attr.parse(value), session);
                }

                _ => (),
            }
        }

        // Finally, parse the kernel matrix.
        for (attr, value) in attrs
            .iter()
            .filter(|(attr, _)| attr.expanded() == expanded_name!("", "kernelMatrix"))
        {
            self.params.kernel_matrix = Some({
                let cols = self.params.order.0 as usize;
                let rows = self.params.order.1 as usize;

                let number_of_elements = cols * rows;

                // #691: Limit list to 400 (20x20) to mitigate malicious SVGs
                let NumberList::<0, 400>(v) = attr.parse(value)?;
                // #691: Update check as v.len can be different than number of elements because
                //       of the above limit (and will = 400 if that happens)
                if v.len() != number_of_elements && v.len() != 400 {
                    return Err(ValueErrorKind::value_error(&format!(
                        "incorrect number of elements: expected {}",
                        number_of_elements
                    )))
                    .attribute(attr);
                }

                DMatrix::from_data(VecStorage::new(
                    Dynamic::new(self.params.order.1 as usize),
                    Dynamic::new(self.params.order.0 as usize),
                    v,
                ))
            });
        }

        // kernel_matrix must have been specified.
        if self.params.kernel_matrix.is_none() {
            return Err(ValueErrorKind::value_error("the value must be set"))
                .attribute(QualName::new(None, ns!(svg), local_name!("kernelMatrix")));
        }

        Ok(())
    }
}

impl ConvolveMatrix {
    pub fn render(
        &self,
        bounds_builder: BoundsBuilder,
        ctx: &FilterContext,
        acquired_nodes: &mut AcquiredNodes<'_>,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<FilterOutput, FilterError> {
        #![allow(clippy::many_single_char_names)]

        let input_1 = ctx.get_input(
            acquired_nodes,
            draw_ctx,
            &self.in1,
            self.color_interpolation_filters,
        )?;
        let mut bounds: IRect = bounds_builder
            .add_input(&input_1)
            .compute(ctx)
            .clipped
            .into();
        let original_bounds = bounds;

        let target_x = match self.target_x {
            Some(x) if x >= self.order.0 => {
                return Err(FilterError::InvalidParameter(
                    "targetX must be less than orderX".to_string(),
                ))
            }
            Some(x) => x,
            None => self.order.0 / 2,
        };

        let target_y = match self.target_y {
            Some(y) if y >= self.order.1 => {
                return Err(FilterError::InvalidParameter(
                    "targetY must be less than orderY".to_string(),
                ))
            }
            Some(y) => y,
            None => self.order.1 / 2,
        };

        let mut input_surface = if self.preserve_alpha {
            // preserve_alpha means we need to premultiply and unpremultiply the values.
            input_1.surface().unpremultiply(bounds)?
        } else {
            input_1.surface().clone()
        };

        let scale = self
            .kernel_unit_length
            .and_then(|(x, y)| {
                if x <= 0.0 || y <= 0.0 {
                    None
                } else {
                    Some((x, y))
                }
            })
            .map(|(dx, dy)| ctx.paffine().transform_distance(dx, dy));

        if let Some((ox, oy)) = scale {
            // Scale the input surface to match kernel_unit_length.
            let (new_surface, new_bounds) = input_surface.scale(bounds, 1.0 / ox, 1.0 / oy)?;

            input_surface = new_surface;
            bounds = new_bounds;
        }

        let matrix = self.kernel_matrix.as_ref().unwrap();

        let divisor = if self.divisor != 0.0 {
            self.divisor
        } else {
            let d = matrix.iter().sum();

            if d != 0.0 {
                d
            } else {
                1.0
            }
        };

        let mut surface = ExclusiveImageSurface::new(
            input_surface.width(),
            input_surface.height(),
            input_1.surface().surface_type(),
        )?;

        surface.modify(&mut |data, stride| {
            for (x, y, pixel) in Pixels::within(&input_surface, bounds) {
                // Compute the convolution rectangle bounds.
                let kernel_bounds = IRect::new(
                    x as i32 - target_x as i32,
                    y as i32 - target_y as i32,
                    x as i32 - target_x as i32 + self.order.0 as i32,
                    y as i32 - target_y as i32 + self.order.1 as i32,
                );

                // Do the convolution.
                let mut r = 0.0;
                let mut g = 0.0;
                let mut b = 0.0;
                let mut a = 0.0;

                for (x, y, pixel) in
                    PixelRectangle::within(&input_surface, bounds, kernel_bounds, self.edge_mode)
                {
                    let kernel_x = (kernel_bounds.x1 - x - 1) as usize;
                    let kernel_y = (kernel_bounds.y1 - y - 1) as usize;

                    r += f64::from(pixel.r) / 255.0 * matrix[(kernel_y, kernel_x)];
                    g += f64::from(pixel.g) / 255.0 * matrix[(kernel_y, kernel_x)];
                    b += f64::from(pixel.b) / 255.0 * matrix[(kernel_y, kernel_x)];

                    if !self.preserve_alpha {
                        a += f64::from(pixel.a) / 255.0 * matrix[(kernel_y, kernel_x)];
                    }
                }

                // If preserve_alpha is true, set a to the source alpha value.
                if self.preserve_alpha {
                    a = f64::from(pixel.a) / 255.0;
                } else {
                    a = a / divisor + self.bias;
                }

                let clamped_a = clamp(a, 0.0, 1.0);

                let compute = |x| {
                    let x = x / divisor + self.bias * a;

                    let x = if self.preserve_alpha {
                        // Premultiply the output value.
                        clamp(x, 0.0, 1.0) * clamped_a
                    } else {
                        clamp(x, 0.0, clamped_a)
                    };

                    ((x * 255.0) + 0.5) as u8
                };

                let output_pixel = Pixel {
                    r: compute(r),
                    g: compute(g),
                    b: compute(b),
                    a: ((clamped_a * 255.0) + 0.5) as u8,
                };

                data.set_pixel(stride, output_pixel, x, y);
            }
        });

        let mut surface = surface.share()?;

        if let Some((ox, oy)) = scale {
            // Scale the output surface back.
            surface = surface.scale_to(
                ctx.source_graphic().width(),
                ctx.source_graphic().height(),
                original_bounds,
                ox,
                oy,
            )?;

            bounds = original_bounds;
        }

        Ok(FilterOutput { surface, bounds })
    }
}

impl FilterEffect for FeConvolveMatrix {
    fn resolve(
        &self,
        _acquired_nodes: &mut AcquiredNodes<'_>,
        node: &Node,
    ) -> Result<ResolvedPrimitive, FilterResolveError> {
        let cascaded = CascadedValues::new_from_node(node);
        let values = cascaded.get();

        let mut params = self.params.clone();
        params.color_interpolation_filters = values.color_interpolation_filters();

        Ok(ResolvedPrimitive {
            primitive: self.base.clone(),
            params: PrimitiveParams::ConvolveMatrix(params),
        })
    }
}

impl Parse for EdgeMode {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
        Ok(parse_identifiers!(
            parser,
            "duplicate" => EdgeMode::Duplicate,
            "wrap" => EdgeMode::Wrap,
            "none" => EdgeMode::None,
        )?)
    }
}

// Used for the preserveAlpha attribute
impl Parse for bool {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
        Ok(parse_identifiers!(
            parser,
            "false" => false,
            "true" => true,
        )?)
    }
}
<|endoftext|>


<commit_before>pub trait RequestTimeoutable {
    type Output;

    /// Specify `timeout` value. Unit: second
    ///
    /// Panics if specified negative float value.
    fn append_request_timeout(self, timeout: f64) -> Self::Output;
}

macro_rules! request_timeoutable {
    ($($t:ty), +) => (
        $(impl RequestTimeoutable for $t {
            type Output = $t;

            fn append_request_timeout(mut self, timeout: f64) -> Self::Output {
                if !timeout.is_sign_positive() {
                    panic!("`timeout` should be positive 64bit float number.")
                }
                let string = format!("{}", timeout);
                self.arguments.insert("request_timeout".to_string(), string.to_owned());
                self
            }
        })+
    )
}
<commit_msg>rustdoc: Fix Unit markup<commit_after>pub trait RequestTimeoutable {
    type Output;

    /// Specify `timeout` value. Unit: `seconds`
    ///
    /// Panics if specified negative float value.
    fn append_request_timeout(self, timeout: f64) -> Self::Output;
}

macro_rules! request_timeoutable {
    ($($t:ty), +) => (
        $(impl RequestTimeoutable for $t {
            type Output = $t;

            fn append_request_timeout(mut self, timeout: f64) -> Self::Output {
                if !timeout.is_sign_positive() {
                    panic!("`timeout` should be positive 64bit float number.")
                }
                let string = format!("{}", timeout);
                self.arguments.insert("request_timeout".to_string(), string.to_owned());
                self
            }
        })+
    )
}
<|endoftext|>