<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::{
    config::Config,
    config::{OperationPersister, PersistConfig},
    errors::BuildProjectError,
    Artifact, ArtifactContent,
};
use common::PerfLogEvent;
use lazy_static::lazy_static;
use log::debug;
use md5::{Digest, Md5};
use regex::Regex;
use std::{fs, path::PathBuf};

lazy_static! {
    static ref RELAY_HASH_REGEX: Regex = Regex::new(r#"@relayHash (\w{32})\n"#).unwrap();
    static ref REQUEST_ID_REGEX: Regex = Regex::new(r#"@relayRequestID (\w+)\n"#).unwrap();
}

pub async fn persist_operations(
    artifacts: &mut [Artifact],
    root_dir: &PathBuf,
    persist_config: &PersistConfig,
    config: &Config,
    operation_persister: &Box<dyn OperationPersister + Send + Sync>,
    log_event: &impl PerfLogEvent,
) -> Result<(), BuildProjectError> {
    let handles = artifacts
        .iter_mut()
        .flat_map(|artifact| {
            if let ArtifactContent::Operation {
                ref text,
                ref mut id_and_text_hash,
                ..
            } = artifact.content
            {
                let text_hash = md5(text);
                let artifact_path = root_dir.join(&artifact.path);
                let extracted_persist_id = if config.repersist_operations {
                    None
                } else {
                    extract_persist_id(&artifact_path, &text_hash)
                };
                if let Some(id) = extracted_persist_id {
                    *id_and_text_hash = Some((id, text_hash));
                    None
                } else {
                    let text = text.clone();
                    Some(async move {
                        operation_persister
                            .persist_artifact(text, persist_config)
                            .await
                            .map(|id| {
                                *id_and_text_hash = Some((id, text_hash));
                            })
                    })
                }
            } else {
                None
            }
        })
        .collect::<Vec<_>>();
    log_event.number("persist_documents", handles.len());
    log_event.number("worker_count", operation_persister.worker_count());
    let results = futures::future::join_all(handles).await;
    debug!("done persisting");
    let errors = results
        .into_iter()
        .filter_map(Result::err)
        .collect::<Vec<_>>();
    if !errors.is_empty() {
        return Err(BuildProjectError::PersistErrors { errors });
    }
    Ok(())
}

fn extract_persist_id(path: &PathBuf, text_hash: &str) -> Option<String> {
    let content = fs::read_to_string(path).ok()?;

    // Looks like a merge conflict, let's not trust this file.
    if content.contains("<<<<") || content.contains(">>>>") {
        return None;
    }

    // If the existing hash doesn't match the hash of the new query test, abort.
    if let Some(existing_hash) = extract_relay_hash(&content) {
        if existing_hash != text_hash {
            return None;
        }
    }

    extract_request_id(&content)
}

fn extract_relay_hash(content: &str) -> Option<&str> {
    RELAY_HASH_REGEX
        .captures(content)
        .and_then(|captures| captures.get(1).map(|m| m.as_str()))
}

fn extract_request_id(content: &str) -> Option<String> {
    REQUEST_ID_REGEX
        .captures(content)
        .map(|captures| captures[1].to_owned())
}

fn md5(data: &str) -> String {
    let mut md5 = Md5::new();
    md5.input(data);
    hex::encode(md5.result())
}
<commit_msg>Fix extracting persisting query id<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::{
    config::Config,
    config::{OperationPersister, PersistConfig},
    errors::BuildProjectError,
    Artifact, ArtifactContent,
};
use common::PerfLogEvent;
use lazy_static::lazy_static;
use log::debug;
use md5::{Digest, Md5};
use regex::Regex;
use std::{fs, path::PathBuf};

lazy_static! {
    static ref RELAY_HASH_REGEX: Regex = Regex::new(r#"@relayHash (\w{32})\n"#).unwrap();
    static ref REQUEST_ID_REGEX: Regex = Regex::new(r#"@relayRequestID (.+)\n"#).unwrap();
}

pub async fn persist_operations(
    artifacts: &mut [Artifact],
    root_dir: &PathBuf,
    persist_config: &PersistConfig,
    config: &Config,
    operation_persister: &Box<dyn OperationPersister + Send + Sync>,
    log_event: &impl PerfLogEvent,
) -> Result<(), BuildProjectError> {
    let handles = artifacts
        .iter_mut()
        .flat_map(|artifact| {
            if let ArtifactContent::Operation {
                ref text,
                ref mut id_and_text_hash,
                ..
            } = artifact.content
            {
                let text_hash = md5(text);
                let artifact_path = root_dir.join(&artifact.path);
                let extracted_persist_id = if config.repersist_operations {
                    None
                } else {
                    extract_persist_id(&artifact_path, &text_hash)
                };
                if let Some(id) = extracted_persist_id {
                    *id_and_text_hash = Some((id, text_hash));
                    None
                } else {
                    let text = text.clone();
                    Some(async move {
                        operation_persister
                            .persist_artifact(text, persist_config)
                            .await
                            .map(|id| {
                                *id_and_text_hash = Some((id, text_hash));
                            })
                    })
                }
            } else {
                None
            }
        })
        .collect::<Vec<_>>();
    log_event.number("persist_documents", handles.len());
    log_event.number("worker_count", operation_persister.worker_count());
    let results = futures::future::join_all(handles).await;
    debug!("done persisting");
    let errors = results
        .into_iter()
        .filter_map(Result::err)
        .collect::<Vec<_>>();
    if !errors.is_empty() {
        return Err(BuildProjectError::PersistErrors { errors });
    }
    Ok(())
}

fn extract_persist_id(path: &PathBuf, text_hash: &str) -> Option<String> {
    let content = fs::read_to_string(path).ok()?;

    // Looks like a merge conflict, let's not trust this file.
    if content.contains("<<<<") || content.contains(">>>>") {
        return None;
    }

    // If the existing hash doesn't match the hash of the new query test, abort.
    if let Some(existing_hash) = extract_relay_hash(&content) {
        if existing_hash != text_hash {
            return None;
        }
    }

    extract_request_id(&content)
}

fn extract_relay_hash(content: &str) -> Option<&str> {
    RELAY_HASH_REGEX
        .captures(content)
        .and_then(|captures| captures.get(1).map(|m| m.as_str()))
}

fn extract_request_id(content: &str) -> Option<String> {
    REQUEST_ID_REGEX
        .captures(content)
        .map(|captures| captures[1].to_owned())
}

fn md5(data: &str) -> String {
    let mut md5 = Md5::new();
    md5.input(data);
    hex::encode(md5.result())
}
<|endoftext|>


<commit_before>use {
    AddColor,
    Borrowed,
    Field,
    Matrix2d,
    Rectangle,
    RoundRectangleColorContext,
    Value,
    View,
};
use vecmath::{
    identity,
};
use internal::{
    CanRectangle,
    CanTransform,
    HasRectangle,
    HasTransform,
};

/// A round rectangle context.
pub struct RoundRectangleContext<'a> {
    /// Base/origin transform.
    pub base: Field<'a, Matrix2d>,
    /// Current transform.
    pub transform: Field<'a, Matrix2d>,
    /// Current rectangle.
    pub rect: Field<'a, Rectangle>,
    /// Current roundnes radius.
    pub round_radius: Field<'a, f64>,
}

impl<'a> HasTransform<'a, Matrix2d> for RoundRectangleContext<'a> {
    #[inline(always)]
    fn get_transform(&'a self) -> &'a Matrix2d {
        self.transform.get()
    }
}

impl<'a> CanTransform<'a, RoundRectangleContext<'a>, Matrix2d> for RoundRectangleContext<'a> {
    #[inline(always)]
    fn transform(&'a self, value: Matrix2d) -> RoundRectangleContext<'a> {
        RoundRectangleContext {
            base: Borrowed(self.base.get()),
            transform: Value(value),
            rect: Borrowed(self.rect.get()),
            round_radius: Borrowed(self.round_radius.get()),
        }
    }
}

impl<'a> HasRectangle<'a, Rectangle> for RoundRectangleContext<'a> {
    #[inline(always)]
    fn get_rectangle(&'a self) -> &'a Rectangle {
        self.rect.get()
    }
}

impl<'a> CanRectangle<'a, RoundRectangleContext<'a>, Rectangle> for RoundRectangleContext<'a> {
    #[inline(always)]
    fn rectangle(&'a self, rect: Rectangle) -> RoundRectangleContext<'a> {
        RoundRectangleContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            rect: Value(rect),
            round_radius: Borrowed(self.round_radius.get()),
        }
    }
}

impl<'a> AddColor<'a, RoundRectangleColorContext<'a>> for RoundRectangleContext<'a> {
    /// Creates a RectangleColorContext.
    #[inline(always)]
    fn rgba(&'a self, r: f32, g: f32, b: f32, a: f32) -> RoundRectangleColorContext<'a> {
        RoundRectangleColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            color: Value([r, g, b, a]),
            rect: Borrowed(self.rect.get()),
            round_radius: Borrowed(self.round_radius.get()),
        }
    }
}

impl<'a> View<'a> for RoundRectangleContext<'a> {
    #[inline(always)]
    fn view(&'a self) -> RoundRectangleContext<'a> {
        RoundRectangleContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.base.get()),
            rect: Borrowed(self.rect.get()),
            round_radius: Borrowed(self.round_radius.get()),
        }
    }

    #[inline(always)]
    fn reset(&'a self) -> RoundRectangleContext<'a> {
        RoundRectangleContext {
            base: Borrowed(self.base.get()),
            transform: Value(identity()),
            rect: Borrowed(self.rect.get()),
            round_radius: Borrowed(self.round_radius.get()),
        }
    }

    #[inline(always)]
    fn store_view(&'a self) -> RoundRectangleContext<'a> {
        RoundRectangleContext {
            base: Borrowed(self.transform.get()),
            transform: Borrowed(self.transform.get()),
            rect: Borrowed(self.rect.get()),
            round_radius: Borrowed(self.round_radius.get()),
        }
    }
}

<commit_msg>Fixed comment for `round_radius` in `RoundRectangleContext`<commit_after>use {
    AddColor,
    Borrowed,
    Field,
    Matrix2d,
    Rectangle,
    RoundRectangleColorContext,
    Value,
    View,
};
use vecmath::{
    identity,
};
use internal::{
    CanRectangle,
    CanTransform,
    HasRectangle,
    HasTransform,
};

/// A round rectangle context.
pub struct RoundRectangleContext<'a> {
    /// Base/origin transform.
    pub base: Field<'a, Matrix2d>,
    /// Current transform.
    pub transform: Field<'a, Matrix2d>,
    /// Current rectangle.
    pub rect: Field<'a, Rectangle>,
    /// Current roundness radius.
    pub round_radius: Field<'a, f64>,
}

impl<'a> HasTransform<'a, Matrix2d> for RoundRectangleContext<'a> {
    #[inline(always)]
    fn get_transform(&'a self) -> &'a Matrix2d {
        self.transform.get()
    }
}

impl<'a> CanTransform<'a, RoundRectangleContext<'a>, Matrix2d> for RoundRectangleContext<'a> {
    #[inline(always)]
    fn transform(&'a self, value: Matrix2d) -> RoundRectangleContext<'a> {
        RoundRectangleContext {
            base: Borrowed(self.base.get()),
            transform: Value(value),
            rect: Borrowed(self.rect.get()),
            round_radius: Borrowed(self.round_radius.get()),
        }
    }
}

impl<'a> HasRectangle<'a, Rectangle> for RoundRectangleContext<'a> {
    #[inline(always)]
    fn get_rectangle(&'a self) -> &'a Rectangle {
        self.rect.get()
    }
}

impl<'a> CanRectangle<'a, RoundRectangleContext<'a>, Rectangle> for RoundRectangleContext<'a> {
    #[inline(always)]
    fn rectangle(&'a self, rect: Rectangle) -> RoundRectangleContext<'a> {
        RoundRectangleContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            rect: Value(rect),
            round_radius: Borrowed(self.round_radius.get()),
        }
    }
}

impl<'a> AddColor<'a, RoundRectangleColorContext<'a>> for RoundRectangleContext<'a> {
    /// Creates a RectangleColorContext.
    #[inline(always)]
    fn rgba(&'a self, r: f32, g: f32, b: f32, a: f32) -> RoundRectangleColorContext<'a> {
        RoundRectangleColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            color: Value([r, g, b, a]),
            rect: Borrowed(self.rect.get()),
            round_radius: Borrowed(self.round_radius.get()),
        }
    }
}

impl<'a> View<'a> for RoundRectangleContext<'a> {
    #[inline(always)]
    fn view(&'a self) -> RoundRectangleContext<'a> {
        RoundRectangleContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.base.get()),
            rect: Borrowed(self.rect.get()),
            round_radius: Borrowed(self.round_radius.get()),
        }
    }

    #[inline(always)]
    fn reset(&'a self) -> RoundRectangleContext<'a> {
        RoundRectangleContext {
            base: Borrowed(self.base.get()),
            transform: Value(identity()),
            rect: Borrowed(self.rect.get()),
            round_radius: Borrowed(self.round_radius.get()),
        }
    }

    #[inline(always)]
    fn store_view(&'a self) -> RoundRectangleContext<'a> {
        RoundRectangleContext {
            base: Borrowed(self.transform.get()),
            transform: Borrowed(self.transform.get()),
            rect: Borrowed(self.rect.get()),
            round_radius: Borrowed(self.round_radius.get()),
        }
    }
}

<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::account_config::constants::CORE_CODE_ADDRESS;
use move_core_types::{
    identifier::{IdentStr, Identifier},
    language_storage::{ModuleId, StructTag},
};
use once_cell::sync::Lazy;

pub const ACCOUNT_MODULE_NAME: &str = "LibraAccount";

// Account
static ACCOUNT_MODULE_IDENTIFIER: Lazy<Identifier> =
    Lazy::new(|| Identifier::new("LibraAccount").unwrap());
static ACCOUNT_STRUCT_NAME: Lazy<Identifier> = Lazy::new(|| Identifier::new("T").unwrap());

/// The ModuleId for the Account module.
pub static ACCOUNT_MODULE: Lazy<ModuleId> =
    Lazy::new(|| ModuleId::new(CORE_CODE_ADDRESS, ACCOUNT_MODULE_IDENTIFIER.clone()));

// Payment Events
static SENT_EVENT_NAME: Lazy<Identifier> =
    Lazy::new(|| Identifier::new("SentPaymentEvent").unwrap());
static RECEIVED_EVENT_NAME: Lazy<Identifier> =
    Lazy::new(|| Identifier::new("ReceivedPaymentEvent").unwrap());

pub fn sent_event_name() -> &'static IdentStr {
    &*SENT_EVENT_NAME
}

pub fn received_event_name() -> &'static IdentStr {
    &*RECEIVED_EVENT_NAME
}

pub fn account_struct_tag() -> StructTag {
    StructTag {
        address: CORE_CODE_ADDRESS,
        module: ACCOUNT_MODULE_IDENTIFIER.clone(),
        name: ACCOUNT_STRUCT_NAME.to_owned(),
        type_params: vec![],
    }
}

pub fn sent_payment_tag() -> StructTag {
    StructTag {
        address: CORE_CODE_ADDRESS,
        module: ACCOUNT_MODULE_IDENTIFIER.clone(),
        name: sent_event_name().to_owned(),
        type_params: vec![],
    }
}

pub fn received_payment_tag() -> StructTag {
    StructTag {
        address: CORE_CODE_ADDRESS,
        module: ACCOUNT_MODULE_IDENTIFIER.clone(),
        name: received_event_name().to_owned(),
        type_params: vec![],
    }
}
<commit_msg>Removing account_struct_tag from types/src/account_config/constants/account.rs<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::account_config::constants::CORE_CODE_ADDRESS;
use move_core_types::{
    identifier::{IdentStr, Identifier},
    language_storage::{ModuleId, StructTag},
};
use once_cell::sync::Lazy;

pub const ACCOUNT_MODULE_NAME: &str = "LibraAccount";

// Account
static ACCOUNT_MODULE_IDENTIFIER: Lazy<Identifier> =
    Lazy::new(|| Identifier::new("LibraAccount").unwrap());

/// The ModuleId for the Account module.
pub static ACCOUNT_MODULE: Lazy<ModuleId> =
    Lazy::new(|| ModuleId::new(CORE_CODE_ADDRESS, ACCOUNT_MODULE_IDENTIFIER.clone()));

// Payment Events
static SENT_EVENT_NAME: Lazy<Identifier> =
    Lazy::new(|| Identifier::new("SentPaymentEvent").unwrap());
static RECEIVED_EVENT_NAME: Lazy<Identifier> =
    Lazy::new(|| Identifier::new("ReceivedPaymentEvent").unwrap());

pub fn sent_event_name() -> &'static IdentStr {
    &*SENT_EVENT_NAME
}

pub fn received_event_name() -> &'static IdentStr {
    &*RECEIVED_EVENT_NAME
}

pub fn sent_payment_tag() -> StructTag {
    StructTag {
        address: CORE_CODE_ADDRESS,
        module: ACCOUNT_MODULE_IDENTIFIER.clone(),
        name: sent_event_name().to_owned(),
        type_params: vec![],
    }
}

pub fn received_payment_tag() -> StructTag {
    StructTag {
        address: CORE_CODE_ADDRESS,
        module: ACCOUNT_MODULE_IDENTIFIER.clone(),
        name: received_event_name().to_owned(),
        type_params: vec![],
    }
}
<|endoftext|>


<commit_before>//! ARMv6K Nintendo 3DS C Newlib definitions

pub type c_char = u8;
pub type c_long = i32;
pub type c_ulong = u32;

pub type wchar_t = ::c_uint;

pub type u_register_t = ::c_uint;
pub type u_char = ::c_uchar;
pub type u_short = ::c_ushort;
pub type u_int = ::c_uint;
pub type u_long = c_ulong;
pub type ushort = ::c_ushort;
pub type uint = ::c_uint;
pub type ulong = c_ulong;
pub type clock_t = c_ulong;
pub type daddr_t = c_long;
pub type caddr_t = *mut c_char;
pub type sbintime_t = ::c_longlong;
pub type sigset_t = ::c_ulong;

s! {
    pub struct sockaddr {
        pub sa_family: ::sa_family_t,
        pub sa_data: [::c_char; 26usize],
    }

    pub struct sockaddr_storage {
        pub ss_family: ::sa_family_t,
        pub __ss_padding: [::c_char; 26usize],
    }

    pub struct sockaddr_in {
        pub sin_family: ::sa_family_t,
        pub sin_port: ::in_port_t,
        pub sin_addr: ::in_addr,
    }

    pub struct sockaddr_in6 {
        pub sin6_family: ::sa_family_t,
        pub sin6_port: ::in_port_t,
        pub sin6_flowinfo: u32,
        pub sin6_addr: ::in6_addr,
        pub sin6_scope_id: u32,
    }

    pub struct sockaddr_un {
        pub sun_len: ::c_uchar,
        pub sun_family: ::sa_family_t,
        pub sun_path: [::c_char; 104usize],
    }

    pub struct sched_param {
        pub sched_priority: ::c_int,
    }

    pub struct stat {
        pub st_dev: ::dev_t,
        pub st_ino: ::ino_t,
        pub st_mode: ::mode_t,
        pub st_nlink: ::nlink_t,
        pub st_uid: ::uid_t,
        pub st_gid: ::gid_t,
        pub st_rdev: ::dev_t,
        pub st_size: ::off_t,
        pub st_atim: ::timespec,
        pub st_mtim: ::timespec,
        pub st_ctim: ::timespec,
        pub st_blksize: ::blksize_t,
        pub st_blocks: ::blkcnt_t,
        pub st_spare4: [::c_long; 2usize],
    }
}

pub const SIGEV_NONE: ::c_int = 1;
pub const SIGEV_SIGNAL: ::c_int = 2;
pub const SIGEV_THREAD: ::c_int = 3;
pub const SA_NOCLDSTOP: ::c_int = 1;
pub const MINSIGSTKSZ: ::c_int = 2048;
pub const SIGSTKSZ: ::c_int = 8192;
pub const SS_ONSTACK: ::c_int = 1;
pub const SS_DISABLE: ::c_int = 2;
pub const SIG_SETMASK: ::c_int = 0;
pub const SIG_BLOCK: ::c_int = 1;
pub const SIG_UNBLOCK: ::c_int = 2;
pub const SIGHUP: ::c_int = 1;
pub const SIGINT: ::c_int = 2;
pub const SIGQUIT: ::c_int = 3;
pub const SIGILL: ::c_int = 4;
pub const SIGTRAP: ::c_int = 5;
pub const SIGABRT: ::c_int = 6;
pub const SIGEMT: ::c_int = 7;
pub const SIGFPE: ::c_int = 8;
pub const SIGKILL: ::c_int = 9;
pub const SIGBUS: ::c_int = 10;
pub const SIGSEGV: ::c_int = 11;
pub const SIGSYS: ::c_int = 12;
pub const SIGPIPE: ::c_int = 13;
pub const SIGALRM: ::c_int = 14;
pub const SIGTERM: ::c_int = 15;
pub const SIGURG: ::c_int = 16;
pub const SIGSTOP: ::c_int = 17;
pub const SIGTSTP: ::c_int = 18;
pub const SIGCONT: ::c_int = 19;
pub const SIGCHLD: ::c_int = 20;
pub const SIGCLD: ::c_int = 20;
pub const SIGTTIN: ::c_int = 21;
pub const SIGTTOU: ::c_int = 22;
pub const SIGIO: ::c_int = 23;
pub const SIGPOLL: ::c_int = 23;
pub const SIGXCPU: ::c_int = 24;
pub const SIGXFSZ: ::c_int = 25;
pub const SIGVTALRM: ::c_int = 26;
pub const SIGPROF: ::c_int = 27;
pub const SIGWINCH: ::c_int = 28;
pub const SIGLOST: ::c_int = 29;
pub const SIGUSR1: ::c_int = 30;
pub const SIGUSR2: ::c_int = 31;
pub const NSIG: ::c_int = 32;
pub const CLOCK_ENABLED: ::c_uint = 1;
pub const CLOCK_DISABLED: ::c_uint = 0;
pub const CLOCK_ALLOWED: ::c_uint = 1;
pub const CLOCK_DISALLOWED: ::c_uint = 0;
pub const TIMER_ABSTIME: ::c_uint = 4;
pub const SOL_SOCKET: ::c_int = 65535;
pub const MSG_OOB: ::c_int = 1;
pub const MSG_PEEK: ::c_int = 2;
pub const MSG_DONTWAIT: ::c_int = 4;
pub const MSG_DONTROUTE: ::c_int = 0;
pub const MSG_WAITALL: ::c_int = 0;
pub const MSG_MORE: ::c_int = 0;
pub const MSG_NOSIGNAL: ::c_int = 0;
pub const SOL_CONFIG: ::c_uint = 65534;

pub const _SC_PAGESIZE: ::c_int = 8;
pub const _SC_GETPW_R_SIZE_MAX: ::c_int = 51;

pub const PTHREAD_STACK_MIN: ::size_t = 4096;
pub const WNOHANG: ::c_int = 1;

pub const POLLIN: ::c_short = 0x0001;
pub const POLLPRI: ::c_short = 0x0002;
pub const POLLOUT: ::c_short = 0x0004;
pub const POLLRDNORM: ::c_short = 0x0040;
pub const POLLWRNORM: ::c_short = POLLOUT;
pub const POLLRDBAND: ::c_short = 0x0080;
pub const POLLWRBAND: ::c_short = 0x0100;
pub const POLLERR: ::c_short = 0x0008;
pub const POLLHUP: ::c_short = 0x0010;
pub const POLLNVAL: ::c_short = 0x0020;

pub const EAI_AGAIN: ::c_int = 2;
pub const EAI_BADFLAGS: ::c_int = 3;
pub const EAI_FAIL: ::c_int = 4;
pub const EAI_SERVICE: ::c_int = 9;
pub const EAI_SYSTEM: ::c_int = 11;
pub const EAI_BADHINTS: ::c_int = 12;
pub const EAI_PROTOCOL: ::c_int = 13;
pub const EAI_OVERFLOW: ::c_int = 14;
pub const EAI_MAX: ::c_int = 15;

pub const AF_UNIX: ::c_int = 1;
pub const AF_INET6: ::c_int = 23;

pub const FIONBIO: ::c_ulong = 1;

pub const RTLD_DEFAULT: *mut ::c_void = 0 as *mut ::c_void;

// For pthread get/setschedparam
pub const SCHED_FIFO: ::c_int = 1;
pub const SCHED_RR: ::c_int = 2;

// For getrandom()
pub const GRND_NONBLOCK: ::c_uint = 0x1;
pub const GRND_RANDOM: ::c_uint = 0x2;

// Horizon OS works doesn't or can't hold any of this information
safe_f! {
    pub {const} fn WIFSTOPPED(_status: ::c_int) -> bool {
        false
    }

    pub {const} fn WSTOPSIG(_status: ::c_int) -> ::c_int {
        0
    }

    pub {const} fn WIFCONTINUED(_status: ::c_int) -> bool {
        true
    }

    pub {const} fn WIFSIGNALED(_status: ::c_int) -> bool {
        false
    }

    pub {const} fn WTERMSIG(_status: ::c_int) -> ::c_int {
        0
    }

    pub {const} fn WIFEXITED(_status: ::c_int) -> bool {
        true
    }

    pub {const} fn WEXITSTATUS(_status: ::c_int) -> ::c_int {
        0
    }

    pub {const} fn WCOREDUMP(_status: ::c_int) -> bool {
        false
    }
}

extern "C" {
    pub fn pthread_create(
        native: *mut ::pthread_t,
        attr: *const ::pthread_attr_t,
        f: extern "C" fn(_: *mut ::c_void) -> *mut ::c_void,
        value: *mut ::c_void,
    ) -> ::c_int;

    pub fn pthread_attr_getschedparam(
        attr: *const ::pthread_attr_t,
        param: *mut sched_param,
    ) -> ::c_int;

    pub fn pthread_attr_setschedparam(
        attr: *mut ::pthread_attr_t,
        param: *const sched_param,
    ) -> ::c_int;

    pub fn pthread_attr_getprocessorid_np(
        attr: *const ::pthread_attr_t,
        processor_id: *mut ::c_int,
    ) -> ::c_int;

    pub fn pthread_attr_setprocessorid_np(
        attr: *mut ::pthread_attr_t,
        processor_id: ::c_int,
    ) -> ::c_int;

    pub fn pthread_getschedparam(
        native: ::pthread_t,
        policy: *mut ::c_int,
        param: *mut ::sched_param,
    ) -> ::c_int;

    pub fn pthread_setschedparam(
        native: ::pthread_t,
        policy: ::c_int,
        param: *const ::sched_param,
    ) -> ::c_int;

    pub fn pthread_getprocessorid_np() -> ::c_int;

    pub fn getrandom(buf: *mut ::c_void, buflen: ::size_t, flags: ::c_uint) -> ::ssize_t;

    pub fn gethostid() -> ::c_long;
}
<commit_msg>Auto merge of #2752 - ian-h-chamberlain:horizon/pthread_condattr, r=Amanieu<commit_after>//! ARMv6K Nintendo 3DS C Newlib definitions

pub type c_char = u8;
pub type c_long = i32;
pub type c_ulong = u32;

pub type wchar_t = ::c_uint;

pub type u_register_t = ::c_uint;
pub type u_char = ::c_uchar;
pub type u_short = ::c_ushort;
pub type u_int = ::c_uint;
pub type u_long = c_ulong;
pub type ushort = ::c_ushort;
pub type uint = ::c_uint;
pub type ulong = c_ulong;
pub type clock_t = c_ulong;
pub type daddr_t = c_long;
pub type caddr_t = *mut c_char;
pub type sbintime_t = ::c_longlong;
pub type sigset_t = ::c_ulong;

s! {
    pub struct sockaddr {
        pub sa_family: ::sa_family_t,
        pub sa_data: [::c_char; 26usize],
    }

    pub struct sockaddr_storage {
        pub ss_family: ::sa_family_t,
        pub __ss_padding: [::c_char; 26usize],
    }

    pub struct sockaddr_in {
        pub sin_family: ::sa_family_t,
        pub sin_port: ::in_port_t,
        pub sin_addr: ::in_addr,
    }

    pub struct sockaddr_in6 {
        pub sin6_family: ::sa_family_t,
        pub sin6_port: ::in_port_t,
        pub sin6_flowinfo: u32,
        pub sin6_addr: ::in6_addr,
        pub sin6_scope_id: u32,
    }

    pub struct sockaddr_un {
        pub sun_len: ::c_uchar,
        pub sun_family: ::sa_family_t,
        pub sun_path: [::c_char; 104usize],
    }

    pub struct sched_param {
        pub sched_priority: ::c_int,
    }

    pub struct stat {
        pub st_dev: ::dev_t,
        pub st_ino: ::ino_t,
        pub st_mode: ::mode_t,
        pub st_nlink: ::nlink_t,
        pub st_uid: ::uid_t,
        pub st_gid: ::gid_t,
        pub st_rdev: ::dev_t,
        pub st_size: ::off_t,
        pub st_atim: ::timespec,
        pub st_mtim: ::timespec,
        pub st_ctim: ::timespec,
        pub st_blksize: ::blksize_t,
        pub st_blocks: ::blkcnt_t,
        pub st_spare4: [::c_long; 2usize],
    }
}

pub const SIGEV_NONE: ::c_int = 1;
pub const SIGEV_SIGNAL: ::c_int = 2;
pub const SIGEV_THREAD: ::c_int = 3;
pub const SA_NOCLDSTOP: ::c_int = 1;
pub const MINSIGSTKSZ: ::c_int = 2048;
pub const SIGSTKSZ: ::c_int = 8192;
pub const SS_ONSTACK: ::c_int = 1;
pub const SS_DISABLE: ::c_int = 2;
pub const SIG_SETMASK: ::c_int = 0;
pub const SIG_BLOCK: ::c_int = 1;
pub const SIG_UNBLOCK: ::c_int = 2;
pub const SIGHUP: ::c_int = 1;
pub const SIGINT: ::c_int = 2;
pub const SIGQUIT: ::c_int = 3;
pub const SIGILL: ::c_int = 4;
pub const SIGTRAP: ::c_int = 5;
pub const SIGABRT: ::c_int = 6;
pub const SIGEMT: ::c_int = 7;
pub const SIGFPE: ::c_int = 8;
pub const SIGKILL: ::c_int = 9;
pub const SIGBUS: ::c_int = 10;
pub const SIGSEGV: ::c_int = 11;
pub const SIGSYS: ::c_int = 12;
pub const SIGPIPE: ::c_int = 13;
pub const SIGALRM: ::c_int = 14;
pub const SIGTERM: ::c_int = 15;
pub const SIGURG: ::c_int = 16;
pub const SIGSTOP: ::c_int = 17;
pub const SIGTSTP: ::c_int = 18;
pub const SIGCONT: ::c_int = 19;
pub const SIGCHLD: ::c_int = 20;
pub const SIGCLD: ::c_int = 20;
pub const SIGTTIN: ::c_int = 21;
pub const SIGTTOU: ::c_int = 22;
pub const SIGIO: ::c_int = 23;
pub const SIGPOLL: ::c_int = 23;
pub const SIGXCPU: ::c_int = 24;
pub const SIGXFSZ: ::c_int = 25;
pub const SIGVTALRM: ::c_int = 26;
pub const SIGPROF: ::c_int = 27;
pub const SIGWINCH: ::c_int = 28;
pub const SIGLOST: ::c_int = 29;
pub const SIGUSR1: ::c_int = 30;
pub const SIGUSR2: ::c_int = 31;
pub const NSIG: ::c_int = 32;
pub const CLOCK_ENABLED: ::c_uint = 1;
pub const CLOCK_DISABLED: ::c_uint = 0;
pub const CLOCK_ALLOWED: ::c_uint = 1;
pub const CLOCK_DISALLOWED: ::c_uint = 0;
pub const TIMER_ABSTIME: ::c_uint = 4;
pub const SOL_SOCKET: ::c_int = 65535;
pub const MSG_OOB: ::c_int = 1;
pub const MSG_PEEK: ::c_int = 2;
pub const MSG_DONTWAIT: ::c_int = 4;
pub const MSG_DONTROUTE: ::c_int = 0;
pub const MSG_WAITALL: ::c_int = 0;
pub const MSG_MORE: ::c_int = 0;
pub const MSG_NOSIGNAL: ::c_int = 0;
pub const SOL_CONFIG: ::c_uint = 65534;

pub const _SC_PAGESIZE: ::c_int = 8;
pub const _SC_GETPW_R_SIZE_MAX: ::c_int = 51;

pub const PTHREAD_STACK_MIN: ::size_t = 4096;
pub const WNOHANG: ::c_int = 1;

pub const POLLIN: ::c_short = 0x0001;
pub const POLLPRI: ::c_short = 0x0002;
pub const POLLOUT: ::c_short = 0x0004;
pub const POLLRDNORM: ::c_short = 0x0040;
pub const POLLWRNORM: ::c_short = POLLOUT;
pub const POLLRDBAND: ::c_short = 0x0080;
pub const POLLWRBAND: ::c_short = 0x0100;
pub const POLLERR: ::c_short = 0x0008;
pub const POLLHUP: ::c_short = 0x0010;
pub const POLLNVAL: ::c_short = 0x0020;

pub const EAI_AGAIN: ::c_int = 2;
pub const EAI_BADFLAGS: ::c_int = 3;
pub const EAI_FAIL: ::c_int = 4;
pub const EAI_SERVICE: ::c_int = 9;
pub const EAI_SYSTEM: ::c_int = 11;
pub const EAI_BADHINTS: ::c_int = 12;
pub const EAI_PROTOCOL: ::c_int = 13;
pub const EAI_OVERFLOW: ::c_int = 14;
pub const EAI_MAX: ::c_int = 15;

pub const AF_UNIX: ::c_int = 1;
pub const AF_INET6: ::c_int = 23;

pub const FIONBIO: ::c_ulong = 1;

pub const RTLD_DEFAULT: *mut ::c_void = 0 as *mut ::c_void;

// For pthread get/setschedparam
pub const SCHED_FIFO: ::c_int = 1;
pub const SCHED_RR: ::c_int = 2;

// For getrandom()
pub const GRND_NONBLOCK: ::c_uint = 0x1;
pub const GRND_RANDOM: ::c_uint = 0x2;

// Horizon OS works doesn't or can't hold any of this information
safe_f! {
    pub {const} fn WIFSTOPPED(_status: ::c_int) -> bool {
        false
    }

    pub {const} fn WSTOPSIG(_status: ::c_int) -> ::c_int {
        0
    }

    pub {const} fn WIFCONTINUED(_status: ::c_int) -> bool {
        true
    }

    pub {const} fn WIFSIGNALED(_status: ::c_int) -> bool {
        false
    }

    pub {const} fn WTERMSIG(_status: ::c_int) -> ::c_int {
        0
    }

    pub {const} fn WIFEXITED(_status: ::c_int) -> bool {
        true
    }

    pub {const} fn WEXITSTATUS(_status: ::c_int) -> ::c_int {
        0
    }

    pub {const} fn WCOREDUMP(_status: ::c_int) -> bool {
        false
    }
}

extern "C" {
    pub fn pthread_create(
        native: *mut ::pthread_t,
        attr: *const ::pthread_attr_t,
        f: extern "C" fn(_: *mut ::c_void) -> *mut ::c_void,
        value: *mut ::c_void,
    ) -> ::c_int;

    pub fn pthread_attr_getschedparam(
        attr: *const ::pthread_attr_t,
        param: *mut sched_param,
    ) -> ::c_int;

    pub fn pthread_attr_setschedparam(
        attr: *mut ::pthread_attr_t,
        param: *const sched_param,
    ) -> ::c_int;

    pub fn pthread_attr_getprocessorid_np(
        attr: *const ::pthread_attr_t,
        processor_id: *mut ::c_int,
    ) -> ::c_int;

    pub fn pthread_attr_setprocessorid_np(
        attr: *mut ::pthread_attr_t,
        processor_id: ::c_int,
    ) -> ::c_int;

    pub fn pthread_getschedparam(
        native: ::pthread_t,
        policy: *mut ::c_int,
        param: *mut ::sched_param,
    ) -> ::c_int;

    pub fn pthread_setschedparam(
        native: ::pthread_t,
        policy: ::c_int,
        param: *const ::sched_param,
    ) -> ::c_int;

    pub fn pthread_condattr_getclock(
        attr: *const ::pthread_condattr_t,
        clock_id: *mut ::clockid_t,
    ) -> ::c_int;

    pub fn pthread_condattr_setclock(
        attr: *mut ::pthread_condattr_t,
        clock_id: ::clockid_t,
    ) -> ::c_int;

    pub fn pthread_getprocessorid_np() -> ::c_int;

    pub fn getrandom(buf: *mut ::c_void, buflen: ::size_t, flags: ::c_uint) -> ::ssize_t;

    pub fn gethostid() -> ::c_long;
}
<|endoftext|>


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

//! Utility functions for doubly-linked lists.

use std::collections::LinkedList;
use std::mem;

/// Splits the head off a list in O(1) time, and returns the head.
pub fn split_off_head<T>(list: &mut LinkedList<T>) -> LinkedList<T> {
    // FIXME: Work around https://github.com/rust-lang/rust/issues/22244
    if list.len() == 1 {
        return mem::replace(list, LinkedList::new());
    }
    let tail = list.split_off(1);
    mem::replace(list, tail)
}

/// Prepends the items in the other list to this one, leaving the other list empty.
#[inline]
pub fn prepend_from<T>(this: &mut LinkedList<T>, other: &mut LinkedList<T>) {
    other.append(this);
    mem::swap(this, other);
}
<commit_msg>Remove workaround for rust-lang/rust#22244<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Utility functions for doubly-linked lists.

use std::collections::LinkedList;
use std::mem;

/// Splits the head off a list in O(1) time, and returns the head.
pub fn split_off_head<T>(list: &mut LinkedList<T>) -> LinkedList<T> {
    let tail = list.split_off(1);
    mem::replace(list, tail)
}

/// Prepends the items in the other list to this one, leaving the other list empty.
#[inline]
pub fn prepend_from<T>(this: &mut LinkedList<T>, other: &mut LinkedList<T>) {
    other.append(this);
    mem::swap(this, other);
}
<|endoftext|>


<commit_before>use crc32c::*;
use std::cell::RefCell;
use std::collections::HashMap;
use std::fs::{File, OpenOptions};
use std::io::{Cursor, Read, Seek, SeekFrom, Write};
use std::path::Path;
use std::sync::Arc;

use crate::blockchain::{block::*, index::*};

const MAX_CACHE_SIZE: u64 = 100;

pub struct BlockStore {
    indexer: Arc<Indexer>,

    height: u64,
    blocks: HashMap<u64, Arc<SignedBlock>>,
    genesis_block: Option<Arc<SignedBlock>>,

    file: RefCell<File>,
    byte_pos_tail: u64,
}

impl BlockStore {
    pub fn new(path: &Path, indexer: Arc<Indexer>) -> BlockStore {
        let (file, tail) = {
            let f = OpenOptions::new()
                .create(true)
                .read(true)
                .append(true)
                .open(path)
                .unwrap();
            let m = f.metadata().unwrap();
            (f, m.len())
        };

        let height = indexer.get_chain_height();
        let mut store = BlockStore {
            indexer,

            height,
            blocks: HashMap::new(),
            genesis_block: None,

            file: RefCell::new(file),
            byte_pos_tail: tail,
        };
        store.genesis_block = store.get(0);

        {
            // Initialize the cache
            let min = if height < MAX_CACHE_SIZE {
                height
            } else {
                height - 100
            };
            let max = min + MAX_CACHE_SIZE;
            for height in min..=max {
                if let Some(block) = store.get_from_disk(height) {
                    store.blocks.insert(height, Arc::new(block));
                } else {
                    break;
                }
            }
        }

        store
    }

    #[inline(always)]
    pub fn get_chain_height(&self) -> u64 {
        self.height
    }

    pub fn get(&self, height: u64) -> Option<Arc<SignedBlock>> {
        if height > self.height {
            return None;
        } else if height == 0 {
            if let Some(ref block) = self.genesis_block {
                return Some(Arc::clone(block));
            }
        }
        if let Some(block) = self.blocks.get(&height) {
            Some(Arc::clone(block))
        } else {
            Some(Arc::new(self.get_from_disk(height)?))
        }
    }

    fn get_from_disk(&self, height: u64) -> Option<SignedBlock> {
        if height > self.height {
            return None;
        }

        let pos = self.indexer.get_block_byte_pos(height)?;
        let mut f = self.file.borrow_mut();
        f.seek(SeekFrom::Start(pos)).unwrap();

        let (block_len, crc) = {
            let mut meta = [0u8; 8];
            f.read_exact(&mut meta).unwrap();
            let len = u32_from_buf!(meta, 0) as usize;
            let crc = u32_from_buf!(meta, 4);
            (len, crc)
        };

        let block_vec = {
            let mut buf = Vec::with_capacity(block_len);
            unsafe {
                buf.set_len(block_len);
            }
            f.read_exact(&mut buf).unwrap();
            assert_eq!(crc, crc32c(&buf));
            buf
        };

        let mut cursor = Cursor::<&[u8]>::new(&block_vec);
        let block = SignedBlock::decode_with_tx(&mut cursor).unwrap();
        Some(block)
    }

    pub fn insert(&mut self, block: SignedBlock) {
        assert_eq!(self.height + 1, block.height, "invalid block height");
        let byte_pos = self.byte_pos_tail;
        self.write_to_disk(&block);

        {
            // Update internal cache
            let height = block.height;
            self.height = height;
            self.indexer.set_block_byte_pos(height, byte_pos);
            self.indexer.set_chain_height(height);

            let opt = self.blocks.insert(height, Arc::new(block));
            if self.blocks.len() > MAX_CACHE_SIZE as usize {
                let b = self.blocks.remove(&(height - MAX_CACHE_SIZE));
                debug_assert!(b.is_some(), "nothing removed from cache");
            }
            debug_assert!(opt.is_none(), "block already in the chain");
        }
    }

    pub fn insert_genesis(&mut self, block: SignedBlock) {
        assert_eq!(block.height, 0, "expected to be 0");
        assert!(
            self.genesis_block.is_none(),
            "expected genesis block to not exist"
        );
        self.write_to_disk(&block);
        self.genesis_block = Some(Arc::new(block));
        self.indexer.set_block_byte_pos(0, 0);
    }

    fn write_to_disk(&mut self, block: &SignedBlock) {
        let vec = &mut Vec::with_capacity(1_048_576);
        block.encode_with_tx(vec);
        let len = vec.len() as u32;
        let crc = crc32c(vec);

        let mut f = self.file.borrow_mut();
        {
            let mut buf = [0u8; 8];
            buf[0] = (len >> 24) as u8;
            buf[1] = (len >> 16) as u8;
            buf[2] = (len >> 8) as u8;
            buf[3] = len as u8;

            buf[4] = (crc >> 24) as u8;
            buf[5] = (crc >> 16) as u8;
            buf[6] = (crc >> 8) as u8;
            buf[7] = crc as u8;

            f.write_all(&buf).unwrap();
        }

        f.write_all(vec).unwrap();
        f.flush().unwrap();

        self.byte_pos_tail += u64::from(len) + 8;
    }
}
<commit_msg>Improve panic errors when blocks fail to decode from disk<commit_after>use crc32c::*;
use std::cell::RefCell;
use std::collections::HashMap;
use std::fs::{File, OpenOptions};
use std::io::{Cursor, Read, Seek, SeekFrom, Write};
use std::path::Path;
use std::sync::Arc;

use crate::blockchain::{block::*, index::*};

const MAX_CACHE_SIZE: u64 = 100;

pub struct BlockStore {
    indexer: Arc<Indexer>,

    height: u64,
    blocks: HashMap<u64, Arc<SignedBlock>>,
    genesis_block: Option<Arc<SignedBlock>>,

    file: RefCell<File>,
    byte_pos_tail: u64,
}

impl BlockStore {
    pub fn new(path: &Path, indexer: Arc<Indexer>) -> BlockStore {
        let (file, tail) = {
            let f = OpenOptions::new()
                .create(true)
                .read(true)
                .append(true)
                .open(path)
                .unwrap();
            let m = f.metadata().unwrap();
            (f, m.len())
        };

        let height = indexer.get_chain_height();
        let mut store = BlockStore {
            indexer,

            height,
            blocks: HashMap::new(),
            genesis_block: None,

            file: RefCell::new(file),
            byte_pos_tail: tail,
        };
        store.genesis_block = store.get(0);

        {
            // Initialize the cache
            let min = if height < MAX_CACHE_SIZE {
                height
            } else {
                height - 100
            };
            let max = min + MAX_CACHE_SIZE;
            for height in min..=max {
                if let Some(block) = store.get_from_disk(height) {
                    store.blocks.insert(height, Arc::new(block));
                } else {
                    break;
                }
            }
        }

        store
    }

    #[inline(always)]
    pub fn get_chain_height(&self) -> u64 {
        self.height
    }

    pub fn get(&self, height: u64) -> Option<Arc<SignedBlock>> {
        if height > self.height {
            return None;
        } else if height == 0 {
            if let Some(ref block) = self.genesis_block {
                return Some(Arc::clone(block));
            }
        }
        if let Some(block) = self.blocks.get(&height) {
            Some(Arc::clone(block))
        } else {
            Some(Arc::new(self.get_from_disk(height)?))
        }
    }

    fn get_from_disk(&self, height: u64) -> Option<SignedBlock> {
        if height > self.height {
            return None;
        }

        let pos = self.indexer.get_block_byte_pos(height)?;
        let mut f = self.file.borrow_mut();
        f.seek(SeekFrom::Start(pos)).unwrap();

        let (block_len, crc) = {
            let mut meta = [0u8; 8];
            f.read_exact(&mut meta).unwrap();
            let len = u32_from_buf!(meta, 0) as usize;
            let crc = u32_from_buf!(meta, 4);
            (len, crc)
        };

        let block_vec = {
            let mut buf = Vec::with_capacity(block_len);
            unsafe {
                buf.set_len(block_len);
            }
            f.read_exact(&mut buf).unwrap();
            assert_eq!(crc, crc32c(&buf));
            buf
        };

        let mut cursor = Cursor::<&[u8]>::new(&block_vec);
        Some(SignedBlock::decode_with_tx(&mut cursor).expect("failed to decode block from disk"))
    }

    pub fn insert(&mut self, block: SignedBlock) {
        assert_eq!(self.height + 1, block.height, "invalid block height");
        let byte_pos = self.byte_pos_tail;
        self.write_to_disk(&block);

        {
            // Update internal cache
            let height = block.height;
            self.height = height;
            self.indexer.set_block_byte_pos(height, byte_pos);
            self.indexer.set_chain_height(height);

            let opt = self.blocks.insert(height, Arc::new(block));
            if self.blocks.len() > MAX_CACHE_SIZE as usize {
                let b = self.blocks.remove(&(height - MAX_CACHE_SIZE));
                debug_assert!(b.is_some(), "nothing removed from cache");
            }
            debug_assert!(opt.is_none(), "block already in the chain");
        }
    }

    pub fn insert_genesis(&mut self, block: SignedBlock) {
        assert_eq!(block.height, 0, "expected to be 0");
        assert!(
            self.genesis_block.is_none(),
            "expected genesis block to not exist"
        );
        self.write_to_disk(&block);
        self.genesis_block = Some(Arc::new(block));
        self.indexer.set_block_byte_pos(0, 0);
    }

    fn write_to_disk(&mut self, block: &SignedBlock) {
        let vec = &mut Vec::with_capacity(1_048_576);
        block.encode_with_tx(vec);
        let len = vec.len() as u32;
        let crc = crc32c(vec);

        let mut f = self.file.borrow_mut();
        {
            let mut buf = [0u8; 8];
            buf[0] = (len >> 24) as u8;
            buf[1] = (len >> 16) as u8;
            buf[2] = (len >> 8) as u8;
            buf[3] = len as u8;

            buf[4] = (crc >> 24) as u8;
            buf[5] = (crc >> 16) as u8;
            buf[6] = (crc >> 8) as u8;
            buf[7] = crc as u8;

            f.write_all(&buf).unwrap();
        }

        f.write_all(vec).unwrap();
        f.flush().unwrap();

        self.byte_pos_tail += u64::from(len) + 8;
    }
}
<|endoftext|>


<commit_before>use hir::db::HirDatabase;
use hir::source_binder::function_from_child_node;
use ra_syntax::{ast::{self, AstNode}, TextRange};
use ra_syntax::ast::{PatKind, ExprKind};

use crate::{Assist, AssistCtx, AssistId};
use crate::assist_ctx::AssistBuilder;

pub(crate) fn inline_local_varialbe(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
    let let_stmt = ctx.node_at_offset::<ast::LetStmt>()?;
    let bind_pat = match let_stmt.pat()?.kind() {
        PatKind::BindPat(pat) => pat,
        _ => return None,
    };
    if bind_pat.is_mutable() {
        return None;
    }
    let initializer = let_stmt.initializer()?;
    let wrap_in_parens = match initializer.kind() {
        ExprKind::LambdaExpr(_) => true,
        ExprKind::IfExpr(_) => true,
        ExprKind::LoopExpr(_) => true,
        ExprKind::ForExpr(_) => true,
        ExprKind::WhileExpr(_) => true,
        ExprKind::ContinueExpr(_) => true,
        ExprKind::BreakExpr(_) => true,
        ExprKind::Label(_) => true,
        ExprKind::ReturnExpr(_) => true,
        ExprKind::MatchExpr(_) => true,
        ExprKind::StructLit(_) => true,
        ExprKind::CastExpr(_) => true,
        ExprKind::PrefixExpr(_) => true,
        ExprKind::RangeExpr(_) => true,
        ExprKind::BinExpr(_) => true,
        ExprKind::CallExpr(_) => false,
        ExprKind::IndexExpr(_) => false,
        ExprKind::MethodCallExpr(_) => false,
        ExprKind::FieldExpr(_) => false,
        ExprKind::TryExpr(_) => false,
        ExprKind::RefExpr(_) => false,
        ExprKind::Literal(_) => false,
        ExprKind::TupleExpr(_) => false,
        ExprKind::ArrayExpr(_) => false,
        ExprKind::ParenExpr(_) => false,
        ExprKind::PathExpr(_) => false,
        ExprKind::BlockExpr(_) => false,
    };

    let delete_range = if let Some(whitespace) =
        let_stmt.syntax().next_sibling().and_then(ast::Whitespace::cast)
    {
        TextRange::from_to(let_stmt.syntax().range().start(), whitespace.syntax().range().end())
    } else {
        let_stmt.syntax().range()
    };

    let init_str = if wrap_in_parens {
        format!("({})", initializer.syntax().text().to_string())
    } else {
        initializer.syntax().text().to_string()
    };
    let function = function_from_child_node(ctx.db, ctx.frange.file_id, bind_pat.syntax())?;
    let scope = function.scopes(ctx.db);
    let refs = scope.find_all_refs(bind_pat);

    ctx.add_action(
        AssistId("inline_local_variable"),
        "inline local variable",
        move |edit: &mut AssistBuilder| {
            edit.delete(delete_range);
            for desc in refs {
                edit.replace(desc.range, init_str.clone())
            }
            edit.set_cursor(delete_range.start())
        },
    );

    ctx.build()
}

#[cfg(test)]
mod tests {
    use crate::helpers::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn test_inline_let_bind_literal_expr() {
        check_assist(
            inline_local_varialbe,
            "
fn bar(a: usize) {}
fn foo() {
    let a<|> = 1;
    a + 1;
    if a > 10 {
    }

    while a > 10 {

    }
    let b = a * 10;
    bar(a);
}",
            "
fn bar(a: usize) {}
fn foo() {
    <|>1 + 1;
    if 1 > 10 {
    }

    while 1 > 10 {

    }
    let b = 1 * 10;
    bar(1);
}",
        );
    }

    #[test]
    fn test_inline_let_bind_bin_expr() {
        check_assist(
            inline_local_varialbe,
            "
fn bar(a: usize) {}
fn foo() {
    let a<|> = 1 + 1;
    a + 1;
    if a > 10 {
    }

    while a > 10 {

    }
    let b = a * 10;
    bar(a);
}",
            "
fn bar(a: usize) {}
fn foo() {
    <|>(1 + 1) + 1;
    if (1 + 1) > 10 {
    }

    while (1 + 1) > 10 {

    }
    let b = (1 + 1) * 10;
    bar((1 + 1));
}",
        );
    }

    #[test]
    fn test_inline_let_bind_function_call_expr() {
        check_assist(
            inline_local_varialbe,
            "
fn bar(a: usize) {}
fn foo() {
    let a<|> = bar(1);
    a + 1;
    if a > 10 {
    }

    while a > 10 {

    }
    let b = a * 10;
    bar(a);
}",
            "
fn bar(a: usize) {}
fn foo() {
    <|>bar(1) + 1;
    if bar(1) > 10 {
    }

    while bar(1) > 10 {

    }
    let b = bar(1) * 10;
    bar(bar(1));
}",
        );
    }

    #[test]
    fn test_inline_let_bind_cast_expr() {
        check_assist(
            inline_local_varialbe,
            "
fn bar(a: usize): usize { a }
fn foo() {
    let a<|> = bar(1) as u64;
    a + 1;
    if a > 10 {
    }

    while a > 10 {

    }
    let b = a * 10;
    bar(a);
}",
            "
fn bar(a: usize): usize { a }
fn foo() {
    <|>(bar(1) as u64) + 1;
    if (bar(1) as u64) > 10 {
    }

    while (bar(1) as u64) > 10 {

    }
    let b = (bar(1) as u64) * 10;
    bar((bar(1) as u64));
}",
        );
    }

    #[test]
    fn test_inline_let_bind_block_expr() {
        check_assist(
            inline_local_varialbe,
            "
fn foo() {
    let a<|> = { 10 + 1 };
    a + 1;
    if a > 10 {
    }

    while a > 10 {

    }
    let b = a * 10;
    bar(a);
}",
            "
fn foo() {
    <|>{ 10 + 1 } + 1;
    if { 10 + 1 } > 10 {
    }

    while { 10 + 1 } > 10 {

    }
    let b = { 10 + 1 } * 10;
    bar({ 10 + 1 });
}",
        );
    }

    #[test]
    fn test_inline_let_bind_paren_expr() {
        check_assist(
            inline_local_varialbe,
            "
fn foo() {
    let a<|> = ( 10 + 1 );
    a + 1;
    if a > 10 {
    }

    while a > 10 {

    }
    let b = a * 10;
    bar(a);
}",
            "
fn foo() {
    <|>( 10 + 1 ) + 1;
    if ( 10 + 1 ) > 10 {
    }

    while ( 10 + 1 ) > 10 {

    }
    let b = ( 10 + 1 ) * 10;
    bar(( 10 + 1 ));
}",
        );
    }

    #[test]
    fn test_not_inline_mut_variable() {
        check_assist_not_applicable(
            inline_local_varialbe,
            "
fn foo() {
    let mut a<|> = 1 + 1;
    a + 1;
}",
        );
    }
}
<commit_msg>use | instead of multiple match arms<commit_after>use hir::db::HirDatabase;
use hir::source_binder::function_from_child_node;
use ra_syntax::{ast::{self, AstNode}, TextRange};
use ra_syntax::ast::{PatKind, ExprKind};

use crate::{Assist, AssistCtx, AssistId};
use crate::assist_ctx::AssistBuilder;

pub(crate) fn inline_local_varialbe(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
    let let_stmt = ctx.node_at_offset::<ast::LetStmt>()?;
    let bind_pat = match let_stmt.pat()?.kind() {
        PatKind::BindPat(pat) => pat,
        _ => return None,
    };
    if bind_pat.is_mutable() {
        return None;
    }
    let initializer = let_stmt.initializer()?;
    let wrap_in_parens = match initializer.kind() {
        ExprKind::LambdaExpr(_)
        | ExprKind::IfExpr(_)
        | ExprKind::LoopExpr(_)
        | ExprKind::ForExpr(_)
        | ExprKind::WhileExpr(_)
        | ExprKind::ContinueExpr(_)
        | ExprKind::BreakExpr(_)
        | ExprKind::Label(_)
        | ExprKind::ReturnExpr(_)
        | ExprKind::MatchExpr(_)
        | ExprKind::StructLit(_)
        | ExprKind::CastExpr(_)
        | ExprKind::PrefixExpr(_)
        | ExprKind::RangeExpr(_)
        | ExprKind::BinExpr(_) => true,
        ExprKind::CallExpr(_)
        | ExprKind::IndexExpr(_)
        | ExprKind::MethodCallExpr(_)
        | ExprKind::FieldExpr(_)
        | ExprKind::TryExpr(_)
        | ExprKind::RefExpr(_)
        | ExprKind::Literal(_)
        | ExprKind::TupleExpr(_)
        | ExprKind::ArrayExpr(_)
        | ExprKind::ParenExpr(_)
        | ExprKind::PathExpr(_)
        | ExprKind::BlockExpr(_) => false,
    };

    let delete_range = if let Some(whitespace) =
        let_stmt.syntax().next_sibling().and_then(ast::Whitespace::cast)
    {
        TextRange::from_to(let_stmt.syntax().range().start(), whitespace.syntax().range().end())
    } else {
        let_stmt.syntax().range()
    };

    let init_str = if wrap_in_parens {
        format!("({})", initializer.syntax().text().to_string())
    } else {
        initializer.syntax().text().to_string()
    };
    let function = function_from_child_node(ctx.db, ctx.frange.file_id, bind_pat.syntax())?;
    let scope = function.scopes(ctx.db);
    let refs = scope.find_all_refs(bind_pat);

    ctx.add_action(
        AssistId("inline_local_variable"),
        "inline local variable",
        move |edit: &mut AssistBuilder| {
            edit.delete(delete_range);
            for desc in refs {
                edit.replace(desc.range, init_str.clone())
            }
            edit.set_cursor(delete_range.start())
        },
    );

    ctx.build()
}

#[cfg(test)]
mod tests {
    use crate::helpers::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn test_inline_let_bind_literal_expr() {
        check_assist(
            inline_local_varialbe,
            "
fn bar(a: usize) {}
fn foo() {
    let a<|> = 1;
    a + 1;
    if a > 10 {
    }

    while a > 10 {

    }
    let b = a * 10;
    bar(a);
}",
            "
fn bar(a: usize) {}
fn foo() {
    <|>1 + 1;
    if 1 > 10 {
    }

    while 1 > 10 {

    }
    let b = 1 * 10;
    bar(1);
}",
        );
    }

    #[test]
    fn test_inline_let_bind_bin_expr() {
        check_assist(
            inline_local_varialbe,
            "
fn bar(a: usize) {}
fn foo() {
    let a<|> = 1 + 1;
    a + 1;
    if a > 10 {
    }

    while a > 10 {

    }
    let b = a * 10;
    bar(a);
}",
            "
fn bar(a: usize) {}
fn foo() {
    <|>(1 + 1) + 1;
    if (1 + 1) > 10 {
    }

    while (1 + 1) > 10 {

    }
    let b = (1 + 1) * 10;
    bar((1 + 1));
}",
        );
    }

    #[test]
    fn test_inline_let_bind_function_call_expr() {
        check_assist(
            inline_local_varialbe,
            "
fn bar(a: usize) {}
fn foo() {
    let a<|> = bar(1);
    a + 1;
    if a > 10 {
    }

    while a > 10 {

    }
    let b = a * 10;
    bar(a);
}",
            "
fn bar(a: usize) {}
fn foo() {
    <|>bar(1) + 1;
    if bar(1) > 10 {
    }

    while bar(1) > 10 {

    }
    let b = bar(1) * 10;
    bar(bar(1));
}",
        );
    }

    #[test]
    fn test_inline_let_bind_cast_expr() {
        check_assist(
            inline_local_varialbe,
            "
fn bar(a: usize): usize { a }
fn foo() {
    let a<|> = bar(1) as u64;
    a + 1;
    if a > 10 {
    }

    while a > 10 {

    }
    let b = a * 10;
    bar(a);
}",
            "
fn bar(a: usize): usize { a }
fn foo() {
    <|>(bar(1) as u64) + 1;
    if (bar(1) as u64) > 10 {
    }

    while (bar(1) as u64) > 10 {

    }
    let b = (bar(1) as u64) * 10;
    bar((bar(1) as u64));
}",
        );
    }

    #[test]
    fn test_inline_let_bind_block_expr() {
        check_assist(
            inline_local_varialbe,
            "
fn foo() {
    let a<|> = { 10 + 1 };
    a + 1;
    if a > 10 {
    }

    while a > 10 {

    }
    let b = a * 10;
    bar(a);
}",
            "
fn foo() {
    <|>{ 10 + 1 } + 1;
    if { 10 + 1 } > 10 {
    }

    while { 10 + 1 } > 10 {

    }
    let b = { 10 + 1 } * 10;
    bar({ 10 + 1 });
}",
        );
    }

    #[test]
    fn test_inline_let_bind_paren_expr() {
        check_assist(
            inline_local_varialbe,
            "
fn foo() {
    let a<|> = ( 10 + 1 );
    a + 1;
    if a > 10 {
    }

    while a > 10 {

    }
    let b = a * 10;
    bar(a);
}",
            "
fn foo() {
    <|>( 10 + 1 ) + 1;
    if ( 10 + 1 ) > 10 {
    }

    while ( 10 + 1 ) > 10 {

    }
    let b = ( 10 + 1 ) * 10;
    bar(( 10 + 1 ));
}",
        );
    }

    #[test]
    fn test_not_inline_mut_variable() {
        check_assist_not_applicable(
            inline_local_varialbe,
            "
fn foo() {
    let mut a<|> = 1 + 1;
    a + 1;
}",
        );
    }
}
<|endoftext|>


<commit_before>mod support;

use serde_json::json;
use ra_lsp_server::req::{Runnables, RunnablesParams, CodeActionRequest, CodeActionParams, Formatting};
use languageserver_types::{Position, Range, CodeActionContext, DocumentFormattingParams, FormattingOptions};

use crate::support::project;

const LOG: &'static str = "";

#[test]
fn test_runnables_no_project() {
    let server = project(
        r"
//- lib.rs
#[test]
fn foo() {
}
",
    );
    server.wait_for_feedback("workspace loaded");
    server.request::<Runnables>(
        RunnablesParams {
            text_document: server.doc_id("lib.rs"),
            position: None,
        },
        json!([
          {
            "args": [ "test", "--", "foo", "--nocapture" ],
            "bin": "cargo",
            "env": { "RUST_BACKTRACE": "short" },
            "label": "test foo",
            "range": {
              "end": { "character": 1, "line": 2 },
              "start": { "character": 0, "line": 0 }
            }
          },
          {
            "args": [
              "check",
              "--all"
            ],
            "bin": "cargo",
            "env": {},
            "label": "cargo check --all",
            "range": {
              "end": {
                "character": 0,
                "line": 0
              },
              "start": {
                "character": 0,
                "line": 0
              }
            }
          }
        ]),
    );
}

#[test]
fn test_runnables_project() {
    let server = project(
        r#"
//- Cargo.toml
[package]
name = "foo"
version = "0.0.0"

//- src/lib.rs
pub fn foo() {}

//- tests/spam.rs
#[test]
fn test_eggs() {}
"#,
    );
    server.wait_for_feedback("workspace loaded");
    server.request::<Runnables>(
        RunnablesParams {
            text_document: server.doc_id("tests/spam.rs"),
            position: None,
        },
        json!([
          {
            "args": [ "test", "--package", "foo", "--test", "spam", "--", "test_eggs", "--nocapture" ],
            "bin": "cargo",
            "env": { "RUST_BACKTRACE": "short" },
            "label": "test test_eggs",
            "range": {
              "end": { "character": 17, "line": 1 },
              "start": { "character": 0, "line": 0 }
            }
          },
          {
            "args": [
              "check",
              "--package",
              "foo",
              "--test",
              "spam"
            ],
            "bin": "cargo",
            "env": {},
            "label": "cargo check -p foo",
            "range": {
              "end": {
                "character": 0,
                "line": 0
              },
              "start": {
                "character": 0,
                "line": 0
              }
            }
          }
        ])
    );
}

use std::collections::HashMap;
#[test]
fn test_format_document() {
    tools::install_rustfmt().unwrap();

    let server = project(
        r#"
[package]
name = "foo"
version = "0.0.0"

//- src/lib.rs
mod bar;

fn main() {
}

pub use std::collections::HashMap;
"#,
    );
    server.wait_for_feedback("workspace loaded");

    server.request::<Formatting>(
        DocumentFormattingParams {
            text_document: server.doc_id("src/lib.rs"),
            options: FormattingOptions {
                tab_size: 4,
                insert_spaces: false,
                properties: HashMap::new(),
            },
        },
        json!([
            {
                "newText": r#"mod bar;

fn main() {}

pub use std::collections::HashMap;
"#,
                "range": {
                    "end": {
                        "character": 0,
                        "line": 6
                    },
                    "start": {
                        "character": 0,
                        "line": 0
                    }
                }
            }
        ]),
    );
}

#[test]
fn test_missing_module_code_action() {
    let server = project(
        r#"
//- Cargo.toml
[package]
name = "foo"
version = "0.0.0"

//- src/lib.rs
mod bar;

fn main() {}
"#,
    );
    server.wait_for_feedback("workspace loaded");
    let empty_context = || CodeActionContext {
        diagnostics: Vec::new(),
        only: None,
    };
    server.request::<CodeActionRequest>(
        CodeActionParams {
            text_document: server.doc_id("src/lib.rs"),
            range: Range::new(Position::new(0, 4), Position::new(0, 7)),
            context: empty_context(),
        },
        json!([
            {
              "arguments": [
                {
                  "cursorPosition": null,
                  "fileSystemEdits": [
                    {
                        "type": "createFile",
                        "uri": "file:///[..]/src/bar.rs"
                    }
                  ],
                  "label": "create module",
                  "sourceFileEdits": []
                }
              ],
              "command": "ra-lsp.applySourceChange",
              "title": "create module"
            }
        ]),
    );

    server.request::<CodeActionRequest>(
        CodeActionParams {
            text_document: server.doc_id("src/lib.rs"),
            range: Range::new(Position::new(2, 4), Position::new(2, 7)),
            context: empty_context(),
        },
        json!([]),
    );
}
<commit_msg>fix tests<commit_after>mod support;

use languageserver_types::{
    CodeActionContext, DocumentFormattingParams, FormattingOptions, Position, Range,
};
use ra_lsp_server::req::{
    CodeActionParams, CodeActionRequest, Formatting, Runnables, RunnablesParams,
};
use serde_json::json;

use crate::support::project;

const LOG: &'static str = "";

#[test]
fn test_runnables_no_project() {
    let server = project(
        r"
//- lib.rs
#[test]
fn foo() {
}
",
    );
    server.wait_for_feedback("workspace loaded");
    server.request::<Runnables>(
        RunnablesParams {
            text_document: server.doc_id("lib.rs"),
            position: None,
        },
        json!([
          {
            "args": [ "test", "--", "foo", "--nocapture" ],
            "bin": "cargo",
            "env": { "RUST_BACKTRACE": "short" },
            "label": "test foo",
            "range": {
              "end": { "character": 1, "line": 2 },
              "start": { "character": 0, "line": 0 }
            }
          },
          {
            "args": [
              "check",
              "--all"
            ],
            "bin": "cargo",
            "env": {},
            "label": "cargo check --all",
            "range": {
              "end": {
                "character": 0,
                "line": 0
              },
              "start": {
                "character": 0,
                "line": 0
              }
            }
          }
        ]),
    );
}

#[test]
fn test_runnables_project() {
    let server = project(
        r#"
//- Cargo.toml
[package]
name = "foo"
version = "0.0.0"

//- src/lib.rs
pub fn foo() {}

//- tests/spam.rs
#[test]
fn test_eggs() {}
"#,
    );
    server.wait_for_feedback("workspace loaded");
    server.request::<Runnables>(
        RunnablesParams {
            text_document: server.doc_id("tests/spam.rs"),
            position: None,
        },
        json!([
          {
            "args": [ "test", "--package", "foo", "--test", "spam", "--", "test_eggs", "--nocapture" ],
            "bin": "cargo",
            "env": { "RUST_BACKTRACE": "short" },
            "label": "test test_eggs",
            "range": {
              "end": { "character": 17, "line": 1 },
              "start": { "character": 0, "line": 0 }
            }
          },
          {
            "args": [
              "check",
              "--package",
              "foo",
              "--test",
              "spam"
            ],
            "bin": "cargo",
            "env": {},
            "label": "cargo check -p foo",
            "range": {
              "end": {
                "character": 0,
                "line": 0
              },
              "start": {
                "character": 0,
                "line": 0
              }
            }
          }
        ])
    );
}

use std::collections::HashMap;
#[test]
fn test_format_document() {
    tools::install_rustfmt().unwrap();

    let server = project(
        r#"
[package]
name = "foo"
version = "0.0.0"

//- src/lib.rs
mod bar;

fn main() {
}

pub use std::collections::HashMap;
"#,
    );
    server.wait_for_feedback("workspace loaded");

    server.request::<Formatting>(
        DocumentFormattingParams {
            text_document: server.doc_id("src/lib.rs"),
            options: FormattingOptions {
                tab_size: 4,
                insert_spaces: false,
                properties: HashMap::new(),
            },
        },
        json!([
            {
                "newText": r#"mod bar;

fn main() {}

pub use std::collections::HashMap;
"#,
                "range": {
                    "end": {
                        "character": 0,
                        "line": 6
                    },
                    "start": {
                        "character": 0,
                        "line": 0
                    }
                }
            }
        ]),
    );
}

#[test]
fn test_missing_module_code_action() {
    let server = project(
        r#"
//- Cargo.toml
[package]
name = "foo"
version = "0.0.0"

//- src/lib.rs
mod bar;

fn main() {}
"#,
    );
    server.wait_for_feedback("workspace loaded");
    let empty_context = || CodeActionContext {
        diagnostics: Vec::new(),
        only: None,
    };
    server.request::<CodeActionRequest>(
        CodeActionParams {
            text_document: server.doc_id("src/lib.rs"),
            range: Range::new(Position::new(0, 4), Position::new(0, 7)),
            context: empty_context(),
        },
        json!([
            {
              "arguments": [
                {
                  "cursorPosition": null,
                  "workspaceEdit": {
                    "documentChanges": [
                      {
                        "kind": "create",
                        "uri": "file:///[..]/src/bar.rs"
                      }
                    ]
                  },
                  "label": "create module"
                }
              ],
              "command": "ra-lsp.applySourceChange",
              "title": "create module"
            }
        ]),
    );

    server.request::<CodeActionRequest>(
        CodeActionParams {
            text_document: server.doc_id("src/lib.rs"),
            range: Range::new(Position::new(2, 4), Position::new(2, 7)),
            context: empty_context(),
        },
        json!([]),
    );
}
<|endoftext|>


<commit_before>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2013, 2014  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

// This module provides types that are intrinsic in GIR, so they do not
// get defined through other types. It should ultimately have a name defined
// for every basic type listed in the documentation:
// https://wiki.gnome.org/Projects/GObjectIntrospection/Annotations#Default_Basic_Types
//
// Exceptions are:
// 1. Fixed-size integer types. These have straightforward machine-independent
//    counterparts in Rust.
// 2. Strings annotated as "utf8" or "filename". These types are not named
//    as such in the C API, being only aliases for gchar*.
//    Their representation in Rust is quite intricate and involves multiple
//    types, so they each get their own module.
//
// Rust aliases are needed for machine-dependent basic types used in GIR,
// since the GLib types are not necessarily identical to their Rust namesakes
// (the issue similarly addressed by libc::c_int and the like).
// GIR uses the GLib names for these types as well.

#![allow(non_camel_case_types)]

use libc;

pub type gboolean       = libc::c_int;
pub type gchar          = libc::c_char;
pub type guchar         = libc::c_uchar;
pub type gint           = libc::c_int;
pub type guint          = libc::c_uint;
pub type glong          = libc::c_long;
pub type gulong         = libc::c_ulong;
pub type gsize          = libc::size_t;
pub type gssize         = libc::ssize_t;
pub type gfloat         = libc::c_float;
pub type gdouble        = libc::c_double;
pub type gpointer       = *mut   libc::c_void;
pub type gconstpointer  = *const libc::c_void;

pub const FALSE: gboolean = 0;
pub const TRUE : gboolean = 1;
<commit_msg>Rewritten the module comment as the doc comment<commit_after>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2013, 2014  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

//! This crate provides definitions for types that are intrinsic in
//! GObject introspection, unlike all other types that have a definition in
//! a GIR file. All crates generated from GObject introspection data should
//! use these shared definitions, usable in FFI declarations as well as
//! in idiomatic Rust bindings.
//!
//! Some types are omitted because a suitable equivalent is readily available
//! in Rust:
//!
//! 1. Fixed-size integer types. These have straightforward built-in
//!    counterparts in Rust.
//! 2. Strings can have GI types `utf8` or `filename`. In the FFI all string
//!    values are represented as raw pointers to `gchar`. A safe
//!    representation of C strings in idiomatic Rust bindings
//!    needs some wrapper types which are not defined here.

#![allow(non_camel_case_types)]

use libc;

pub type gboolean       = libc::c_int;
pub type gchar          = libc::c_char;
pub type guchar         = libc::c_uchar;
pub type gint           = libc::c_int;
pub type guint          = libc::c_uint;
pub type glong          = libc::c_long;
pub type gulong         = libc::c_ulong;
pub type gsize          = libc::size_t;
pub type gssize         = libc::ssize_t;
pub type gfloat         = libc::c_float;
pub type gdouble        = libc::c_double;
pub type gpointer       = *mut   libc::c_void;
pub type gconstpointer  = *const libc::c_void;

pub const FALSE: gboolean = 0;
pub const TRUE : gboolean = 1;
<|endoftext|>


<commit_before>use std::rc::{Rc};
use std::cell::{RefCell};
use std::collections::HashMap;

//is same identity
fn is_same<T>(lhs: &T, rhs: &T) -> bool {
    lhs as *const T == rhs as *const T
}

//the code below is horrible
//borrow doesn't return T, it returns Ref<T>
//we need to dereference it to get to the T inside
//is_same takes borrow so reapply the ampersand
fn is_same_subscriber<T: Subscriber>(lhs: Rc<RefCell<T>>, rhs: Rc<RefCell<T>>) -> bool {
    let lhs = lhs.clone();
    let rhs = rhs.clone();
    let res = is_same(&*lhs.borrow(), &*rhs.borrow()); //needed to live long enough
    res
}

pub trait Subscriber {
    fn new_message(&mut self, bytes: &[u8]);
}

pub struct Broker<T: Subscriber> {
    tree: Node<T>,
    use_cache: bool,
    cache: HashMap<String, Vec<Rc<RefCell<T>>>>,
}

struct Node<T: Subscriber> {
    children: HashMap<String, Node<T>>,
    leaves: Vec<Subscription<T>>,
}

struct Subscription<T: Subscriber> {
    subscriber: Rc<RefCell<T>>,
    topic: String,
}

impl<T: Subscriber> Subscription<T> {
    fn new(subscriber: Rc<RefCell<T>>, topic: &str) -> Self {
        Subscription { subscriber: subscriber.clone(), topic: topic.to_string() }
    }
}

impl<T: Subscriber> Node<T> {
    fn new() -> Self {
        Node { children: HashMap::new(), leaves: vec![] }
    }

    fn add_subscription(&mut self, subscription: Subscription<T>) {
        self.leaves.push(subscription);
    }
}

impl<T: Subscriber> Broker<T> {
    pub fn new(use_cache: bool) -> Self {
        Broker { tree: Node::new(), use_cache: use_cache, cache: HashMap::new() }
    }

    pub fn subscribe(&mut self, subscriber: Rc<RefCell<T>>, topic: &str) {
        self.invalidate_cache();
        let sub_parts : Vec<&str> = topic.split("/").collect();
        Self::ensure_node_exists(&sub_parts, &mut self.tree);
        Self::add_subscription_to_node(&mut self.tree, subscriber.clone(), &sub_parts, topic);
    }

    pub fn unsubscribe_all(&mut self, subscriber: Rc<RefCell<T>>) {
        self.invalidate_cache();
        Self::unsubscribe_impl(&mut self.tree, subscriber.clone(), &[], false);
    }

    pub fn unsubscribe(&mut self, subscriber: Rc<RefCell<T>>, topics: &[&str]) {
        self.invalidate_cache();
        Self::unsubscribe_impl(&mut self.tree, subscriber.clone(), topics, true);
    }

    pub fn publish(&mut self, topic: &str, payload: &[u8]) {
        let pub_parts : Vec<&str> = topic.split("/").collect();
        Self::publish_impl(&self.tree, &pub_parts, &payload, topic, self.use_cache, &mut self.cache);
    }

    fn ensure_node_exists(sub_parts: &[&str], node: &mut Node<T>) {
        if sub_parts.len() == 0 {
            return;
        }

        let part = &sub_parts[0][..];
        if !node.children.contains_key(part) {
            node.children.insert(sub_parts[0].to_string(), Node::new());
        }

        Self::ensure_node_exists(&sub_parts[1..], node.children.get_mut(part)
                                 .expect(&format!("Could not get node at {}", &part)));
    }

    fn add_subscription_to_node(tree: &mut Node<T>, subscriber: Rc<RefCell<T>>, sub_parts: &[&str], topic: &str) {
        if sub_parts.len() < 1 {
            panic!("oops");
        }

        let part = &sub_parts[0][..];
        let node = tree.children.get_mut(part)
            .expect(&format!("Could not get node at {}", &part));
        let sub_parts = &sub_parts[1..];

        if sub_parts.len() == 0 {
            node.add_subscription(Subscription::new(subscriber.clone(), topic));
        } else {
            Self::add_subscription_to_node(node, subscriber, sub_parts, topic);
        }
    }

    fn publish_impl(tree: &Node<T>, pub_parts: &[&str], payload: &[u8], topic: &str, use_cache: bool, cache: &mut HashMap<String, Vec<Rc<RefCell<T>>>>) {

        if use_cache {
            if let Some(subscribers) = cache.get(topic) {
                for subscriber in subscribers {
                    subscriber.borrow_mut().new_message(payload);
                }
                return;
            }
        }

        if pub_parts.len() < 1 {
            return;
        }

        let part = &pub_parts[0][..];
        let pub_parts = &pub_parts[1..];

        for part in vec![part, "#", "+"] {

            let node = tree.children.get(part);

            match node {
                None => {
                    continue; //didn't find a subscriber
                },
                Some(node) => {
                    //so that "finance/#" matches "finance"
                    if pub_parts.len() == 0 && node.children.contains_key("#") {
                        Self::publish_node(node.children.get("#")
                                           .expect(&format!("Could not get node at {}", &part)),
                                           payload, topic, use_cache, cache);
                    }

                    if pub_parts.len() == 0 || part == "#" {
                        Self::publish_node(&node, payload, topic, use_cache, cache);
                    }

                    Self::publish_impl(&node, pub_parts, payload, topic, use_cache, cache);
                }
            }
        }
    }

    fn publish_node(node: &Node<T>, payload: &[u8], topic: &str, use_cache: bool, cache: &mut HashMap<String, Vec<Rc<RefCell<T>>>>) {
        for subscription in &node.leaves {
            let subscriber = subscription.subscriber.clone();
            subscriber.borrow_mut().new_message(payload);
            if use_cache {
                if !cache.contains_key(topic) {
                    cache.insert(topic.to_string(), vec![]);
                }
                match cache.get_mut(topic) {
                    None => {
                        panic!("Impossible to not have key")
                    }
                    Some(subscribers) => {
                        subscribers.push(subscriber.clone());
                    }
                }
            }
        }
    }

    fn unsubscribe_impl(tree: &mut Node<T>, subscriber: Rc<RefCell<T>>, topics: &[&str], check_topics: bool) {
        tree.leaves.retain(|s| {
            let is_same_subscriber = is_same_subscriber(s.subscriber.clone(), subscriber.clone());
            //I have no idea why t below is &&&str, I added a tripe deref cos the compiler told me to
            let is_same_topic = !check_topics || topics.into_iter().find(|t| ***t == s.topic).is_some();
            !is_same_subscriber || !is_same_topic
        });

        if tree.children.len() == 0 {
            return;
        }

        for (_, node) in tree.children.iter_mut() {
            Self::unsubscribe_impl(node, subscriber.clone(), topics, check_topics);
        }
    }

    fn invalidate_cache(&mut self) {
        if self.use_cache {
            self.cache = HashMap::new();
        }
    }
}

#[cfg(test)]
struct TestSubscriber {
    msgs: Vec<Vec<u8>>,
}

#[cfg(test)]
impl TestSubscriber {
    fn new() -> Self {
        TestSubscriber{msgs: vec![]}
    }
}

#[cfg(test)]
impl Subscriber for TestSubscriber {
    fn new_message(&mut self, bytes: &[u8]) {
        self.msgs.push(bytes.to_vec());
    }
}

#[test]
fn test_subscribe() {
    let mut broker = Broker::<TestSubscriber>::new(false);
    let sub_rc = Rc::new(RefCell::new(TestSubscriber::new()));
    let subscriber = sub_rc.clone();
    broker.publish("topics/foo", &[0, 1, 2]);
    assert_eq!(subscriber.borrow().msgs.len(), 0);

    broker.subscribe(subscriber.clone(), "topics/foo");
    broker.publish("topics/foo", &[0, 1, 9]); //should get this
    broker.publish("topics/bar", &[2, 4, 6]); //shouldn't get this
    assert_eq!(subscriber.borrow().msgs.len(), 1);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);

    broker.subscribe(subscriber.clone(), "topics/bar");
    broker.publish("topics/foo", &[1, 3, 5, 7]);
    broker.publish("topics/bar", &[2, 4]);
    assert_eq!(subscriber.borrow().msgs.len(), 3);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);
    assert_eq!(subscriber.borrow().msgs[1], &[1, 3, 5, 7]);
    assert_eq!(subscriber.borrow().msgs[2], &[2, 4]);
}

#[test]
fn test_unsubscribe_all() {
    let mut broker = Broker::<TestSubscriber>::new(false);
    let sub_rc = Rc::new(RefCell::new(TestSubscriber::new()));
    let subscriber = sub_rc.clone();

    broker.subscribe(subscriber.clone(), "topics/foo");
    broker.publish("topics/foo", &[0, 1, 9]); //should get this
    broker.publish("topics/bar", &[2, 4, 6]); //shouldn't get this
    assert_eq!(subscriber.borrow().msgs.len(), 1);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);

    broker.unsubscribe_all(subscriber.clone());
    broker.publish("topics/foo", &[0, 1, 9]);
    broker.publish("topics/bar", &[2, 4]);
    broker.publish("topics/baz", &[2, 4, 7, 11]);

    //shouldn't have changed
    assert_eq!(subscriber.borrow().msgs.len(), 1);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);
}

#[test]
fn test_unsubscribe_one() {
    let mut broker = Broker::<TestSubscriber>::new(false);
    let sub_rc = Rc::new(RefCell::new(TestSubscriber::new()));
    let subscriber = sub_rc.clone();

    broker.subscribe(subscriber.clone(), "topics/foo");
    broker.subscribe(subscriber.clone(), "topics/bar");
    broker.publish("topics/foo", &[0, 1, 9]); //should get this
    broker.publish("topics/bar", &[2, 4]); //should get this
    broker.publish("topics/baz", &[2, 4, 7, 11]); //shouldn't get this
    assert_eq!(subscriber.borrow().msgs.len(), 2);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);
    assert_eq!(subscriber.borrow().msgs[1], &[2, 4]);

    broker.unsubscribe(subscriber.clone(), &["topics/foo"]);
    broker.publish("topics/foo", &[0, 1, 9]); //shouldn't get this
    broker.publish("topics/bar", &[2, 4]); //should get this
    broker.publish("topics/baz", &[2, 4, 7, 11]); //shouldn't get this

    assert_eq!(subscriber.borrow().msgs.len(), 3);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);
    assert_eq!(subscriber.borrow().msgs[1], &[2, 4]);
    assert_eq!(subscriber.borrow().msgs[2], &[2, 4]);
}

#[cfg(test)]
fn test_matches(pub_topic: &str, sub_topic: &str) -> bool {
    let mut broker = Broker::<TestSubscriber>::new(false);
    let sub_rc = Rc::new(RefCell::new(TestSubscriber::new()));
    let subscriber = sub_rc.clone();

    broker.subscribe(subscriber.clone(), sub_topic);
    broker.publish(pub_topic, &[0, 1, 2]);
    let subscriber = subscriber.borrow();
    subscriber.msgs.len() == 1
}

#[test]
fn test_wildcards() {
    assert_eq!(test_matches("foo/bar/baz", "foo/bar/baz"), true);
    assert_eq!(test_matches("foo/bar", "foo/+"), true);
    assert_eq!(test_matches("foo/baz", "foo/+"), true);
    assert_eq!(test_matches("foo/bar/baz", "foo/+"), false);
    assert_eq!(test_matches("foo/bar", "foo/#"), true);
    assert_eq!(test_matches("foo/bar/baz", "foo/#"), true);
    assert_eq!(test_matches("foo/bar/baz/boo", "foo/#"), true);
    assert_eq!(test_matches("foo/bla/bar/baz/boo/bogadog", "foo/+/bar/baz/#"), true);
    assert_eq!(test_matches("finance", "finance/#"), true);
    assert_eq!(test_matches("finance", "finance#"), false);
    assert_eq!(test_matches("finance", "#"), true);
    assert_eq!(test_matches("finance/stock", "#"), true);
    assert_eq!(test_matches("finance/stock", "finance/stock/ibm"), false);
    assert_eq!(test_matches("topics/foo/bar", "topics/foo/#"), true);
    assert_eq!(test_matches("topics/bar/baz/boo", "topics/foo/#"), false);
}

#[test]
fn test_subscribe_wildcards() {
    let mut broker = Broker::<TestSubscriber>::new(false);
    let sub_rc1 = Rc::new(RefCell::new(TestSubscriber::new()));
    let sub_rc2 = Rc::new(RefCell::new(TestSubscriber::new()));
    let sub_rc3 = Rc::new(RefCell::new(TestSubscriber::new()));
    let sub_rc4 = Rc::new(RefCell::new(TestSubscriber::new()));

    let subscriber1 = sub_rc1.clone();
    let subscriber2 = sub_rc2.clone();
    let subscriber3 = sub_rc3.clone();
    let subscriber4 = sub_rc4.clone();

    broker.subscribe(subscriber1.clone(), "topics/foo/+");
    broker.publish("topics/foo/bar", &[3]);
    broker.publish("topics/bar/baz/boo", &[4]); //shouldn't get this one
    assert_eq!(subscriber1.borrow().msgs, vec![&[3]]);

    broker.subscribe(subscriber2.clone(), "topics/foo/#");
    broker.publish("topics/foo/bar", &[3]);
    broker.publish("topics/bar/baz/boo", &[4]); //shouldn't get this one
    assert_eq!(subscriber1.borrow().msgs, vec![&[3], &[3]]);
    assert_eq!(subscriber2.borrow().msgs, vec![&[3]]);

    broker.subscribe(subscriber3.clone(), "topics/+/bar");
    broker.subscribe(subscriber4.clone(), "topics/#");

    broker.publish("topics/foo/bar", &[3]);
    broker.publish("topics/bar/baz/boo", &[4]);
    broker.publish("topics/boo/bar/zoo", &[5]);
    broker.publish("topics/foo/bar/zoo", &[6]);
    broker.publish("topics/bbobobobo/bar", &[7]);

    assert_eq!(subscriber1.borrow().msgs, vec![&[3], &[3], &[3]]);
    assert_eq!(subscriber2.borrow().msgs, vec![&[3], &[3], &[6]]);
    assert_eq!(subscriber3.borrow().msgs, vec![&[3], &[7]]);
    assert_eq!(subscriber4.borrow().msgs, vec![&[3], &[4], &[5], &[6], &[7]]);
}
<commit_msg>Refactoring<commit_after>use std::rc::{Rc};
use std::cell::{RefCell};
use std::collections::HashMap;

//is same identity
fn is_same<T>(lhs: &T, rhs: &T) -> bool {
    lhs as *const T == rhs as *const T
}

//the code below is horrible
//borrow doesn't return T, it returns Ref<T>
//we need to dereference it to get to the T inside
//is_same takes borrow so reapply the ampersand
fn is_same_subscriber<T: Subscriber>(lhs: Rc<RefCell<T>>, rhs: Rc<RefCell<T>>) -> bool {
    let lhs = lhs.clone();
    let rhs = rhs.clone();
    let res = is_same(&*lhs.borrow(), &*rhs.borrow()); //needed to live long enough
    res
}

pub trait Subscriber {
    fn new_message(&mut self, bytes: &[u8]);
}

pub struct Broker<T: Subscriber> {
    tree: Node<T>,
    use_cache: bool,
    cache: HashMap<String, Vec<Rc<RefCell<T>>>>,
}

struct Node<T: Subscriber> {
    children: HashMap<String, Node<T>>,
    leaves: Vec<Subscription<T>>,
}

struct Subscription<T: Subscriber> {
    subscriber: Rc<RefCell<T>>,
    topic: String,
}

impl<T: Subscriber> Subscription<T> {
    fn new(subscriber: Rc<RefCell<T>>, topic: &str) -> Self {
        Subscription { subscriber: subscriber.clone(), topic: topic.to_string() }
    }
}

impl<T: Subscriber> Node<T> {
    fn new() -> Self {
        Node { children: HashMap::new(), leaves: vec![] }
    }

    fn add_subscription(&mut self, subscription: Subscription<T>) {
        self.leaves.push(subscription);
    }
}

impl<T: Subscriber> Broker<T> {
    pub fn new(use_cache: bool) -> Self {
        Broker { tree: Node::new(), use_cache: use_cache, cache: HashMap::new() }
    }

    pub fn subscribe(&mut self, subscriber: Rc<RefCell<T>>, topic: &str) {
        self.invalidate_cache();
        let sub_parts : Vec<&str> = topic.split("/").collect();
        Self::ensure_node_exists(&sub_parts, &mut self.tree);
        Self::add_subscription_to_node(&mut self.tree, subscriber.clone(), &sub_parts, topic);
    }

    pub fn unsubscribe_all(&mut self, subscriber: Rc<RefCell<T>>) {
        self.invalidate_cache();
        Self::unsubscribe_impl(&mut self.tree, subscriber.clone(), &[], false);
    }

    pub fn unsubscribe(&mut self, subscriber: Rc<RefCell<T>>, topics: &[&str]) {
        self.invalidate_cache();
        Self::unsubscribe_impl(&mut self.tree, subscriber.clone(), topics, true);
    }

    pub fn publish(&mut self, topic: &str, payload: &[u8]) {
        let pub_parts : Vec<&str> = topic.split("/").collect();
        Self::publish_impl(&self.tree, &pub_parts, &payload, topic, self.use_cache, &mut self.cache);
    }

    fn ensure_node_exists(sub_parts: &[&str], node: &mut Node<T>) {
        if sub_parts.len() == 0 {
            return;
        }

        let part = &sub_parts[0][..];
        if !node.children.contains_key(part) {
            node.children.insert(sub_parts[0].to_string(), Node::new());
        }

        Self::ensure_node_exists(&sub_parts[1..], node.children.get_mut(part)
                                 .expect(&format!("Could not get node at {}", &part)));
    }

    fn add_subscription_to_node(tree: &mut Node<T>, subscriber: Rc<RefCell<T>>, sub_parts: &[&str], topic: &str) {
        if sub_parts.len() < 1 {
            panic!("oops");
        }

        let part = &sub_parts[0][..];
        let node = tree.children.get_mut(part)
            .expect(&format!("Could not get node at {}", &part));
        let sub_parts = &sub_parts[1..];

        if sub_parts.len() == 0 {
            node.add_subscription(Subscription::new(subscriber.clone(), topic));
        } else {
            Self::add_subscription_to_node(node, subscriber, sub_parts, topic);
        }
    }

    fn publish_impl(tree: &Node<T>, pub_parts: &[&str], payload: &[u8], topic: &str, use_cache: bool, cache: &mut HashMap<String, Vec<Rc<RefCell<T>>>>) {

        if use_cache {
            if let Some(subscribers) = cache.get(topic) {
                for subscriber in subscribers {
                    subscriber.borrow_mut().new_message(payload);
                }
                return;
            }
        }

        if pub_parts.len() < 1 {
            return;
        }

        let part = &pub_parts[0][..];
        let pub_parts = &pub_parts[1..];

        for part in vec![part, "#", "+"] {

            if let Some(node) = tree.children.get(part) {
                if pub_parts.len() == 0 || part == "#" {
                    Self::publish_node(&node, payload, topic, use_cache, cache);
                }

                //so that "finance/#" matches "finance"
                if pub_parts.len() == 0 && node.children.contains_key("#") {
                    Self::publish_node(node.children.get("#")
                                       .expect(&format!("Could not get node at {}", &part)),
                                       payload, topic, use_cache, cache);
                }

                Self::publish_impl(&node, pub_parts, payload, topic, use_cache, cache);
            }
        }
    }

    fn publish_node(node: &Node<T>, payload: &[u8], topic: &str, use_cache: bool, cache: &mut HashMap<String, Vec<Rc<RefCell<T>>>>) {
        for subscription in &node.leaves {
            let subscriber = subscription.subscriber.clone();
            subscriber.borrow_mut().new_message(payload);
            if use_cache {
                if !cache.contains_key(topic) {
                    cache.insert(topic.to_string(), vec![]);
                }
                if let Some(subscribers) = cache.get_mut(topic) {
                    subscribers.push(subscriber.clone());
                }
            }
        }
    }

    fn unsubscribe_impl(tree: &mut Node<T>, subscriber: Rc<RefCell<T>>, topics: &[&str], check_topics: bool) {
        tree.leaves.retain(|s| {
            let is_same_subscriber = is_same_subscriber(s.subscriber.clone(), subscriber.clone());
            //I have no idea why t below is &&&str, I added a tripe deref cos the compiler told me to
            let is_same_topic = !check_topics || topics.into_iter().find(|t| ***t == s.topic).is_some();
            !is_same_subscriber || !is_same_topic
        });

        if tree.children.len() == 0 {
            return;
        }

        for (_, node) in tree.children.iter_mut() {
            Self::unsubscribe_impl(node, subscriber.clone(), topics, check_topics);
        }
    }

    fn invalidate_cache(&mut self) {
        if self.use_cache {
            self.cache = HashMap::new();
        }
    }
}

#[cfg(test)]
struct TestSubscriber {
    msgs: Vec<Vec<u8>>,
}

#[cfg(test)]
impl TestSubscriber {
    fn new() -> Self {
        TestSubscriber{msgs: vec![]}
    }
}

#[cfg(test)]
impl Subscriber for TestSubscriber {
    fn new_message(&mut self, bytes: &[u8]) {
        self.msgs.push(bytes.to_vec());
    }
}

#[test]
fn test_subscribe() {
    let mut broker = Broker::<TestSubscriber>::new(false);
    let sub_rc = Rc::new(RefCell::new(TestSubscriber::new()));
    let subscriber = sub_rc.clone();
    broker.publish("topics/foo", &[0, 1, 2]);
    assert_eq!(subscriber.borrow().msgs.len(), 0);

    broker.subscribe(subscriber.clone(), "topics/foo");
    broker.publish("topics/foo", &[0, 1, 9]); //should get this
    broker.publish("topics/bar", &[2, 4, 6]); //shouldn't get this
    assert_eq!(subscriber.borrow().msgs.len(), 1);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);

    broker.subscribe(subscriber.clone(), "topics/bar");
    broker.publish("topics/foo", &[1, 3, 5, 7]);
    broker.publish("topics/bar", &[2, 4]);
    assert_eq!(subscriber.borrow().msgs.len(), 3);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);
    assert_eq!(subscriber.borrow().msgs[1], &[1, 3, 5, 7]);
    assert_eq!(subscriber.borrow().msgs[2], &[2, 4]);
}

#[test]
fn test_unsubscribe_all() {
    let mut broker = Broker::<TestSubscriber>::new(false);
    let sub_rc = Rc::new(RefCell::new(TestSubscriber::new()));
    let subscriber = sub_rc.clone();

    broker.subscribe(subscriber.clone(), "topics/foo");
    broker.publish("topics/foo", &[0, 1, 9]); //should get this
    broker.publish("topics/bar", &[2, 4, 6]); //shouldn't get this
    assert_eq!(subscriber.borrow().msgs.len(), 1);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);

    broker.unsubscribe_all(subscriber.clone());
    broker.publish("topics/foo", &[0, 1, 9]);
    broker.publish("topics/bar", &[2, 4]);
    broker.publish("topics/baz", &[2, 4, 7, 11]);

    //shouldn't have changed
    assert_eq!(subscriber.borrow().msgs.len(), 1);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);
}

#[test]
fn test_unsubscribe_one() {
    let mut broker = Broker::<TestSubscriber>::new(false);
    let sub_rc = Rc::new(RefCell::new(TestSubscriber::new()));
    let subscriber = sub_rc.clone();

    broker.subscribe(subscriber.clone(), "topics/foo");
    broker.subscribe(subscriber.clone(), "topics/bar");
    broker.publish("topics/foo", &[0, 1, 9]); //should get this
    broker.publish("topics/bar", &[2, 4]); //should get this
    broker.publish("topics/baz", &[2, 4, 7, 11]); //shouldn't get this
    assert_eq!(subscriber.borrow().msgs.len(), 2);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);
    assert_eq!(subscriber.borrow().msgs[1], &[2, 4]);

    broker.unsubscribe(subscriber.clone(), &["topics/foo"]);
    broker.publish("topics/foo", &[0, 1, 9]); //shouldn't get this
    broker.publish("topics/bar", &[2, 4]); //should get this
    broker.publish("topics/baz", &[2, 4, 7, 11]); //shouldn't get this

    assert_eq!(subscriber.borrow().msgs.len(), 3);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);
    assert_eq!(subscriber.borrow().msgs[1], &[2, 4]);
    assert_eq!(subscriber.borrow().msgs[2], &[2, 4]);
}

#[cfg(test)]
fn test_matches(pub_topic: &str, sub_topic: &str) -> bool {
    let mut broker = Broker::<TestSubscriber>::new(false);
    let sub_rc = Rc::new(RefCell::new(TestSubscriber::new()));
    let subscriber = sub_rc.clone();

    broker.subscribe(subscriber.clone(), sub_topic);
    broker.publish(pub_topic, &[0, 1, 2]);
    let subscriber = subscriber.borrow();
    subscriber.msgs.len() == 1
}

#[test]
fn test_wildcards() {
    assert_eq!(test_matches("foo/bar/baz", "foo/bar/baz"), true);
    assert_eq!(test_matches("foo/bar", "foo/+"), true);
    assert_eq!(test_matches("foo/baz", "foo/+"), true);
    assert_eq!(test_matches("foo/bar/baz", "foo/+"), false);
    assert_eq!(test_matches("foo/bar", "foo/#"), true);
    assert_eq!(test_matches("foo/bar/baz", "foo/#"), true);
    assert_eq!(test_matches("foo/bar/baz/boo", "foo/#"), true);
    assert_eq!(test_matches("foo/bla/bar/baz/boo/bogadog", "foo/+/bar/baz/#"), true);
    assert_eq!(test_matches("finance", "finance/#"), true);
    assert_eq!(test_matches("finance", "finance#"), false);
    assert_eq!(test_matches("finance", "#"), true);
    assert_eq!(test_matches("finance/stock", "#"), true);
    assert_eq!(test_matches("finance/stock", "finance/stock/ibm"), false);
    assert_eq!(test_matches("topics/foo/bar", "topics/foo/#"), true);
    assert_eq!(test_matches("topics/bar/baz/boo", "topics/foo/#"), false);
}

#[test]
fn test_subscribe_wildcards() {
    let mut broker = Broker::<TestSubscriber>::new(false);
    let sub_rc1 = Rc::new(RefCell::new(TestSubscriber::new()));
    let sub_rc2 = Rc::new(RefCell::new(TestSubscriber::new()));
    let sub_rc3 = Rc::new(RefCell::new(TestSubscriber::new()));
    let sub_rc4 = Rc::new(RefCell::new(TestSubscriber::new()));

    let subscriber1 = sub_rc1.clone();
    let subscriber2 = sub_rc2.clone();
    let subscriber3 = sub_rc3.clone();
    let subscriber4 = sub_rc4.clone();

    broker.subscribe(subscriber1.clone(), "topics/foo/+");
    broker.publish("topics/foo/bar", &[3]);
    broker.publish("topics/bar/baz/boo", &[4]); //shouldn't get this one
    assert_eq!(subscriber1.borrow().msgs, vec![&[3]]);

    broker.subscribe(subscriber2.clone(), "topics/foo/#");
    broker.publish("topics/foo/bar", &[3]);
    broker.publish("topics/bar/baz/boo", &[4]); //shouldn't get this one
    assert_eq!(subscriber1.borrow().msgs, vec![&[3], &[3]]);
    assert_eq!(subscriber2.borrow().msgs, vec![&[3]]);

    broker.subscribe(subscriber3.clone(), "topics/+/bar");
    broker.subscribe(subscriber4.clone(), "topics/#");

    broker.publish("topics/foo/bar", &[3]);
    broker.publish("topics/bar/baz/boo", &[4]);
    broker.publish("topics/boo/bar/zoo", &[5]);
    broker.publish("topics/foo/bar/zoo", &[6]);
    broker.publish("topics/bbobobobo/bar", &[7]);

    assert_eq!(subscriber1.borrow().msgs, vec![&[3], &[3], &[3]]);
    assert_eq!(subscriber2.borrow().msgs, vec![&[3], &[3], &[6]]);
    assert_eq!(subscriber3.borrow().msgs, vec![&[3], &[7]]);
    assert_eq!(subscriber4.borrow().msgs, vec![&[3], &[4], &[5], &[6], &[7]]);
}
<|endoftext|>