<commit_before>#![doc(html_favicon_url = "https://www.ruma.io/favicon.ico")]
#![doc(html_logo_url = "https://www.ruma.io/images/logo.png")]
//! Types and traits for working with the [Matrix](https://matrix.org) protocol.
//!
//! This crate re-exports things from all of the other ruma crates so you don't
//! have to manually keep all the versions in sync.
//!
//! Which crates are re-exported can be configured through cargo features.
//!
//! > ⚠ Some details might be missing because rustdoc has trouble with re-exports so you may need
//!   to refer to other crates' documentations.
//!
//! # API features
//!
//! Depending on which parts of Matrix are relevant to you, activate the following features:
//!
//! * `appservice-api` -- Application Service API.
//! * `client-api` -- Client-Server API.
//! * `federation-api` -- Server-Server (Federation) API.
//! * `identity-service-api` -- Identity Service API.
//! * `push-gateway-api` -- Push Gateway API.
//!
//! These features have `client`- and `server`-optimized variants that are enabled respectively
//! with the `-c` and `-s` suffixes. For example:
//!   * `client-api-c` -- The Client-Server API optimized for the client side.
//!   * `client-api-s` -- The Client-Server API optimized for the server side.
//!
//! # Compatibility feature
//!
//! * `compat` increases compatibility with other parts of the Matrix ecosystem, at the expense of
//! deviating from the specification.
//!
//! # Convenience features
//!
//! These features are only useful if you want to use a method that requires it:
//!
//! * `either`
//! * `rand`
//! * `markdown`
//!
//! # Unstable features
//!
//! By using these features, you opt out of all semver guarantees Ruma otherwise provides:
//!
//! * `unstable-exhaustive-types` -- Most types in Ruma are marked as non-exhaustive to avoid
//!   breaking changes when new fields are added in the specification. This feature compiles all
//!   types as exhaustive.
//! * `unstable-mscXXXX`, where `XXXX` is the MSC number -- Upcoming Matrix features that may be
//!   subject to change or removal.
//! * `unstable-pre-spec` -- Undocumented Matrix features that may be subject to change or removal.
//!
//! # Common features
//!
//! These submodules are usually activated by the API features when needed:
//!
//! * `api`
//! * `events`
//! * `signatures`
//!
//! # `ruma-client` features
//!
//! The `client` feature activates [`ruma::client`][client], and `client-ext-client-api` activates
//! `ruma-client`s `client-api` feature. All other `client-*` features activate the same feature
//! without the `client-` prefix on `ruma-client`. See the crate's documentation for the effect of
//! these features.
//!
//! If you are viewing this on `docs.rs`, you can have a look at the feature dependencies by
//! clicking **Feature flags** in the toolbar at the top.

#![warn(missing_docs)]
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]

#[doc(no_inline)]
pub use assign::assign;
#[doc(no_inline)]
pub use js_int::{int, uint, Int, UInt};

pub use ruma_common::*;
#[doc(inline)]
pub use ruma_identifiers as identifiers;
#[doc(inline)]
pub use ruma_serde as serde;

pub use ruma_serde::Outgoing;

pub use ruma_identifiers::{
    device_id, device_key_id, event_id, matrix_uri, mxc_uri, room_alias_id, room_id,
    room_version_id, server_name, server_signing_key_id, user_id, ClientSecret, DeviceId,
    DeviceKeyAlgorithm, DeviceKeyId, DeviceSignatures, DeviceSigningKeyId, EntitySignatures,
    EventEncryptionAlgorithm, EventId, KeyId, KeyName, MatrixToUri, MxcUri, RoomAliasId, RoomId,
    RoomOrAliasId, RoomVersionId, ServerName, ServerSignatures, ServerSigningKeyId, SessionId,
    Signatures, SigningKeyAlgorithm, TransactionId, UserId,
};

#[cfg(feature = "client")]
#[doc(inline)]
pub use ruma_client as client;
#[cfg(feature = "events")]
#[doc(inline)]
pub use ruma_events as events;
#[cfg(feature = "signatures")]
#[doc(inline)]
pub use ruma_signatures as signatures;
#[cfg(feature = "state-res")]
#[doc(inline)]
pub use ruma_state_res as state_res;

/// (De)serializable types for various [Matrix APIs][apis] requests and responses and abstractions
/// for them.
///
/// [apis]: https://spec.matrix.org/v1.2/#matrix-apis
#[cfg(feature = "api")]
pub mod api {
    pub use ruma_api::*;

    #[cfg(feature = "ruma-appservice-api")]
    #[cfg_attr(
        docsrs,
        doc(cfg(any(
            feature = "appservice-api",
            feature = "appservice-api-c",
            feature = "appservice-api-s"
        )))
    )]
    #[doc(inline)]
    pub use ruma_appservice_api as appservice;
    #[cfg(feature = "ruma-client-api")]
    #[cfg_attr(
        docsrs,
        doc(cfg(any(
            feature = "client-api",
            feature = "client-api-c",
            feature = "client-api-s"
        )))
    )]
    #[doc(inline)]
    pub use ruma_client_api as client;
    #[cfg(feature = "ruma-federation-api")]
    #[cfg_attr(
        docsrs,
        doc(cfg(any(
            feature = "federation-api",
            feature = "federation-api-c",
            feature = "federation-api-s"
        )))
    )]
    #[doc(inline)]
    pub use ruma_federation_api as federation;
    #[cfg(feature = "ruma-identity-service-api")]
    #[cfg_attr(
        docsrs,
        doc(cfg(any(
            feature = "identity-service-api",
            feature = "identity-service-api-c",
            feature = "identity-service-api-s"
        )))
    )]
    #[doc(inline)]
    pub use ruma_identity_service_api as identity_service;
    #[cfg(feature = "ruma-push-gateway-api")]
    #[cfg_attr(
        docsrs,
        doc(cfg(any(
            feature = "push-gateway-api",
            feature = "push-gateway-api-c",
            feature = "push-gateway-api-s"
        )))
    )]
    #[doc(inline)]
    pub use ruma_push_gateway_api as push_gateway;
}
<commit_msg>ruma: Reorder re-exports<commit_after>#![doc(html_favicon_url = "https://www.ruma.io/favicon.ico")]
#![doc(html_logo_url = "https://www.ruma.io/images/logo.png")]
//! Types and traits for working with the [Matrix](https://matrix.org) protocol.
//!
//! This crate re-exports things from all of the other ruma crates so you don't
//! have to manually keep all the versions in sync.
//!
//! Which crates are re-exported can be configured through cargo features.
//!
//! > ⚠ Some details might be missing because rustdoc has trouble with re-exports so you may need
//!   to refer to other crates' documentations.
//!
//! # API features
//!
//! Depending on which parts of Matrix are relevant to you, activate the following features:
//!
//! * `appservice-api` -- Application Service API.
//! * `client-api` -- Client-Server API.
//! * `federation-api` -- Server-Server (Federation) API.
//! * `identity-service-api` -- Identity Service API.
//! * `push-gateway-api` -- Push Gateway API.
//!
//! These features have `client`- and `server`-optimized variants that are enabled respectively
//! with the `-c` and `-s` suffixes. For example:
//!   * `client-api-c` -- The Client-Server API optimized for the client side.
//!   * `client-api-s` -- The Client-Server API optimized for the server side.
//!
//! # Compatibility feature
//!
//! * `compat` increases compatibility with other parts of the Matrix ecosystem, at the expense of
//! deviating from the specification.
//!
//! # Convenience features
//!
//! These features are only useful if you want to use a method that requires it:
//!
//! * `either`
//! * `rand`
//! * `markdown`
//!
//! # Unstable features
//!
//! By using these features, you opt out of all semver guarantees Ruma otherwise provides:
//!
//! * `unstable-exhaustive-types` -- Most types in Ruma are marked as non-exhaustive to avoid
//!   breaking changes when new fields are added in the specification. This feature compiles all
//!   types as exhaustive.
//! * `unstable-mscXXXX`, where `XXXX` is the MSC number -- Upcoming Matrix features that may be
//!   subject to change or removal.
//! * `unstable-pre-spec` -- Undocumented Matrix features that may be subject to change or removal.
//!
//! # Common features
//!
//! These submodules are usually activated by the API features when needed:
//!
//! * `api`
//! * `events`
//! * `signatures`
//!
//! # `ruma-client` features
//!
//! The `client` feature activates [`ruma::client`][client], and `client-ext-client-api` activates
//! `ruma-client`s `client-api` feature. All other `client-*` features activate the same feature
//! without the `client-` prefix on `ruma-client`. See the crate's documentation for the effect of
//! these features.
//!
//! If you are viewing this on `docs.rs`, you can have a look at the feature dependencies by
//! clicking **Feature flags** in the toolbar at the top.

#![warn(missing_docs)]
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]

#[doc(inline)]
pub use ruma_identifiers as identifiers;
#[doc(inline)]
pub use ruma_serde as serde;

#[cfg(feature = "client")]
#[doc(inline)]
pub use ruma_client as client;
#[cfg(feature = "events")]
#[doc(inline)]
pub use ruma_events as events;
#[cfg(feature = "signatures")]
#[doc(inline)]
pub use ruma_signatures as signatures;
#[cfg(feature = "state-res")]
#[doc(inline)]
pub use ruma_state_res as state_res;

/// (De)serializable types for various [Matrix APIs][apis] requests and responses and abstractions
/// for them.
///
/// [apis]: https://spec.matrix.org/v1.2/#matrix-apis
#[cfg(feature = "api")]
pub mod api {
    pub use ruma_api::*;

    #[cfg(feature = "ruma-appservice-api")]
    #[cfg_attr(
        docsrs,
        doc(cfg(any(
            feature = "appservice-api",
            feature = "appservice-api-c",
            feature = "appservice-api-s"
        )))
    )]
    #[doc(inline)]
    pub use ruma_appservice_api as appservice;
    #[cfg(feature = "ruma-client-api")]
    #[cfg_attr(
        docsrs,
        doc(cfg(any(
            feature = "client-api",
            feature = "client-api-c",
            feature = "client-api-s"
        )))
    )]
    #[doc(inline)]
    pub use ruma_client_api as client;
    #[cfg(feature = "ruma-federation-api")]
    #[cfg_attr(
        docsrs,
        doc(cfg(any(
            feature = "federation-api",
            feature = "federation-api-c",
            feature = "federation-api-s"
        )))
    )]
    #[doc(inline)]
    pub use ruma_federation_api as federation;
    #[cfg(feature = "ruma-identity-service-api")]
    #[cfg_attr(
        docsrs,
        doc(cfg(any(
            feature = "identity-service-api",
            feature = "identity-service-api-c",
            feature = "identity-service-api-s"
        )))
    )]
    #[doc(inline)]
    pub use ruma_identity_service_api as identity_service;
    #[cfg(feature = "ruma-push-gateway-api")]
    #[cfg_attr(
        docsrs,
        doc(cfg(any(
            feature = "push-gateway-api",
            feature = "push-gateway-api-c",
            feature = "push-gateway-api-s"
        )))
    )]
    #[doc(inline)]
    pub use ruma_push_gateway_api as push_gateway;
}

#[doc(no_inline)]
pub use assign::assign;
#[doc(no_inline)]
pub use js_int::{int, uint, Int, UInt};
pub use ruma_common::*;
pub use ruma_identifiers::{
    device_id, device_key_id, event_id, matrix_uri, mxc_uri, room_alias_id, room_id,
    room_version_id, server_name, server_signing_key_id, user_id, ClientSecret, DeviceId,
    DeviceKeyAlgorithm, DeviceKeyId, DeviceSignatures, DeviceSigningKeyId, EntitySignatures,
    EventEncryptionAlgorithm, EventId, KeyId, KeyName, MatrixToUri, MxcUri, RoomAliasId, RoomId,
    RoomOrAliasId, RoomVersionId, ServerName, ServerSignatures, ServerSigningKeyId, SessionId,
    Signatures, SigningKeyAlgorithm, TransactionId, UserId,
};
pub use ruma_serde::Outgoing;
<|endoftext|>


<commit_before>///Lazy git tool
use std::env::args as cmd_args;
use std::process::Command;

///Executes git command with arguments
///Building sequence of arguments like .arg(@arg)
macro_rules! exec_git_cmd {
    ($($arg:expr),*) => { Command::new("git")$(.arg($arg))*.status().unwrap(); }
}

///Print with prefix >>>
macro_rules! trace {
    ($($arg:expr),*) => { println!(">>>{}", [$(format!("{}", $arg),)*].connect(" ")); }
}

#[inline(always)]
fn usage() {
    println!("lgit [option]\n");
    println!("options:");
    println!("  amend [edit] - amend all changes into last commit");
    println!("  add - add all changes");
    println!("  clean - undo all changes");
    println!("  push [force] - push current branch");
    println!("  commit [message] - commit with message");
    println!("  fetch - get updates from upstream\n");
}

///Amend changes
fn git_amend(args: &[String]) {
    git_add();
    if args.len() != 0 && args[0] == "edit" { exec_git_cmd!("commit", "--amend"); }
    else { exec_git_cmd!("commit", "--amend", "--no-edit"); }
}

///Fetch changes from upstream
fn git_fetch() {
    exec_git_cmd!("checkout", "master");
    exec_git_cmd!("fetch", "upstream");
    exec_git_cmd!("merge", "upstream/master");
}

///Push the current branch
fn git_push(args: &[String]) {
    if args.len() != 0 && args[0] =="force" { exec_git_cmd!("push", "--force", "origin", "HEAD"); }
    else { exec_git_cmd!("push", "origin", "HEAD"); }
}

///Add all changes
fn git_add() {
    exec_git_cmd!("add", "--all");
}

///Undo all changes
fn git_clean() {
    exec_git_cmd!("checkout", "-f");
    exec_git_cmd!("clean", "-fdq");
}

///Commit with message
fn git_commit(args: &[String]) {
    if args.len() == 0 {
        trace!("Empty commit message");
    }
    else {
        exec_git_cmd!("commit", "-m", args.connect(" "));
    }
}

///Unexpected argument handler
fn unexpected(arg: &str) {
    trace!("Unexpected argument:", arg);
    usage();
}

fn main() {
    let args: Vec<String> = cmd_args().collect();
    //To check if git repo present
    let is_repo = exec_git_cmd!("rev-parse", "-q");

    if !is_repo.success() {
        trace!("Not a git repository");
        return;
    }
    else if args.len() == 1 {
        usage();
        return;
    }

    match args[1].as_ref() {
        "amend"  => git_amend(&args[2..]),
        "fetch"  => git_fetch(),
        "push"   => git_push(&args[2..]),
        "add"    => git_add(),
        "clean"  => git_clean(),
        "commit" => git_commit(&args[2..]),
        _        => unexpected(&args[1]),
    }
}
<commit_msg>lgit: null some stderr<commit_after>///Lazy git tool
use std::env::args as cmd_args;
use std::process::{Command, Stdio};

///Executes git command with arguments
///Building sequence of arguments like .arg(@arg)
macro_rules! exec_git_cmd {
    (all_fd=>$fd:expr, $($arg:expr),*) => { Command::new("git")$(.arg($arg))*.stdout($fd).stderr($fd).status().unwrap(); };
    (stdout=>$stdout:expr, stderr=>$stderr:expr, $($arg:expr),*) => { Command::new("git")$(.arg($arg))*.stdout($stdout).stderr($stderr).status().unwrap(); };
    (stdout=>$stdout:expr, $($arg:expr),*) => { Command::new("git")$(.arg($arg))*.stdout($stdout).status().unwrap(); };
    (stderr=>$stderr:expr, $($arg:expr),*) => { Command::new("git")$(.arg($arg))*.stderr($stderr).status().unwrap(); };
    ($($arg:expr),*) => { Command::new("git")$(.arg($arg))*.status().unwrap(); };
}

///Print with prefix >>>
macro_rules! trace {
    ($($arg:expr),*) => { println!(">>>{}", [$(format!("{}", $arg),)*].connect(" ")); }
}

#[inline(always)]
fn usage() {
    println!("lgit [option]\n");
    println!("options:");
    println!("  amend [edit] - amend all changes into last commit");
    println!("  add - add all changes");
    println!("  clean - undo all changes");
    println!("  push [force] - push current branch");
    println!("  commit [message] - commit with message");
    println!("  fetch - get updates from upstream\n");
}

///Amend changes
fn git_amend(args: &[String]) {
    git_add();
    if args.len() != 0 && args[0] == "edit" { exec_git_cmd!("commit", "--amend"); }
    else { exec_git_cmd!("commit", "--amend", "--no-edit"); }
}

///Fetch changes from upstream
fn git_fetch() {
    exec_git_cmd!("checkout", "master");
    exec_git_cmd!("fetch", "upstream");
    exec_git_cmd!("merge", "upstream/master");
}

///Push the current branch
fn git_push(args: &[String]) {
    if args.len() != 0 && args[0] =="force" { exec_git_cmd!("push", "--force", "origin", "HEAD"); }
    else { exec_git_cmd!("push", "origin", "HEAD"); }
}

///Add all changes
fn git_add() {
    exec_git_cmd!("add", "--all");
}

///Undo all changes
fn git_clean() {
    exec_git_cmd!("checkout", "-f");
    exec_git_cmd!("clean", "-fdq");
}

///Commit with message
fn git_commit(args: &[String]) {
    if args.len() == 0 {
        trace!("Empty commit message");
    }
    else {
        exec_git_cmd!("commit", "-m", args.connect(" "));
    }
}

///Unexpected argument handler
fn unexpected(arg: &str) {
    trace!("Unexpected argument:", arg);
    usage();
}

fn main() {
    let args: Vec<String> = cmd_args().collect();
    //To check if git repo present
    let is_repo = exec_git_cmd!(stderr=>Stdio::null(), "rev-parse", "-q");

    if !is_repo.success() {
        trace!("Not a git repository");
        return;
    }
    else if args.len() == 1 {
        usage();
        return;
    }

    match args[1].as_ref() {
        "amend"  => git_amend(&args[2..]),
        "fetch"  => git_fetch(),
        "push"   => git_push(&args[2..]),
        "add"    => git_add(),
        "clean"  => git_clean(),
        "commit" => git_commit(&args[2..]),
        _        => unexpected(&args[1]),
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate wayland_server;

fn main() {
    let (display, mut event_loop) = wayland_server::create_display();

    event_loop.run();
}
<commit_msg>server: silence example warnings<commit_after>extern crate wayland_server;

fn main() {
    let (_display, mut event_loop) = wayland_server::create_display();

    event_loop.run().unwrap();
}
<|endoftext|>


<commit_before>use ritual::config::Config;
use ritual::cpp_checker::{PreliminaryTest, Snippet};
use ritual::cpp_data::{CppItem, CppPath};
use ritual::cpp_ffi_data::CppFfiFunctionKind;
use ritual::cpp_type::CppType;
use ritual::rust_info::{NameType, RustPathScope};
use ritual::rust_type::RustPath;
use ritual_common::errors::{bail, Result};

/// QtCore specific configuration.
pub fn core_config(config: &mut Config) -> Result<()> {
    let crate_name = config.crate_properties().name().to_string();
    let namespace = CppPath::from_good_str("Qt");
    config.set_rust_path_scope_hook(move |path| {
        if path == &namespace {
            return Ok(Some(RustPathScope {
                path: RustPath::from_good_str(&crate_name),
                prefix: None,
            }));
        }
        Ok(None)
    });

    config.set_cpp_parser_path_hook(|path| {
        let string = path.to_templateless_string();
        let blocked = &[
            // Qt internals, not intended for direct use
            "QtPrivate",
            "QAlgorithmsPrivate",
            "QtMetaTypePrivate",
            "QInternal",
            "qFlagLocation",
            "QArrayData",
            "QTypedArrayData",
            "QStaticByteArrayData",
            "QListData",
            "QObjectData",
            "QObjectUserData",
            "QObject::registerUserData",
            "QMapNodeBase",
            "QMapNode",
            "QMapDataBase",
            "QMapData",
            "QHashData",
            "QHashDummyValue",
            "QHashNode",
            "QContiguousCacheData",
            "QContiguousCacheTypedData",
            "QLinkedListData",
            "QLinkedListNode",
            "QThreadStorageData",
            "QVariant::Private",
            "QVariant::PrivateShared",
            "QByteArrayDataPtr",
            "QStringDataPtr",
            "QArrayDataPointer",
            "QArrayDataPointerRef",
            "QMetaTypeId",
            "QMetaTypeId2",
            "QVariantComparisonHelper",
            "QtStringBuilder",
            "QStringBuilder",
            "QStringBuilderCommon",
            "QStringBuilderBase",
            "QConcatenable",
            "QVariant::Handler",
            "QForeachContainer",
            "QPersistentModelIndex::internalId",
            "QPersistentModelIndex::internalPointer",
            "qMapLessThanKey",
            "qt_hash",
            "qt_qFindChild_helper",
            "qt_qFindChildren_helper",
            "qt_sharedpointer_cast_check",
            "qThreadStorage_deleteData",
            "qbswap_helper",
            // deprecated
            "qGreater",
            "qLess",
            "QString::Null",
            // undocumented, does nothing
            "qt_noop",
            "QNoDebug",
            // undocumented, unknown purpose
            "qTerminate",
            "qt_error_string",
            "QFutureInterfaceBase",
            "QFutureInterfaceBase",
            "Qt::Initialization",
            "QAbstractConcatenable",
            "QTextCodec::ConverterState",
            "QJsonValuePtr",
            "QJsonValueRefPtr",
            "QTypeInfo",
            "QTypeInfoQuery",
            "QTypeInfoMerger",
            "QtGlobalStatic",
            "_GUID",
            // for Q_ASSERT, Q_ASSERT_X macros, no need to access this from Rust
            "qt_assert",
            "qt_assert_x",
            // for Q_CHECK_PTR macro, no need to access this from Rust
            "qt_check_pointer",
            "q_check_ptr",
            // atomic operations, useless in Rust
            "QGenericAtomicOps",
            "QAtomicTraits",
            "QAtomicOps",
            "QBasicAtomicInteger",
            "QBasicAtomicPointer",
            "qAtomicAssign",
            "qAtomicDetach",
            "QAtomicAdditiveType",
            "QAtomicInt",
            "QAtomicPointer",
            "QAtomicInteger",
            // BE/LE integers, useless in Rust
            "QSpecialInteger",
            "QBigEndianStorageType",
            "QLittleEndianStorageType",
            // works on overloading, can't be useful in Rust
            "Qt::qt_getEnumName",
            "Qt::qt_getEnumMetaObject",
            // reimplemented in Rust
            "QFlag",
            "QIncompatibleFlag",
            // not useful in Rust
            "QtSharedPointer",
            "QSharedPointer",
            "QWeakPointer",
            "QEnableSharedFromThis",
            "QScopedArrayPointer",
            // throws exception, so useless here
            "qBadAlloc",
            // requires user class templates, so useless here
            "QSharedDataPointer",
            "QExplicitlySharedDataPointer",
            "QSharedData",
            "QScopeGuard",
            "QScopedValueRollback",
            "QScopedPointer",
            "QScopedPointerObjectDeleteLater",
            "QScopedPointerPodDeleter",
            "QScopedPointerDeleter",
            "QScopedPointerArrayDeleter",
            "QGenericArgument",
            "QGenericReturnArgument",
            "QNonConstOverload",
            "QConstOverload",
            // global functions that redirects to member functions
            "swap",
            // is not cross-platform and is deprecated anyway
            "QProcess::pid",
        ];
        if blocked.contains(&string.as_str()) {
            return Ok(false);
        }

        Ok(true)
    });
    // TODO: replace QVariant::Type with QMetaType::Type?

    let connect_path = CppPath::from_good_str("QObject::connect");
    let qmetamethod_ref_type =
        CppType::new_reference(true, CppType::Class(CppPath::from_good_str("QMetaMethod")));
    config.set_rust_path_hook(move |_path, name_type, data| {
        if let NameType::ApiFunction(function) = name_type {
            if let CppFfiFunctionKind::Function { cpp_function, .. } = &function.kind {
                if cpp_function.path == connect_path && cpp_function.arguments.len() >= 3 {
                    if !cpp_function.is_static_member() {
                        bail!("non-static QObject::connect is blacklisted");
                    }
                    let arg = &cpp_function.arguments[1].argument_type;
                    if arg == &qmetamethod_ref_type {
                        return Ok(Some(RustPath::from_good_str(&format!(
                            "{}::QObject::connect_by_meta_methods",
                            data.current_database.crate_name()
                        ))));
                    }
                }
            }
        }
        Ok(None)
    });

    config.set_ffi_generator_hook(|item| {
        if let CppItem::Function(function) = &item.item {
            if let Ok(class_type) = function.class_type() {
                let class_text = class_type.to_templateless_string();
                if class_text == "QFlags" {
                    return Ok(false);
                }
            }
            if function.is_operator() {
                if let CppType::Class(path) = &function.return_type {
                    if path.to_templateless_string() == "QFlags" {
                        return Ok(false);
                    }
                }
            }
        }
        Ok(true)
    });

    let tests = if config.crate_properties().name().starts_with("moqt") {
        vec![PreliminaryTest::new(
            "moqt_abs",
            true,
            Snippet::new_in_main("ritual_assert(moqt_abs(-2) == 2);", false),
        )]
    } else {
        let code1 = format!(
            "ritual_assert(QLibraryInfo::version().toString() == \"{}\");",
            config.cpp_lib_version().unwrap()
        );
        let test1 = PreliminaryTest::new("qt_version_fn", true, Snippet::new_in_main(code1, false));

        let code2 = format!(
            "ritual_assert(strcmp(QT_VERSION_STR, \"{}\") == 0);",
            config.cpp_lib_version().unwrap()
        );
        let test2 = PreliminaryTest::new(
            "qt_version_define",
            true,
            Snippet::new_in_main(code2, false),
        );
        let code3 = "
            class Class1 : public QObject {
            Q_OBJECT
            public:
                Class1() {
                    emit signal1();
                }
            signals:
                void signal1();
            };

            void x() {
                Class1 c;
            }
        ";
        let test3 =
            PreliminaryTest::new("class_with_signal", true, Snippet::new_global(code3, true));

        vec![test1, test2, test3]
    };
    config.add_cpp_checker_tests(tests);
    Ok(())
}
<commit_msg>move QTextStream helpers to module<commit_after>use ritual::config::Config;
use ritual::cpp_checker::{PreliminaryTest, Snippet};
use ritual::cpp_data::{CppItem, CppPath};
use ritual::cpp_ffi_data::CppFfiFunctionKind;
use ritual::cpp_type::CppType;
use ritual::rust_info::{NameType, RustPathScope};
use ritual::rust_type::RustPath;
use ritual_common::errors::{bail, Result};
use ritual_common::string_utils::CaseOperations;

/// QtCore specific configuration.
pub fn core_config(config: &mut Config) -> Result<()> {
    let crate_name = config.crate_properties().name().to_string();
    let namespace = CppPath::from_good_str("Qt");
    config.set_rust_path_scope_hook(move |path| {
        if path == &namespace {
            return Ok(Some(RustPathScope {
                path: RustPath::from_good_str(&crate_name),
                prefix: None,
            }));
        }
        Ok(None)
    });

    config.set_cpp_parser_path_hook(|path| {
        let string = path.to_templateless_string();
        let blocked = &[
            // Qt internals, not intended for direct use
            "QtPrivate",
            "QAlgorithmsPrivate",
            "QtMetaTypePrivate",
            "QInternal",
            "qFlagLocation",
            "QArrayData",
            "QTypedArrayData",
            "QStaticByteArrayData",
            "QListData",
            "QObjectData",
            "QObjectUserData",
            "QObject::registerUserData",
            "QMapNodeBase",
            "QMapNode",
            "QMapDataBase",
            "QMapData",
            "QHashData",
            "QHashDummyValue",
            "QHashNode",
            "QContiguousCacheData",
            "QContiguousCacheTypedData",
            "QLinkedListData",
            "QLinkedListNode",
            "QThreadStorageData",
            "QVariant::Private",
            "QVariant::PrivateShared",
            "QByteArrayDataPtr",
            "QStringDataPtr",
            "QArrayDataPointer",
            "QArrayDataPointerRef",
            "QMetaTypeId",
            "QMetaTypeId2",
            "QVariantComparisonHelper",
            "QtStringBuilder",
            "QStringBuilder",
            "QStringBuilderCommon",
            "QStringBuilderBase",
            "QConcatenable",
            "QVariant::Handler",
            "QForeachContainer",
            "QPersistentModelIndex::internalId",
            "QPersistentModelIndex::internalPointer",
            "qMapLessThanKey",
            "qt_hash",
            "qt_qFindChild_helper",
            "qt_qFindChildren_helper",
            "qt_sharedpointer_cast_check",
            "qThreadStorage_deleteData",
            "qbswap_helper",
            // deprecated
            "qGreater",
            "qLess",
            "QString::Null",
            // undocumented, does nothing
            "qt_noop",
            "QNoDebug",
            // undocumented, unknown purpose
            "qTerminate",
            "qt_error_string",
            "QFutureInterfaceBase",
            "QFutureInterfaceBase",
            "Qt::Initialization",
            "QAbstractConcatenable",
            "QTextCodec::ConverterState",
            "QJsonValuePtr",
            "QJsonValueRefPtr",
            "QTypeInfo",
            "QTypeInfoQuery",
            "QTypeInfoMerger",
            "QtGlobalStatic",
            "_GUID",
            // for Q_ASSERT, Q_ASSERT_X macros, no need to access this from Rust
            "qt_assert",
            "qt_assert_x",
            // for Q_CHECK_PTR macro, no need to access this from Rust
            "qt_check_pointer",
            "q_check_ptr",
            // atomic operations, useless in Rust
            "QGenericAtomicOps",
            "QAtomicTraits",
            "QAtomicOps",
            "QBasicAtomicInteger",
            "QBasicAtomicPointer",
            "qAtomicAssign",
            "qAtomicDetach",
            "QAtomicAdditiveType",
            "QAtomicInt",
            "QAtomicPointer",
            "QAtomicInteger",
            // BE/LE integers, useless in Rust
            "QSpecialInteger",
            "QBigEndianStorageType",
            "QLittleEndianStorageType",
            // works on overloading, can't be useful in Rust
            "Qt::qt_getEnumName",
            "Qt::qt_getEnumMetaObject",
            // reimplemented in Rust
            "QFlag",
            "QIncompatibleFlag",
            // not useful in Rust
            "QtSharedPointer",
            "QSharedPointer",
            "QWeakPointer",
            "QEnableSharedFromThis",
            "QScopedArrayPointer",
            // throws exception, so useless here
            "qBadAlloc",
            // requires user class templates, so useless here
            "QSharedDataPointer",
            "QExplicitlySharedDataPointer",
            "QSharedData",
            "QScopeGuard",
            "QScopedValueRollback",
            "QScopedPointer",
            "QScopedPointerObjectDeleteLater",
            "QScopedPointerPodDeleter",
            "QScopedPointerDeleter",
            "QScopedPointerArrayDeleter",
            "QGenericArgument",
            "QGenericReturnArgument",
            "QNonConstOverload",
            "QConstOverload",
            // global functions that redirects to member functions
            "swap",
            // is not cross-platform and is deprecated anyway
            "QProcess::pid",
        ];
        if blocked.contains(&string.as_str()) {
            return Ok(false);
        }

        Ok(true)
    });
    // TODO: replace QVariant::Type with QMetaType::Type?

    let connect_path = CppPath::from_good_str("QObject::connect");
    let qmetamethod_ref_type =
        CppType::new_reference(true, CppType::Class(CppPath::from_good_str("QMetaMethod")));
    config.set_rust_path_hook(move |_path, name_type, data| {
        if let NameType::ApiFunction(function) = name_type {
            if let CppFfiFunctionKind::Function { cpp_function, .. } = &function.kind {
                if cpp_function.path == connect_path && cpp_function.arguments.len() >= 3 {
                    if !cpp_function.is_static_member() {
                        bail!("non-static QObject::connect is blacklisted");
                    }
                    let arg = &cpp_function.arguments[1].argument_type;
                    if arg == &qmetamethod_ref_type {
                        return Ok(Some(RustPath::from_good_str(&format!(
                            "{}::QObject::connect_by_meta_methods",
                            data.current_database.crate_name()
                        ))));
                    }
                }

                let q_text_stream_functions = &[
                    "bin",
                    "bom",
                    "center",
                    "dec",
                    "endl",
                    "fixed",
                    "flush",
                    "forcepoint",
                    "forcesign",
                    "hex",
                    "left",
                    "lowercasebase",
                    "lowercasedigits",
                    "noforcepoint",
                    "noforcesign",
                    "noshowbase",
                    "oct",
                    "reset",
                    "right",
                    "scientific",
                    "showbase",
                    "uppercasebase",
                    "uppercasedigits",
                    "ws",
                    "qSetFieldWidth",
                    "qSetPadChar",
                    "qSetRealNumberPrecision",
                ];

                if cpp_function.path.items().len() == 1
                    && q_text_stream_functions.contains(&cpp_function.path.items()[0].name.as_str())
                {
                    let path = RustPath::from_good_str(data.current_database.crate_name())
                        .join("q_text_stream")
                        .join(cpp_function.path.items()[0].name.to_snake_case());

                    return Ok(Some(path));
                }
            }
        }
        Ok(None)
    });

    config.set_ffi_generator_hook(|item| {
        if let CppItem::Function(function) = &item.item {
            if let Ok(class_type) = function.class_type() {
                let class_text = class_type.to_templateless_string();
                if class_text == "QFlags" {
                    return Ok(false);
                }
            }
            if function.is_operator() {
                if let CppType::Class(path) = &function.return_type {
                    if path.to_templateless_string() == "QFlags" {
                        return Ok(false);
                    }
                }
            }
        }
        Ok(true)
    });

    let tests = if config.crate_properties().name().starts_with("moqt") {
        vec![PreliminaryTest::new(
            "moqt_abs",
            true,
            Snippet::new_in_main("ritual_assert(moqt_abs(-2) == 2);", false),
        )]
    } else {
        let code1 = format!(
            "ritual_assert(QLibraryInfo::version().toString() == \"{}\");",
            config.cpp_lib_version().unwrap()
        );
        let test1 = PreliminaryTest::new("qt_version_fn", true, Snippet::new_in_main(code1, false));

        let code2 = format!(
            "ritual_assert(strcmp(QT_VERSION_STR, \"{}\") == 0);",
            config.cpp_lib_version().unwrap()
        );
        let test2 = PreliminaryTest::new(
            "qt_version_define",
            true,
            Snippet::new_in_main(code2, false),
        );
        let code3 = "
            class Class1 : public QObject {
            Q_OBJECT
            public:
                Class1() {
                    emit signal1();
                }
            signals:
                void signal1();
            };

            void x() {
                Class1 c;
            }
        ";
        let test3 =
            PreliminaryTest::new("class_with_signal", true, Snippet::new_global(code3, true));

        vec![test1, test2, test3]
    };
    config.add_cpp_checker_tests(tests);
    Ok(())
}
<|endoftext|>


<commit_before>use ritual::config::Config;
use ritual::cpp_checker::{PreliminaryTest, Snippet};
use ritual::cpp_data::{CppItem, CppPath};
use ritual::cpp_ffi_data::CppFfiFunctionKind;
use ritual::cpp_type::CppType;
use ritual::rust_info::{NameType, RustPathScope};
use ritual::rust_type::RustPath;
use ritual_common::errors::{bail, Result};

/// QtCore specific configuration.
pub fn core_config(config: &mut Config) -> Result<()> {
    let crate_name = config.crate_properties().name().to_string();
    let namespace = CppPath::from_good_str("Qt");
    config.set_rust_path_scope_hook(move |path| {
        if path == &namespace {
            return Ok(Some(RustPathScope {
                path: RustPath::from_good_str(&crate_name),
                prefix: None,
            }));
        }
        Ok(None)
    });

    config.set_cpp_parser_path_hook(|path| {
        let string = path.to_templateless_string();
        let blocked = &[
            // Qt internals, not intended for direct use
            "QtPrivate",
            "QAlgorithmsPrivate",
            "QtMetaTypePrivate",
            "QInternal",
            "qFlagLocation",
            "QArrayData",
            "QTypedArrayData",
            "QStaticByteArrayData",
            "QListData",
            "QObjectData",
            "QObjectUserData",
            "QObject::registerUserData",
            "QMapNodeBase",
            "QMapNode",
            "QMapDataBase",
            "QMapData",
            "QHashData",
            "QHashDummyValue",
            "QHashNode",
            "QContiguousCacheData",
            "QContiguousCacheTypedData",
            "QLinkedListData",
            "QLinkedListNode",
            "QThreadStorageData",
            "QVariant::Private",
            "QVariant::PrivateShared",
            "QByteArrayDataPtr",
            "QStringDataPtr",
            "QArrayDataPointer",
            "QArrayDataPointerRef",
            "QMetaTypeId",
            "QMetaTypeId2",
            "QVariantComparisonHelper",
            "QtStringBuilder",
            "QStringBuilder",
            "QStringBuilderCommon",
            "QStringBuilderBase",
            "QConcatenable",
            "QVariant::Handler",
            "QForeachContainer",
            "QPersistentModelIndex::internalId",
            "QPersistentModelIndex::internalPointer",
            "qMapLessThanKey",
            "qt_hash",
            "qt_qFindChild_helper",
            "qt_qFindChildren_helper",
            "qt_sharedpointer_cast_check",
            "qThreadStorage_deleteData",
            "qbswap_helper",
            // deprecated
            "qGreater",
            "qLess",
            "QString::Null",
            // undocumented, does nothing
            "qt_noop",
            "QNoDebug",
            // undocumented, unknown purpose
            "qTerminate",
            "qt_error_string",
            "QFutureInterfaceBase",
            "QFutureInterfaceBase",
            "Qt::Initialization",
            "QAbstractConcatenable",
            "QTextCodec::ConverterState",
            "QJsonValuePtr",
            "QJsonValueRefPtr",
            "QTypeInfo",
            "QTypeInfoQuery",
            "QTypeInfoMerger",
            "QtGlobalStatic",
            "_GUID",
            // for Q_ASSERT, Q_ASSERT_X macros, no need to access this from Rust
            "qt_assert",
            "qt_assert_x",
            // for Q_CHECK_PTR macro, no need to access this from Rust
            "qt_check_pointer",
            "q_check_ptr",
            // atomic operations, useless in Rust
            "QGenericAtomicOps",
            "QAtomicTraits",
            "QAtomicOps",
            "QBasicAtomicInteger",
            "QBasicAtomicPointer",
            "qAtomicAssign",
            "qAtomicDetach",
            "QAtomicAdditiveType",
            "QAtomicInt",
            "QAtomicPointer",
            "QAtomicInteger",
            // BE/LE integers, useless in Rust
            "QSpecialInteger",
            "QBigEndianStorageType",
            "QLittleEndianStorageType",
            // works on overloading, can't be useful in Rust
            "Qt::qt_getEnumName",
            // reimplemented in Rust
            "QFlag",
            "QIncompatibleFlag",
            // not useful in Rust
            "QtSharedPointer",
            "QSharedPointer",
            "QWeakPointer",
            "QEnableSharedFromThis",
            "QScopedArrayPointer",
            // throws exception, so useless here
            "qBadAlloc",
            // requires user class templates, so useless here
            "QSharedDataPointer",
            "QExplicitlySharedDataPointer",
            "QSharedData",
            "QScopeGuard",
            "QScopedValueRollback",
            "QScopedPointer",
            "QScopedPointerObjectDeleteLater",
            "QScopedPointerPodDeleter",
            "QScopedPointerDeleter",
            "QScopedPointerArrayDeleter",
            "QGenericArgument",
            "QGenericReturnArgument",
            "QNonConstOverload",
            "QConstOverload",
            // global functions that redirects to member functions
            "swap",
        ];
        if blocked.contains(&string.as_str()) {
            return Ok(false);
        }

        Ok(true)
    });
    // TODO: replace QVariant::Type with QMetaType::Type?

    let connect_path = CppPath::from_good_str("QObject::connect");
    let qmetamethod_ref_type =
        CppType::new_reference(true, CppType::Class(CppPath::from_good_str("QMetaMethod")));
    config.set_rust_path_hook(move |_path, name_type, data| {
        if let NameType::ApiFunction(function) = name_type {
            if let CppFfiFunctionKind::Function { cpp_function, .. } = &function.kind {
                if cpp_function.path == connect_path && cpp_function.arguments.len() >= 3 {
                    if !cpp_function.is_static_member() {
                        bail!("non-static QObject::connect is blacklisted");
                    }
                    let arg = &cpp_function.arguments[1].argument_type;
                    if arg == &qmetamethod_ref_type {
                        return Ok(Some(RustPath::from_good_str(&format!(
                            "{}::QObject::connect_by_meta_methods",
                            data.current_database.crate_name()
                        ))));
                    }
                }
            }
        }
        Ok(None)
    });

    config.set_ffi_generator_hook(|item| {
        if let CppItem::Function(function) = &item.item {
            if let Ok(class_type) = function.class_type() {
                let class_text = class_type.to_templateless_string();
                if class_text == "QFlags" {
                    return Ok(false);
                }
            }
            if function.is_operator() {
                if let CppType::Class(path) = &function.return_type {
                    if path.to_templateless_string() == "QFlags" {
                        return Ok(false);
                    }
                }
            }
        }
        Ok(true)
    });

    let tests = if config.crate_properties().name().starts_with("moqt") {
        vec![PreliminaryTest::new(
            "moqt_abs",
            true,
            Snippet::new_in_main("ritual_assert(moqt_abs(-2) == 2);", false),
        )]
    } else {
        let code1 = format!(
            "ritual_assert(QLibraryInfo::version().toString() == \"{}\");",
            config.cpp_lib_version().unwrap()
        );
        let test1 = PreliminaryTest::new("qt_version_fn", true, Snippet::new_in_main(code1, false));

        let code2 = format!(
            "ritual_assert(strcmp(QT_VERSION_STR, \"{}\") == 0);",
            config.cpp_lib_version().unwrap()
        );
        let test2 = PreliminaryTest::new(
            "qt_version_define",
            true,
            Snippet::new_in_main(code2, false),
        );
        let code3 = "
            class Class1 : public QObject {
            Q_OBJECT
            public:
                Class1() {
                    emit signal1();
                }
            signals:
                void signal1();
            };

            void x() {
                Class1 c;
            }
        ";
        let test3 =
            PreliminaryTest::new("class_with_signal", true, Snippet::new_global(code3, true));

        vec![test1, test2, test3]
    };
    config.add_cpp_checker_tests(tests);
    Ok(())
}
<commit_msg>blacklist QProcess::pid<commit_after>use ritual::config::Config;
use ritual::cpp_checker::{PreliminaryTest, Snippet};
use ritual::cpp_data::{CppItem, CppPath};
use ritual::cpp_ffi_data::CppFfiFunctionKind;
use ritual::cpp_type::CppType;
use ritual::rust_info::{NameType, RustPathScope};
use ritual::rust_type::RustPath;
use ritual_common::errors::{bail, Result};

/// QtCore specific configuration.
pub fn core_config(config: &mut Config) -> Result<()> {
    let crate_name = config.crate_properties().name().to_string();
    let namespace = CppPath::from_good_str("Qt");
    config.set_rust_path_scope_hook(move |path| {
        if path == &namespace {
            return Ok(Some(RustPathScope {
                path: RustPath::from_good_str(&crate_name),
                prefix: None,
            }));
        }
        Ok(None)
    });

    config.set_cpp_parser_path_hook(|path| {
        let string = path.to_templateless_string();
        let blocked = &[
            // Qt internals, not intended for direct use
            "QtPrivate",
            "QAlgorithmsPrivate",
            "QtMetaTypePrivate",
            "QInternal",
            "qFlagLocation",
            "QArrayData",
            "QTypedArrayData",
            "QStaticByteArrayData",
            "QListData",
            "QObjectData",
            "QObjectUserData",
            "QObject::registerUserData",
            "QMapNodeBase",
            "QMapNode",
            "QMapDataBase",
            "QMapData",
            "QHashData",
            "QHashDummyValue",
            "QHashNode",
            "QContiguousCacheData",
            "QContiguousCacheTypedData",
            "QLinkedListData",
            "QLinkedListNode",
            "QThreadStorageData",
            "QVariant::Private",
            "QVariant::PrivateShared",
            "QByteArrayDataPtr",
            "QStringDataPtr",
            "QArrayDataPointer",
            "QArrayDataPointerRef",
            "QMetaTypeId",
            "QMetaTypeId2",
            "QVariantComparisonHelper",
            "QtStringBuilder",
            "QStringBuilder",
            "QStringBuilderCommon",
            "QStringBuilderBase",
            "QConcatenable",
            "QVariant::Handler",
            "QForeachContainer",
            "QPersistentModelIndex::internalId",
            "QPersistentModelIndex::internalPointer",
            "qMapLessThanKey",
            "qt_hash",
            "qt_qFindChild_helper",
            "qt_qFindChildren_helper",
            "qt_sharedpointer_cast_check",
            "qThreadStorage_deleteData",
            "qbswap_helper",
            // deprecated
            "qGreater",
            "qLess",
            "QString::Null",
            // undocumented, does nothing
            "qt_noop",
            "QNoDebug",
            // undocumented, unknown purpose
            "qTerminate",
            "qt_error_string",
            "QFutureInterfaceBase",
            "QFutureInterfaceBase",
            "Qt::Initialization",
            "QAbstractConcatenable",
            "QTextCodec::ConverterState",
            "QJsonValuePtr",
            "QJsonValueRefPtr",
            "QTypeInfo",
            "QTypeInfoQuery",
            "QTypeInfoMerger",
            "QtGlobalStatic",
            "_GUID",
            // for Q_ASSERT, Q_ASSERT_X macros, no need to access this from Rust
            "qt_assert",
            "qt_assert_x",
            // for Q_CHECK_PTR macro, no need to access this from Rust
            "qt_check_pointer",
            "q_check_ptr",
            // atomic operations, useless in Rust
            "QGenericAtomicOps",
            "QAtomicTraits",
            "QAtomicOps",
            "QBasicAtomicInteger",
            "QBasicAtomicPointer",
            "qAtomicAssign",
            "qAtomicDetach",
            "QAtomicAdditiveType",
            "QAtomicInt",
            "QAtomicPointer",
            "QAtomicInteger",
            // BE/LE integers, useless in Rust
            "QSpecialInteger",
            "QBigEndianStorageType",
            "QLittleEndianStorageType",
            // works on overloading, can't be useful in Rust
            "Qt::qt_getEnumName",
            // reimplemented in Rust
            "QFlag",
            "QIncompatibleFlag",
            // not useful in Rust
            "QtSharedPointer",
            "QSharedPointer",
            "QWeakPointer",
            "QEnableSharedFromThis",
            "QScopedArrayPointer",
            // throws exception, so useless here
            "qBadAlloc",
            // requires user class templates, so useless here
            "QSharedDataPointer",
            "QExplicitlySharedDataPointer",
            "QSharedData",
            "QScopeGuard",
            "QScopedValueRollback",
            "QScopedPointer",
            "QScopedPointerObjectDeleteLater",
            "QScopedPointerPodDeleter",
            "QScopedPointerDeleter",
            "QScopedPointerArrayDeleter",
            "QGenericArgument",
            "QGenericReturnArgument",
            "QNonConstOverload",
            "QConstOverload",
            // global functions that redirects to member functions
            "swap",
            // is not cross-platform and is deprecated anyway
            "QProcess::pid",
        ];
        if blocked.contains(&string.as_str()) {
            return Ok(false);
        }

        Ok(true)
    });
    // TODO: replace QVariant::Type with QMetaType::Type?

    let connect_path = CppPath::from_good_str("QObject::connect");
    let qmetamethod_ref_type =
        CppType::new_reference(true, CppType::Class(CppPath::from_good_str("QMetaMethod")));
    config.set_rust_path_hook(move |_path, name_type, data| {
        if let NameType::ApiFunction(function) = name_type {
            if let CppFfiFunctionKind::Function { cpp_function, .. } = &function.kind {
                if cpp_function.path == connect_path && cpp_function.arguments.len() >= 3 {
                    if !cpp_function.is_static_member() {
                        bail!("non-static QObject::connect is blacklisted");
                    }
                    let arg = &cpp_function.arguments[1].argument_type;
                    if arg == &qmetamethod_ref_type {
                        return Ok(Some(RustPath::from_good_str(&format!(
                            "{}::QObject::connect_by_meta_methods",
                            data.current_database.crate_name()
                        ))));
                    }
                }
            }
        }
        Ok(None)
    });

    config.set_ffi_generator_hook(|item| {
        if let CppItem::Function(function) = &item.item {
            if let Ok(class_type) = function.class_type() {
                let class_text = class_type.to_templateless_string();
                if class_text == "QFlags" {
                    return Ok(false);
                }
            }
            if function.is_operator() {
                if let CppType::Class(path) = &function.return_type {
                    if path.to_templateless_string() == "QFlags" {
                        return Ok(false);
                    }
                }
            }
        }
        Ok(true)
    });

    let tests = if config.crate_properties().name().starts_with("moqt") {
        vec![PreliminaryTest::new(
            "moqt_abs",
            true,
            Snippet::new_in_main("ritual_assert(moqt_abs(-2) == 2);", false),
        )]
    } else {
        let code1 = format!(
            "ritual_assert(QLibraryInfo::version().toString() == \"{}\");",
            config.cpp_lib_version().unwrap()
        );
        let test1 = PreliminaryTest::new("qt_version_fn", true, Snippet::new_in_main(code1, false));

        let code2 = format!(
            "ritual_assert(strcmp(QT_VERSION_STR, \"{}\") == 0);",
            config.cpp_lib_version().unwrap()
        );
        let test2 = PreliminaryTest::new(
            "qt_version_define",
            true,
            Snippet::new_in_main(code2, false),
        );
        let code3 = "
            class Class1 : public QObject {
            Q_OBJECT
            public:
                Class1() {
                    emit signal1();
                }
            signals:
                void signal1();
            };

            void x() {
                Class1 c;
            }
        ";
        let test3 =
            PreliminaryTest::new("class_with_signal", true, Snippet::new_global(code3, true));

        vec![test1, test2, test3]
    };
    config.add_cpp_checker_tests(tests);
    Ok(())
}
<|endoftext|>


<commit_before>use cairo;
use glib::translate::*;
use glib_sys;
use libc;

use std::f64::consts::*;

use cairo::MatrixTrait;
use cssparser::{ParseError as CssParseError, Parser, ParserInput, Token};

use error::*;
use parsers::{optional_comma, Parse, ParseError};
use util::utf8_cstr;

impl Parse for cairo::Matrix {
    type Data = ();
    type Err = AttributeError;

    fn parse(s: &str, _: ()) -> Result<cairo::Matrix, AttributeError> {
        parse_transform(s)
    }
}

// This parser is for the "transform" attribute in SVG.
// Its operataion and grammar are described here:
// https://www.w3.org/TR/SVG/coords.html#TransformAttribute

pub fn parse_transform(s: &str) -> Result<cairo::Matrix, AttributeError> {
    let matrix = parse_transform_list(s)?;

    matrix
        .try_invert()
        .map(|_| matrix)
        .map_err(|_| AttributeError::Value("invalid transformation matrix".to_string()))
}

fn parse_transform_list(s: &str) -> Result<cairo::Matrix, AttributeError> {
    let mut input = ParserInput::new(s);
    let mut parser = Parser::new(&mut input);

    let mut matrix = cairo::Matrix::identity();

    loop {
        let m = parse_transform_command(&mut parser)?;
        matrix = cairo::Matrix::multiply(&m, &matrix);

        if parser.is_exhausted() {
            break;
        }

        optional_comma(&mut parser);
    }

    Ok(matrix)
}

fn make_expected_function_error() -> AttributeError {
    AttributeError::from(ParseError::new(
        "expected matrix|translate|scale|rotate|skewX|skewY",
    ))
}

fn parse_transform_command(parser: &mut Parser) -> Result<cairo::Matrix, AttributeError> {
    match parser.next()?.clone() {
        Token::Function(ref name) => parse_transform_function(name, parser),

        Token::Ident(ref name) => {
            parser.expect_parenthesis_block()?;
            parse_transform_function(name, parser)
        }

        _ => Err(make_expected_function_error()),
    }
}

fn parse_transform_function(
    name: &str,
    parser: &mut Parser,
) -> Result<cairo::Matrix, AttributeError> {
    match name {
        "matrix" => parse_matrix_args(parser),
        "translate" => parse_translate_args(parser),
        "scale" => parse_scale_args(parser),
        "rotate" => parse_rotate_args(parser),
        "skewX" => parse_skewx_args(parser),
        "skewY" => parse_skewy_args(parser),
        _ => Err(make_expected_function_error()),
    }
}

fn parse_matrix_args(parser: &mut Parser) -> Result<cairo::Matrix, AttributeError> {
    parser
        .parse_nested_block(|p| {
            let xx = f64::from(p.expect_number()?);
            optional_comma(p);

            let yx = f64::from(p.expect_number()?);
            optional_comma(p);

            let xy = f64::from(p.expect_number()?);
            optional_comma(p);

            let yy = f64::from(p.expect_number()?);
            optional_comma(p);

            let x0 = f64::from(p.expect_number()?);
            optional_comma(p);

            let y0 = f64::from(p.expect_number()?);

            Ok(cairo::Matrix::new(xx, yx, xy, yy, x0, y0))
        })
        .map_err(CssParseError::<()>::basic)
        .map_err(AttributeError::from)
}

fn parse_translate_args(parser: &mut Parser) -> Result<cairo::Matrix, AttributeError> {
    parser
        .parse_nested_block(|p| {
            let tx = f64::from(p.expect_number()?);

            let ty = f64::from(p.try(|p| -> Result<f32, CssParseError<()>> {
                optional_comma(p);
                Ok(p.expect_number()?)
            }).unwrap_or(0.0));

            Ok(cairo::Matrix::new(1.0, 0.0, 0.0, 1.0, tx, ty))
        })
        .map_err(CssParseError::<()>::basic)
        .map_err(AttributeError::from)
}

fn parse_scale_args(parser: &mut Parser) -> Result<cairo::Matrix, AttributeError> {
    parser
        .parse_nested_block(|p| {
            let x = f64::from(p.expect_number()?);

            let y = p.try(|p| -> Result<f32, CssParseError<()>> {
                optional_comma(p);
                Ok(p.expect_number()?)
            }).map(f64::from)
                .unwrap_or(x);

            Ok(cairo::Matrix::new(x, 0.0, 0.0, y, 0.0, 0.0))
        })
        .map_err(CssParseError::<()>::basic)
        .map_err(AttributeError::from)
}

fn parse_rotate_args(parser: &mut Parser) -> Result<cairo::Matrix, AttributeError> {
    parser
        .parse_nested_block(|p| {
            let angle = f64::from(p.expect_number()?) * PI / 180.0;
            let (s, c) = angle.sin_cos();

            let (tx, ty) = p.try(|p| -> Result<_, CssParseError<()>> {
                optional_comma(p);
                let tx = f64::from(p.expect_number()?);

                optional_comma(p);
                let ty = f64::from(p.expect_number()?);

                Ok((tx, ty))
            }).unwrap_or((0.0, 0.0));

            let mut m = cairo::Matrix::new(1.0, 0.0, 0.0, 1.0, tx, ty);

            m = cairo::Matrix::multiply(&cairo::Matrix::new(c, s, -s, c, 0.0, 0.0), &m);
            m = cairo::Matrix::multiply(&cairo::Matrix::new(1.0, 0.0, 0.0, 1.0, -tx, -ty), &m);
            Ok(m)
        })
        .map_err(CssParseError::<()>::basic)
        .map_err(AttributeError::from)
}

fn parse_skewx_args(parser: &mut Parser) -> Result<cairo::Matrix, AttributeError> {
    parser
        .parse_nested_block(|p| {
            let a = f64::from(p.expect_number()?) * PI / 180.0;
            Ok(cairo::Matrix::new(1.0, 0.0, a.tan(), 1.0, 0.0, 0.0))
        })
        .map_err(CssParseError::<()>::basic)
        .map_err(AttributeError::from)
}

fn parse_skewy_args(parser: &mut Parser) -> Result<cairo::Matrix, AttributeError> {
    parser
        .parse_nested_block(|p| {
            let a = f64::from(p.expect_number()?) * PI / 180.0;
            Ok(cairo::Matrix::new(1.0, a.tan(), 0.0, 1.0, 0.0, 0.0))
        })
        .map_err(CssParseError::<()>::basic)
        .map_err(AttributeError::from)
}

#[cfg(test)]
fn make_rotation_matrix(angle_degrees: f64, tx: f64, ty: f64) -> cairo::Matrix {
    let angle = angle_degrees * PI / 180.0;

    let mut m = cairo::Matrix::new(1.0, 0.0, 0.0, 1.0, tx, ty);

    let mut r = cairo::Matrix::identity();
    r.rotate(angle);
    m = cairo::Matrix::multiply(&r, &m);

    m = cairo::Matrix::multiply(&cairo::Matrix::new(1.0, 0.0, 0.0, 1.0, -tx, -ty), &m);
    m
}

#[no_mangle]
pub extern "C" fn rsvg_parse_transform(
    out_matrix: *mut cairo::Matrix,
    s: *const libc::c_char,
) -> glib_sys::gboolean {
    assert!(!out_matrix.is_null());
    assert!(!s.is_null());

    let string = unsafe { utf8_cstr(s) };
    let matrix: &mut cairo::Matrix = unsafe { &mut *out_matrix };

    match parse_transform(string) {
        Ok(m) => {
            *matrix = m;
            true.to_glib()
        }

        Err(_) => {
            *matrix = cairo::Matrix::identity();
            false.to_glib()
        }
    }
}

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

    #[test]
    fn parses_valid_transform() {
        let t = cairo::Matrix::new(1.0, 0.0, 0.0, 1.0, 20.0, 30.0);
        let s = cairo::Matrix::new(10.0, 0.0, 0.0, 10.0, 0.0, 0.0);
        let r = make_rotation_matrix(30.0, 10.0, 10.0);

        let a = cairo::Matrix::multiply(&s, &t);
        assert_eq!(
            parse_transform("translate(20, 30), scale (10) rotate (30 10 10)").unwrap(),
            cairo::Matrix::multiply(&r, &a)
        );
    }

    fn assert_parse_error(s: &str) {
        match parse_transform(s) {
            Err(AttributeError::Parse(_)) => {}
            _ => {
                panic!();
            }
        }
    }

    #[test]
    fn syntax_error_yields_parse_error() {
        assert_parse_error("foo");
        assert_parse_error("matrix (1 2 3 4 5)");
        assert_parse_error("translate(1 2 3 4 5)");
        assert_parse_error("translate (1,)");
        assert_parse_error("scale (1,)");
        assert_parse_error("skewX (1,2)");
        assert_parse_error("skewY ()");
        assert_parse_error("skewY");
    }

    #[test]
    fn invalid_transform_yields_value_error() {
        match parse_transform("matrix (0 0 0 0 0 0)") {
            Err(AttributeError::Value(_)) => {}
            _ => {
                panic!();
            }
        }

        match parse_transform("scale (0), translate (10, 10)") {
            Err(AttributeError::Value(_)) => {}
            _ => {
                panic!();
            }
        }

        match parse_transform("scale (0), skewX (90)") {
            Err(AttributeError::Value(_)) => {}
            _ => {
                panic!();
            }
        }
    }
}

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

    #[test]
    fn parses_matrix() {
        assert_eq!(
            parse_transform("matrix (1 2 3 4 5 6)").unwrap(),
            cairo::Matrix::new(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)
        );

        assert_eq!(
            parse_transform("matrix(1,2,3,4 5 6)").unwrap(),
            cairo::Matrix::new(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)
        );

        assert_eq!(
            parse_transform("matrix (1,2.25,-3.25e2,4 5 6)").unwrap(),
            cairo::Matrix::new(1.0, 2.25, -325.0, 4.0, 5.0, 6.0)
        );
    }

    #[test]
    fn parses_translate() {
        assert_eq!(
            parse_transform("translate(-1 -2)").unwrap(),
            cairo::Matrix::new(1.0, 0.0, 0.0, 1.0, -1.0, -2.0)
        );

        assert_eq!(
            parse_transform("translate(-1, -2)").unwrap(),
            cairo::Matrix::new(1.0, 0.0, 0.0, 1.0, -1.0, -2.0)
        );

        assert_eq!(
            parse_transform("translate(-1)").unwrap(),
            cairo::Matrix::new(1.0, 0.0, 0.0, 1.0, -1.0, 0.0)
        );
    }

    #[test]
    fn parses_scale() {
        assert_eq!(
            parse_transform("scale (-1)").unwrap(),
            cairo::Matrix::new(-1.0, 0.0, 0.0, -1.0, 0.0, 0.0)
        );

        assert_eq!(
            parse_transform("scale(-1 -2)").unwrap(),
            cairo::Matrix::new(-1.0, 0.0, 0.0, -2.0, 0.0, 0.0)
        );

        assert_eq!(
            parse_transform("scale(-1, -2)").unwrap(),
            cairo::Matrix::new(-1.0, 0.0, 0.0, -2.0, 0.0, 0.0)
        );
    }

    #[test]
    fn parses_rotate() {
        assert_eq!(
            parse_transform("rotate (30)").unwrap(),
            make_rotation_matrix(30.0, 0.0, 0.0)
        );
        assert_eq!(
            parse_transform("rotate (30,-1,-2)").unwrap(),
            make_rotation_matrix(30.0, -1.0, -2.0)
        );
        assert_eq!(
            parse_transform("rotate(30, -1, -2)").unwrap(),
            make_rotation_matrix(30.0, -1.0, -2.0)
        );
    }

    fn make_skew_x_matrix(angle_degrees: f64) -> cairo::Matrix {
        let a = angle_degrees * PI / 180.0;
        cairo::Matrix::new(1.0, 0.0, a.tan(), 1.0, 0.0, 0.0)
    }

    fn make_skew_y_matrix(angle_degrees: f64) -> cairo::Matrix {
        let mut m = make_skew_x_matrix(angle_degrees);
        m.yx = m.xy;
        m.xy = 0.0;
        m
    }

    #[test]
    fn parses_skew_x() {
        assert_eq!(
            parse_transform("skewX (30)").unwrap(),
            make_skew_x_matrix(30.0)
        );
    }

    #[test]
    fn parses_skew_y() {
        assert_eq!(
            parse_transform("skewY (30)").unwrap(),
            make_skew_y_matrix(30.0)
        );
    }

    #[test]
    fn parses_transform_list() {
        let t = cairo::Matrix::new(1.0, 0.0, 0.0, 1.0, 20.0, 30.0);
        let s = cairo::Matrix::new(10.0, 0.0, 0.0, 10.0, 0.0, 0.0);
        let r = make_rotation_matrix(30.0, 10.0, 10.0);

        assert_eq!(
            parse_transform("scale(10)rotate(30, 10, 10)").unwrap(),
            cairo::Matrix::multiply(&r, &s)
        );

        assert_eq!(
            parse_transform("translate(20, 30), scale (10)").unwrap(),
            cairo::Matrix::multiply(&s, &t)
        );

        let a = cairo::Matrix::multiply(&s, &t);
        assert_eq!(
            parse_transform("translate(20, 30), scale (10) rotate (30 10 10)").unwrap(),
            cairo::Matrix::multiply(&r, &a)
        );
    }
}
<commit_msg>yield the identity transform for empty transform attribute<commit_after>use cairo;
use glib::translate::*;
use glib_sys;
use libc;

use std::f64::consts::*;

use cairo::MatrixTrait;
use cssparser::{ParseError as CssParseError, Parser, ParserInput, Token};

use error::*;
use parsers::{optional_comma, Parse, ParseError};
use util::utf8_cstr;

impl Parse for cairo::Matrix {
    type Data = ();
    type Err = AttributeError;

    fn parse(s: &str, _: ()) -> Result<cairo::Matrix, AttributeError> {
        parse_transform(s)
    }
}

// This parser is for the "transform" attribute in SVG.
// Its operataion and grammar are described here:
// https://www.w3.org/TR/SVG/coords.html#TransformAttribute

pub fn parse_transform(s: &str) -> Result<cairo::Matrix, AttributeError> {
    let matrix = parse_transform_list(s)?;

    matrix
        .try_invert()
        .map(|_| matrix)
        .map_err(|_| AttributeError::Value("invalid transformation matrix".to_string()))
}

fn parse_transform_list(s: &str) -> Result<cairo::Matrix, AttributeError> {
    let mut input = ParserInput::new(s);
    let mut parser = Parser::new(&mut input);

    let mut matrix = cairo::Matrix::identity();

    loop {
        if parser.is_exhausted() {
            break;
        }

        let m = parse_transform_command(&mut parser)?;
        matrix = cairo::Matrix::multiply(&m, &matrix);

        optional_comma(&mut parser);
    }

    Ok(matrix)
}

fn make_expected_function_error() -> AttributeError {
    AttributeError::from(ParseError::new(
        "expected matrix|translate|scale|rotate|skewX|skewY",
    ))
}

fn parse_transform_command(parser: &mut Parser) -> Result<cairo::Matrix, AttributeError> {
    match parser.next()?.clone() {
        Token::Function(ref name) => parse_transform_function(name, parser),

        Token::Ident(ref name) => {
            parser.expect_parenthesis_block()?;
            parse_transform_function(name, parser)
        }

        _ => Err(make_expected_function_error()),
    }
}

fn parse_transform_function(
    name: &str,
    parser: &mut Parser,
) -> Result<cairo::Matrix, AttributeError> {
    match name {
        "matrix" => parse_matrix_args(parser),
        "translate" => parse_translate_args(parser),
        "scale" => parse_scale_args(parser),
        "rotate" => parse_rotate_args(parser),
        "skewX" => parse_skewx_args(parser),
        "skewY" => parse_skewy_args(parser),
        _ => Err(make_expected_function_error()),
    }
}

fn parse_matrix_args(parser: &mut Parser) -> Result<cairo::Matrix, AttributeError> {
    parser
        .parse_nested_block(|p| {
            let xx = f64::from(p.expect_number()?);
            optional_comma(p);

            let yx = f64::from(p.expect_number()?);
            optional_comma(p);

            let xy = f64::from(p.expect_number()?);
            optional_comma(p);

            let yy = f64::from(p.expect_number()?);
            optional_comma(p);

            let x0 = f64::from(p.expect_number()?);
            optional_comma(p);

            let y0 = f64::from(p.expect_number()?);

            Ok(cairo::Matrix::new(xx, yx, xy, yy, x0, y0))
        })
        .map_err(CssParseError::<()>::basic)
        .map_err(AttributeError::from)
}

fn parse_translate_args(parser: &mut Parser) -> Result<cairo::Matrix, AttributeError> {
    parser
        .parse_nested_block(|p| {
            let tx = f64::from(p.expect_number()?);

            let ty = f64::from(p.try(|p| -> Result<f32, CssParseError<()>> {
                optional_comma(p);
                Ok(p.expect_number()?)
            }).unwrap_or(0.0));

            Ok(cairo::Matrix::new(1.0, 0.0, 0.0, 1.0, tx, ty))
        })
        .map_err(CssParseError::<()>::basic)
        .map_err(AttributeError::from)
}

fn parse_scale_args(parser: &mut Parser) -> Result<cairo::Matrix, AttributeError> {
    parser
        .parse_nested_block(|p| {
            let x = f64::from(p.expect_number()?);

            let y = p.try(|p| -> Result<f32, CssParseError<()>> {
                optional_comma(p);
                Ok(p.expect_number()?)
            }).map(f64::from)
                .unwrap_or(x);

            Ok(cairo::Matrix::new(x, 0.0, 0.0, y, 0.0, 0.0))
        })
        .map_err(CssParseError::<()>::basic)
        .map_err(AttributeError::from)
}

fn parse_rotate_args(parser: &mut Parser) -> Result<cairo::Matrix, AttributeError> {
    parser
        .parse_nested_block(|p| {
            let angle = f64::from(p.expect_number()?) * PI / 180.0;
            let (s, c) = angle.sin_cos();

            let (tx, ty) = p.try(|p| -> Result<_, CssParseError<()>> {
                optional_comma(p);
                let tx = f64::from(p.expect_number()?);

                optional_comma(p);
                let ty = f64::from(p.expect_number()?);

                Ok((tx, ty))
            }).unwrap_or((0.0, 0.0));

            let mut m = cairo::Matrix::new(1.0, 0.0, 0.0, 1.0, tx, ty);

            m = cairo::Matrix::multiply(&cairo::Matrix::new(c, s, -s, c, 0.0, 0.0), &m);
            m = cairo::Matrix::multiply(&cairo::Matrix::new(1.0, 0.0, 0.0, 1.0, -tx, -ty), &m);
            Ok(m)
        })
        .map_err(CssParseError::<()>::basic)
        .map_err(AttributeError::from)
}

fn parse_skewx_args(parser: &mut Parser) -> Result<cairo::Matrix, AttributeError> {
    parser
        .parse_nested_block(|p| {
            let a = f64::from(p.expect_number()?) * PI / 180.0;
            Ok(cairo::Matrix::new(1.0, 0.0, a.tan(), 1.0, 0.0, 0.0))
        })
        .map_err(CssParseError::<()>::basic)
        .map_err(AttributeError::from)
}

fn parse_skewy_args(parser: &mut Parser) -> Result<cairo::Matrix, AttributeError> {
    parser
        .parse_nested_block(|p| {
            let a = f64::from(p.expect_number()?) * PI / 180.0;
            Ok(cairo::Matrix::new(1.0, a.tan(), 0.0, 1.0, 0.0, 0.0))
        })
        .map_err(CssParseError::<()>::basic)
        .map_err(AttributeError::from)
}

#[cfg(test)]
fn make_rotation_matrix(angle_degrees: f64, tx: f64, ty: f64) -> cairo::Matrix {
    let angle = angle_degrees * PI / 180.0;

    let mut m = cairo::Matrix::new(1.0, 0.0, 0.0, 1.0, tx, ty);

    let mut r = cairo::Matrix::identity();
    r.rotate(angle);
    m = cairo::Matrix::multiply(&r, &m);

    m = cairo::Matrix::multiply(&cairo::Matrix::new(1.0, 0.0, 0.0, 1.0, -tx, -ty), &m);
    m
}

#[no_mangle]
pub extern "C" fn rsvg_parse_transform(
    out_matrix: *mut cairo::Matrix,
    s: *const libc::c_char,
) -> glib_sys::gboolean {
    assert!(!out_matrix.is_null());
    assert!(!s.is_null());

    let string = unsafe { utf8_cstr(s) };
    let matrix: &mut cairo::Matrix = unsafe { &mut *out_matrix };

    match parse_transform(string) {
        Ok(m) => {
            *matrix = m;
            true.to_glib()
        }

        Err(_) => {
            *matrix = cairo::Matrix::identity();
            false.to_glib()
        }
    }
}

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

    #[test]
    fn parses_valid_transform() {
        let t = cairo::Matrix::new(1.0, 0.0, 0.0, 1.0, 20.0, 30.0);
        let s = cairo::Matrix::new(10.0, 0.0, 0.0, 10.0, 0.0, 0.0);
        let r = make_rotation_matrix(30.0, 10.0, 10.0);

        let a = cairo::Matrix::multiply(&s, &t);
        assert_eq!(
            parse_transform("translate(20, 30), scale (10) rotate (30 10 10)").unwrap(),
            cairo::Matrix::multiply(&r, &a)
        );
    }

    fn assert_parse_error(s: &str) {
        match parse_transform(s) {
            Err(AttributeError::Parse(_)) => {}
            _ => {
                panic!();
            }
        }
    }

    #[test]
    fn syntax_error_yields_parse_error() {
        assert_parse_error("foo");
        assert_parse_error("matrix (1 2 3 4 5)");
        assert_parse_error("translate(1 2 3 4 5)");
        assert_parse_error("translate (1,)");
        assert_parse_error("scale (1,)");
        assert_parse_error("skewX (1,2)");
        assert_parse_error("skewY ()");
        assert_parse_error("skewY");
    }

    #[test]
    fn invalid_transform_yields_value_error() {
        match parse_transform("matrix (0 0 0 0 0 0)") {
            Err(AttributeError::Value(_)) => {}
            _ => {
                panic!();
            }
        }

        match parse_transform("scale (0), translate (10, 10)") {
            Err(AttributeError::Value(_)) => {}
            _ => {
                panic!();
            }
        }

        match parse_transform("scale (0), skewX (90)") {
            Err(AttributeError::Value(_)) => {}
            _ => {
                panic!();
            }
        }
    }
}

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

    #[test]
    fn parses_matrix() {
        assert_eq!(
            parse_transform("matrix (1 2 3 4 5 6)").unwrap(),
            cairo::Matrix::new(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)
        );

        assert_eq!(
            parse_transform("matrix(1,2,3,4 5 6)").unwrap(),
            cairo::Matrix::new(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)
        );

        assert_eq!(
            parse_transform("matrix (1,2.25,-3.25e2,4 5 6)").unwrap(),
            cairo::Matrix::new(1.0, 2.25, -325.0, 4.0, 5.0, 6.0)
        );
    }

    #[test]
    fn parses_translate() {
        assert_eq!(
            parse_transform("translate(-1 -2)").unwrap(),
            cairo::Matrix::new(1.0, 0.0, 0.0, 1.0, -1.0, -2.0)
        );

        assert_eq!(
            parse_transform("translate(-1, -2)").unwrap(),
            cairo::Matrix::new(1.0, 0.0, 0.0, 1.0, -1.0, -2.0)
        );

        assert_eq!(
            parse_transform("translate(-1)").unwrap(),
            cairo::Matrix::new(1.0, 0.0, 0.0, 1.0, -1.0, 0.0)
        );
    }

    #[test]
    fn parses_scale() {
        assert_eq!(
            parse_transform("scale (-1)").unwrap(),
            cairo::Matrix::new(-1.0, 0.0, 0.0, -1.0, 0.0, 0.0)
        );

        assert_eq!(
            parse_transform("scale(-1 -2)").unwrap(),
            cairo::Matrix::new(-1.0, 0.0, 0.0, -2.0, 0.0, 0.0)
        );

        assert_eq!(
            parse_transform("scale(-1, -2)").unwrap(),
            cairo::Matrix::new(-1.0, 0.0, 0.0, -2.0, 0.0, 0.0)
        );
    }

    #[test]
    fn parses_rotate() {
        assert_eq!(
            parse_transform("rotate (30)").unwrap(),
            make_rotation_matrix(30.0, 0.0, 0.0)
        );
        assert_eq!(
            parse_transform("rotate (30,-1,-2)").unwrap(),
            make_rotation_matrix(30.0, -1.0, -2.0)
        );
        assert_eq!(
            parse_transform("rotate(30, -1, -2)").unwrap(),
            make_rotation_matrix(30.0, -1.0, -2.0)
        );
    }

    fn make_skew_x_matrix(angle_degrees: f64) -> cairo::Matrix {
        let a = angle_degrees * PI / 180.0;
        cairo::Matrix::new(1.0, 0.0, a.tan(), 1.0, 0.0, 0.0)
    }

    fn make_skew_y_matrix(angle_degrees: f64) -> cairo::Matrix {
        let mut m = make_skew_x_matrix(angle_degrees);
        m.yx = m.xy;
        m.xy = 0.0;
        m
    }

    #[test]
    fn parses_skew_x() {
        assert_eq!(
            parse_transform("skewX (30)").unwrap(),
            make_skew_x_matrix(30.0)
        );
    }

    #[test]
    fn parses_skew_y() {
        assert_eq!(
            parse_transform("skewY (30)").unwrap(),
            make_skew_y_matrix(30.0)
        );
    }

    #[test]
    fn parses_transform_list() {
        let t = cairo::Matrix::new(1.0, 0.0, 0.0, 1.0, 20.0, 30.0);
        let s = cairo::Matrix::new(10.0, 0.0, 0.0, 10.0, 0.0, 0.0);
        let r = make_rotation_matrix(30.0, 10.0, 10.0);

        assert_eq!(
            parse_transform("scale(10)rotate(30, 10, 10)").unwrap(),
            cairo::Matrix::multiply(&r, &s)
        );

        assert_eq!(
            parse_transform("translate(20, 30), scale (10)").unwrap(),
            cairo::Matrix::multiply(&s, &t)
        );

        let a = cairo::Matrix::multiply(&s, &t);
        assert_eq!(
            parse_transform("translate(20, 30), scale (10) rotate (30 10 10)").unwrap(),
            cairo::Matrix::multiply(&r, &a)
        );
    }

    #[test]
    fn parses_empty() {
        assert_eq!(parse_transform("").unwrap(), cairo::Matrix::identity());
    }
}
<|endoftext|>


<commit_before>//! Common types for the [`m.room.power_levels` event][power_levels]
//!
//! [power_levels]: https://matrix.org/docs/spec/client_server/r0.6.1#m-room-power-levels

use js_int::Int;
use serde::{Deserialize, Serialize};

/// The power level requirements for specific notification types.
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub struct NotificationPowerLevels {
    /// The level required to trigger an `@room` notification.
    #[cfg_attr(feature = "compat", serde(deserialize_with = "ruma_serde::int_or_string_to_int"))]
    #[serde(default = "default_power_level")]
    pub room: Int,
}

impl NotificationPowerLevels {
    /// Value associated with the given `key`.
    pub fn get(&self, key: &str) -> Option<&Int> {
        match key {
            "room" => Some(&self.room),
            _ => None,
        }
    }
}

impl Default for NotificationPowerLevels {
    fn default() -> Self {
        Self { room: default_power_level() }
    }
}

/// Used to default power levels to 50 during deserialization.
pub fn default_power_level() -> Int {
    Int::from(50)
}
<commit_msg>common: Make NotificationPowerLevels non-exhaustive<commit_after>//! Common types for the [`m.room.power_levels` event][power_levels]
//!
//! [power_levels]: https://matrix.org/docs/spec/client_server/r0.6.1#m-room-power-levels

use js_int::Int;
use serde::{Deserialize, Serialize};

/// The power level requirements for specific notification types.
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct NotificationPowerLevels {
    /// The level required to trigger an `@room` notification.
    #[cfg_attr(feature = "compat", serde(deserialize_with = "ruma_serde::int_or_string_to_int"))]
    #[serde(default = "default_power_level")]
    pub room: Int,
}

impl NotificationPowerLevels {
    /// Create a new `NotificationPowerLevels` with all-default values.
    pub fn new() -> Self {
        Self { room: default_power_level() }
    }

    /// Value associated with the given `key`.
    pub fn get(&self, key: &str) -> Option<&Int> {
        match key {
            "room" => Some(&self.room),
            _ => None,
        }
    }
}

impl Default for NotificationPowerLevels {
    fn default() -> Self {
        Self::new()
    }
}

/// Used to default power levels to 50 during deserialization.
pub fn default_power_level() -> Int {
    Int::from(50)
}
<|endoftext|>


<commit_before>// #![ feature( pattern ) ]

use test_tools::*;
use wtools::*;
use wcensor as TheModule;

// use wtools::former::Former;

//

fn vec_as_ref< T >( src : &Vec< T > ) -> Vec< &str >
where
  T : AsRef< str >,
{
  src.iter().map( | e | e.as_ref() ).collect::< Vec< &str > >()
}

//

fn instruction_parse_from_splits_basic_test()
{

  // test.case( "command and several subjects" );
  let args = vec![ ".struct1", "subject1", "subject2" ];
  let instruction = TheModule::instruction::parse_from_splits( args.iter() );
  assert_eq!( instruction.command_name.as_ref(), ".struct1" );
  assert_eq!( vec_as_ref( &instruction.subject ), vec![ "subject1", "subject2" ] );
  assert_eq!( instruction.properties_map, hmap!{} );

  // // test.case( "basic comand, subject map" );
  // let args = vec![ ".struct1", "subject1", "k1:v1" ];
  // let instruction = TheModule::instruction::parse_from_splits( args.iter() );
  // assert_eq!( instruction.command_name.as_ref(), ".struct1" );
  // assert_eq!( vec_as_ref( &instruction.subject ), vec![ "subject1" ] );
  // assert_eq!( instruction.properties_map, hmap!{} );

}

//

// fn _string_split()
// {
//
//   // test.case( "basic" );
//   // let src = "ab ef";
//   // let iter = TheModule::string::split_default( src );
//   // assert_eq!( iter.map( | e | String::from( e ) ).collect::< Vec< _ > >(), vec![ "ab", " ", "ef" ] );
//
//   // test.case( "delimeter : "x" );
//   let src = "ab ef";
//   // let iter = TheModule::string::split().delimeter( "b" ).src( src ).form();
//   let iter = TheModule::string::split().delimeter( "b" ).src( src ).form();
//   assert_eq!( iter.map( | e | String::from( e ) ).collect::< Vec< _ > >(), vec![ "a", "b", " ef" ] );
//
// }

//

test_suite!
{
  instruction_parse_from_splits_basic,
  // string_split,
}
<commit_msg>Update tests of module `wcensor`, use new test macroses<commit_after>use test_tools::*;
use wtools::*;
use wcensor as TheModule;

//

fn vec_as_ref< T >( src : &Vec< T > ) -> Vec< &str >
where
  T : AsRef< str >,
{
  src.iter().map( | e | e.as_ref() ).collect::< Vec< &str > >()
}

tests_impls!
{
  #[ test ]
  fn instruction_parse_from_splits_basic()
  {
    // test.case( "command and several subjects" );
    let args = vec![ ".struct1", "subject1", "subject2" ];
    let instruction = TheModule::instruction::parse_from_splits( args.iter() );
    assert_eq!( instruction.command_name.as_ref(), ".struct1" );
    assert_eq!( vec_as_ref( &instruction.subject ), vec![ "subject1", "subject2" ] );
    assert_eq!( instruction.properties_map, hmap!{} );

    // // test.case( "basic comand, subject map" );
    // let args = vec![ ".struct1", "subject1", "k1:v1" ];
    // let instruction = TheModule::instruction::parse_from_splits( args.iter() );
    // assert_eq!( instruction.command_name.as_ref(), ".struct1" );
    // assert_eq!( vec_as_ref( &instruction.subject ), vec![ "subject1" ] );
    // assert_eq!( instruction.properties_map, hmap!{} );
  }

  //

  // fn _string_split()
  // {
  //
  //   // test.case( "basic" );
  //   // let src = "ab ef";
  //   // let iter = TheModule::string::split_default( src );
  //   // assert_eq!( iter.map( | e | String::from( e ) ).collect::< Vec< _ > >(), vec![ "ab", " ", "ef" ] );
  //
  //   // test.case( "delimeter : "x" );
  //   let src = "ab ef";
  //   // let iter = TheModule::string::split().delimeter( "b" ).src( src ).form();
  //   let iter = TheModule::string::split().delimeter( "b" ).src( src ).form();
  //   assert_eq!( iter.map( | e | String::from( e ) ).collect::< Vec< _ > >(), vec![ "a", "b", " ef" ] );
  //
  // }
}

//

tests_index!
{
  instruction_parse_from_splits_basic,
  // string_split,
}
<|endoftext|>


<commit_before>use deelevate;<commit_msg>Codemod away ::{self}; (#71)<commit_after><|endoftext|>