<commit_before>// Copyright 2016 TiKV Project Authors. Licensed under Apache-2.0.

use std::fmt;
use std::time::Instant;

use engine_rocks::{RocksEngine, RocksSnapshot};
use engine_traits::{KvEngine, Snapshot};
use kvproto::import_sstpb::SstMeta;
use kvproto::metapb;
use kvproto::metapb::RegionEpoch;
use kvproto::pdpb::CheckPolicy;
use kvproto::raft_cmdpb::{RaftCmdRequest, RaftCmdResponse};
use kvproto::raft_serverpb::RaftMessage;
use kvproto::replication_modepb::ReplicationStatus;
use raft::SnapshotStatus;

use crate::store::fsm::apply::TaskRes as ApplyTaskRes;
use crate::store::fsm::apply::{CatchUpLogs, ChangeCmd};
use crate::store::fsm::PeerFsm;
use crate::store::metrics::RaftEventDurationType;
use crate::store::util::KeysInfoFormatter;
use crate::store::SnapKey;
use engine_rocks::CompactedEvent;
use tikv_util::escape;

use super::RegionSnapshot;

#[derive(Debug)]
pub struct ReadResponse<S: Snapshot> {
    pub response: RaftCmdResponse,
    pub snapshot: Option<RegionSnapshot<S>>,
}

#[derive(Debug)]
pub struct WriteResponse {
    pub response: RaftCmdResponse,
}

// This is only necessary because of seeming limitations in derive(Clone) w/r/t
// generics. If it can be deleted in the future in favor of derive, it should
// be.
impl<S> Clone for ReadResponse<S>
where
    S: Snapshot,
{
    fn clone(&self) -> ReadResponse<S> {
        ReadResponse {
            response: self.response.clone(),
            snapshot: self.snapshot.clone(),
        }
    }
}

pub type ReadCallback<S> = Box<dyn FnOnce(ReadResponse<S>) + Send>;
pub type WriteCallback = Box<dyn FnOnce(WriteResponse) + Send>;

/// Variants of callbacks for `Msg`.
///  - `Read`: a callbak for read only requests including `StatusRequest`,
///         `GetRequest` and `SnapRequest`
///  - `Write`: a callback for write only requests including `AdminRequest`
///          `PutRequest`, `DeleteRequest` and `DeleteRangeRequest`.
pub enum Callback<S: Snapshot> {
    /// No callback.
    None,
    /// Read callback.
    Read(ReadCallback<S>),
    /// Write callback.
    Write(WriteCallback),
}

impl<S> Callback<S>
where
    S: Snapshot,
{
    pub fn invoke_with_response(self, resp: RaftCmdResponse) {
        match self {
            Callback::None => (),
            Callback::Read(read) => {
                let resp = ReadResponse {
                    response: resp,
                    snapshot: None,
                };
                read(resp);
            }
            Callback::Write(write) => {
                let resp = WriteResponse { response: resp };
                write(resp);
            }
        }
    }

    pub fn invoke_read(self, args: ReadResponse<S>) {
        match self {
            Callback::Read(read) => read(args),
            other => panic!("expect Callback::Read(..), got {:?}", other),
        }
    }

    pub fn is_none(&self) -> bool {
        match self {
            Callback::None => true,
            _ => false,
        }
    }
}

impl<S> fmt::Debug for Callback<S>
where
    S: Snapshot,
{
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            Callback::None => write!(fmt, "Callback::None"),
            Callback::Read(_) => write!(fmt, "Callback::Read(..)"),
            Callback::Write(_) => write!(fmt, "Callback::Write(..)"),
        }
    }
}

bitflags! {
    pub struct PeerTicks: u8 {
        const RAFT                   = 0b00000001;
        const RAFT_LOG_GC            = 0b00000010;
        const SPLIT_REGION_CHECK     = 0b00000100;
        const PD_HEARTBEAT           = 0b00001000;
        const CHECK_MERGE            = 0b00010000;
        const CHECK_PEER_STALE_STATE = 0b00100000;
    }
}

impl PeerTicks {
    #[inline]
    pub fn tag(self) -> &'static str {
        match self {
            PeerTicks::RAFT => "raft",
            PeerTicks::RAFT_LOG_GC => "raft_log_gc",
            PeerTicks::SPLIT_REGION_CHECK => "split_region_check",
            PeerTicks::PD_HEARTBEAT => "pd_heartbeat",
            PeerTicks::CHECK_MERGE => "check_merge",
            PeerTicks::CHECK_PEER_STALE_STATE => "check_peer_stale_state",
            _ => unreachable!(),
        }
    }
}

#[derive(Debug, Clone, Copy)]
pub enum StoreTick {
    CompactCheck,
    PdStoreHeartbeat,
    SnapGc,
    CompactLockCf,
    ConsistencyCheck,
    CleanupImportSST,
}

impl StoreTick {
    #[inline]
    pub fn tag(self) -> RaftEventDurationType {
        match self {
            StoreTick::CompactCheck => RaftEventDurationType::compact_check,
            StoreTick::PdStoreHeartbeat => RaftEventDurationType::pd_store_heartbeat,
            StoreTick::SnapGc => RaftEventDurationType::snap_gc,
            StoreTick::CompactLockCf => RaftEventDurationType::compact_lock_cf,
            StoreTick::ConsistencyCheck => RaftEventDurationType::consistency_check,
            StoreTick::CleanupImportSST => RaftEventDurationType::cleanup_import_sst,
        }
    }
}

/// Some significant messages sent to raftstore. Raftstore will dispatch these messages to Raft
/// groups to update some important internal status.
#[derive(Debug)]
pub enum SignificantMsg {
    /// Reports whether the snapshot sending is successful or not.
    SnapshotStatus {
        region_id: u64,
        to_peer_id: u64,
        status: SnapshotStatus,
    },
    StoreUnreachable {
        store_id: u64,
    },
    /// Reports `to_peer_id` is unreachable.
    Unreachable {
        region_id: u64,
        to_peer_id: u64,
    },
    /// Source region catch up logs for merging
    CatchUpLogs(CatchUpLogs),
    /// Result of the fact that the region is merged.
    MergeResult {
        target: metapb::Peer,
        // True means it's a stale merge source.
        // False means it came from target region.
        stale: bool,
    },
    StoreResolved {
        store_id: u64,
        group_id: u64,
    },
    /// Capture the changes of the region.
    CaptureChange {
        cmd: ChangeCmd,
        region_epoch: RegionEpoch,
        callback: Callback<RocksSnapshot>,
    },
    LeaderCallback(Callback<RocksSnapshot>),
}

/// Message that will be sent to a peer.
///
/// These messages are not significant and can be dropped occasionally.
pub enum CasualMessage<E: KvEngine> {
    /// Split the target region into several partitions.
    SplitRegion {
        region_epoch: RegionEpoch,
        // It's an encoded key.
        // TODO: support meta key.
        split_keys: Vec<Vec<u8>>,
        callback: Callback<E::Snapshot>,
    },

    /// Hash result of ComputeHash command.
    ComputeHashResult {
        index: u64,
        hash: Vec<u8>,
    },

    /// Approximate size of target region.
    RegionApproximateSize {
        size: u64,
    },

    /// Approximate key count of target region.
    RegionApproximateKeys {
        keys: u64,
    },
    CompactionDeclinedBytes {
        bytes: u64,
    },
    /// Half split the target region.
    HalfSplitRegion {
        region_epoch: RegionEpoch,
        policy: CheckPolicy,
    },
    /// Remove snapshot files in `snaps`.
    GcSnap {
        snaps: Vec<(SnapKey, bool)>,
    },
    /// Clear region size cache.
    ClearRegionSize,
    /// Indicate a target region is overlapped.
    RegionOverlapped,
    /// Notifies that a new snapshot has been generated.
    SnapshotGenerated,

    /// A message to access peer's internal state.
    AccessPeer(Box<dyn FnOnce(&mut PeerFsm<E>) + Send + 'static>),
}

impl<E: KvEngine> fmt::Debug for CasualMessage<E> {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            CasualMessage::ComputeHashResult { index, ref hash } => write!(
                fmt,
                "ComputeHashResult [index: {}, hash: {}]",
                index,
                escape(hash)
            ),
            CasualMessage::SplitRegion { ref split_keys, .. } => write!(
                fmt,
                "Split region with {}",
                KeysInfoFormatter(split_keys.iter())
            ),
            CasualMessage::RegionApproximateSize { size } => {
                write!(fmt, "Region's approximate size [size: {:?}]", size)
            }
            CasualMessage::RegionApproximateKeys { keys } => {
                write!(fmt, "Region's approximate keys [keys: {:?}]", keys)
            }
            CasualMessage::CompactionDeclinedBytes { bytes } => {
                write!(fmt, "compaction declined bytes {}", bytes)
            }
            CasualMessage::HalfSplitRegion { .. } => write!(fmt, "Half Split"),
            CasualMessage::GcSnap { ref snaps } => write! {
                fmt,
                "gc snaps {:?}",
                snaps
            },
            CasualMessage::ClearRegionSize => write! {
                fmt,
                "clear region size"
            },
            CasualMessage::RegionOverlapped => write!(fmt, "RegionOverlapped"),
            CasualMessage::SnapshotGenerated => write!(fmt, "SnapshotGenerated"),
            CasualMessage::AccessPeer(_) => write!(fmt, "AccessPeer"),
        }
    }
}

/// Raft command is the command that is expected to be proposed by the
/// leader of the target raft group.
#[derive(Debug)]
pub struct RaftCommand<S: Snapshot> {
    pub send_time: Instant,
    pub request: RaftCmdRequest,
    pub callback: Callback<S>,
}

impl<S: Snapshot> RaftCommand<S> {
    #[inline]
    pub fn new(request: RaftCmdRequest, callback: Callback<S>) -> RaftCommand<S> {
        RaftCommand {
            request,
            callback,
            send_time: Instant::now(),
        }
    }
}

/// Message that can be sent to a peer.
pub enum PeerMsg<E: KvEngine> {
    /// Raft message is the message sent between raft nodes in the same
    /// raft group. Messages need to be redirected to raftstore if target
    /// peer doesn't exist.
    RaftMessage(RaftMessage),
    /// Raft command is the command that is expected to be proposed by the
    /// leader of the target raft group. If it's failed to be sent, callback
    /// usually needs to be called before dropping in case of resource leak.
    RaftCommand(RaftCommand<E::Snapshot>),
    /// Tick is periodical task. If target peer doesn't exist there is a potential
    /// that the raft node will not work anymore.
    Tick(PeerTicks),
    /// Result of applying committed entries. The message can't be lost.
    ApplyRes { res: ApplyTaskRes<E> },
    /// Message that can't be lost but rarely created. If they are lost, real bad
    /// things happen like some peers will be considered dead in the group.
    SignificantMsg(SignificantMsg),
    /// Start the FSM.
    Start,
    /// A message only used to notify a peer.
    Noop,
    /// Message that is not important and can be dropped occasionally.
    CasualMessage(CasualMessage<E>),
    /// Ask region to report a heartbeat to PD.
    HeartbeatPd,
    /// Asks region to change replication mode.
    UpdateReplicationMode,
}

impl<E: KvEngine> fmt::Debug for PeerMsg<E> {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            PeerMsg::RaftMessage(_) => write!(fmt, "Raft Message"),
            PeerMsg::RaftCommand(_) => write!(fmt, "Raft Command"),
            PeerMsg::Tick(tick) => write! {
                fmt,
                "{:?}",
                tick
            },
            PeerMsg::SignificantMsg(msg) => write!(fmt, "{:?}", msg),
            PeerMsg::ApplyRes { res } => write!(fmt, "ApplyRes {:?}", res),
            PeerMsg::Start => write!(fmt, "Startup"),
            PeerMsg::Noop => write!(fmt, "Noop"),
            PeerMsg::CasualMessage(msg) => write!(fmt, "CasualMessage {:?}", msg),
            PeerMsg::HeartbeatPd => write!(fmt, "HeartbeatPd"),
            PeerMsg::UpdateReplicationMode => write!(fmt, "UpdateReplicationMode"),
        }
    }
}

pub enum StoreMsg {
    RaftMessage(RaftMessage),
    // For snapshot stats.
    SnapshotStats,

    ValidateSSTResult {
        invalid_ssts: Vec<SstMeta>,
    },

    // Clear region size and keys for all regions in the range, so we can force them to re-calculate
    // their size later.
    ClearRegionSizeInRange {
        start_key: Vec<u8>,
        end_key: Vec<u8>,
    },
    StoreUnreachable {
        store_id: u64,
    },

    // Compaction finished event
    CompactedEvent(CompactedEvent),
    Tick(StoreTick),
    Start {
        store: metapb::Store,
    },

    /// Messge only used for test
    #[cfg(any(test, feature = "testexport"))]
    Validate(Box<dyn FnOnce(&crate::store::Config) + Send>),
    /// Asks the store to update replication mode.
    UpdateReplicationMode(ReplicationStatus),
}

impl fmt::Debug for StoreMsg {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            StoreMsg::RaftMessage(_) => write!(fmt, "Raft Message"),
            StoreMsg::SnapshotStats => write!(fmt, "Snapshot stats"),
            StoreMsg::StoreUnreachable { store_id } => {
                write!(fmt, "Store {}  is unreachable", store_id)
            }
            StoreMsg::CompactedEvent(ref event) => write!(fmt, "CompactedEvent cf {}", event.cf),
            StoreMsg::ValidateSSTResult { .. } => write!(fmt, "Validate SST Result"),
            StoreMsg::ClearRegionSizeInRange {
                ref start_key,
                ref end_key,
            } => write!(
                fmt,
                "Clear Region size in range {:?} to {:?}",
                start_key, end_key
            ),
            StoreMsg::Tick(tick) => write!(fmt, "StoreTick {:?}", tick),
            StoreMsg::Start { ref store } => write!(fmt, "Start store {:?}", store),
            #[cfg(any(test, feature = "testexport"))]
            StoreMsg::Validate(_) => write!(fmt, "Validate config"),
            StoreMsg::UpdateReplicationMode(_) => write!(fmt, "UpdateReplicationMode"),
        }
    }
}

// TODO: remove this enum and utilize the actual message instead.
#[derive(Debug)]
pub enum Msg {
    PeerMsg(PeerMsg<RocksEngine>),
    StoreMsg(StoreMsg),
}
<commit_msg>raftstore: fix typo and remove useless msg enum (#7862)<commit_after>// Copyright 2016 TiKV Project Authors. Licensed under Apache-2.0.

use std::fmt;
use std::time::Instant;

use engine_rocks::RocksSnapshot;
use engine_traits::{KvEngine, Snapshot};
use kvproto::import_sstpb::SstMeta;
use kvproto::metapb;
use kvproto::metapb::RegionEpoch;
use kvproto::pdpb::CheckPolicy;
use kvproto::raft_cmdpb::{RaftCmdRequest, RaftCmdResponse};
use kvproto::raft_serverpb::RaftMessage;
use kvproto::replication_modepb::ReplicationStatus;
use raft::SnapshotStatus;

use crate::store::fsm::apply::TaskRes as ApplyTaskRes;
use crate::store::fsm::apply::{CatchUpLogs, ChangeCmd};
use crate::store::fsm::PeerFsm;
use crate::store::metrics::RaftEventDurationType;
use crate::store::util::KeysInfoFormatter;
use crate::store::SnapKey;
use engine_rocks::CompactedEvent;
use tikv_util::escape;

use super::RegionSnapshot;

#[derive(Debug)]
pub struct ReadResponse<S: Snapshot> {
    pub response: RaftCmdResponse,
    pub snapshot: Option<RegionSnapshot<S>>,
}

#[derive(Debug)]
pub struct WriteResponse {
    pub response: RaftCmdResponse,
}

// This is only necessary because of seeming limitations in derive(Clone) w/r/t
// generics. If it can be deleted in the future in favor of derive, it should
// be.
impl<S> Clone for ReadResponse<S>
where
    S: Snapshot,
{
    fn clone(&self) -> ReadResponse<S> {
        ReadResponse {
            response: self.response.clone(),
            snapshot: self.snapshot.clone(),
        }
    }
}

pub type ReadCallback<S> = Box<dyn FnOnce(ReadResponse<S>) + Send>;
pub type WriteCallback = Box<dyn FnOnce(WriteResponse) + Send>;

/// Variants of callbacks for `Msg`.
///  - `Read`: a callback for read only requests including `StatusRequest`,
///         `GetRequest` and `SnapRequest`
///  - `Write`: a callback for write only requests including `AdminRequest`
///          `PutRequest`, `DeleteRequest` and `DeleteRangeRequest`.
pub enum Callback<S: Snapshot> {
    /// No callback.
    None,
    /// Read callback.
    Read(ReadCallback<S>),
    /// Write callback.
    Write(WriteCallback),
}

impl<S> Callback<S>
where
    S: Snapshot,
{
    pub fn invoke_with_response(self, resp: RaftCmdResponse) {
        match self {
            Callback::None => (),
            Callback::Read(read) => {
                let resp = ReadResponse {
                    response: resp,
                    snapshot: None,
                };
                read(resp);
            }
            Callback::Write(write) => {
                let resp = WriteResponse { response: resp };
                write(resp);
            }
        }
    }

    pub fn invoke_read(self, args: ReadResponse<S>) {
        match self {
            Callback::Read(read) => read(args),
            other => panic!("expect Callback::Read(..), got {:?}", other),
        }
    }

    pub fn is_none(&self) -> bool {
        match self {
            Callback::None => true,
            _ => false,
        }
    }
}

impl<S> fmt::Debug for Callback<S>
where
    S: Snapshot,
{
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            Callback::None => write!(fmt, "Callback::None"),
            Callback::Read(_) => write!(fmt, "Callback::Read(..)"),
            Callback::Write(_) => write!(fmt, "Callback::Write(..)"),
        }
    }
}

bitflags! {
    pub struct PeerTicks: u8 {
        const RAFT                   = 0b00000001;
        const RAFT_LOG_GC            = 0b00000010;
        const SPLIT_REGION_CHECK     = 0b00000100;
        const PD_HEARTBEAT           = 0b00001000;
        const CHECK_MERGE            = 0b00010000;
        const CHECK_PEER_STALE_STATE = 0b00100000;
    }
}

impl PeerTicks {
    #[inline]
    pub fn tag(self) -> &'static str {
        match self {
            PeerTicks::RAFT => "raft",
            PeerTicks::RAFT_LOG_GC => "raft_log_gc",
            PeerTicks::SPLIT_REGION_CHECK => "split_region_check",
            PeerTicks::PD_HEARTBEAT => "pd_heartbeat",
            PeerTicks::CHECK_MERGE => "check_merge",
            PeerTicks::CHECK_PEER_STALE_STATE => "check_peer_stale_state",
            _ => unreachable!(),
        }
    }
}

#[derive(Debug, Clone, Copy)]
pub enum StoreTick {
    CompactCheck,
    PdStoreHeartbeat,
    SnapGc,
    CompactLockCf,
    ConsistencyCheck,
    CleanupImportSST,
}

impl StoreTick {
    #[inline]
    pub fn tag(self) -> RaftEventDurationType {
        match self {
            StoreTick::CompactCheck => RaftEventDurationType::compact_check,
            StoreTick::PdStoreHeartbeat => RaftEventDurationType::pd_store_heartbeat,
            StoreTick::SnapGc => RaftEventDurationType::snap_gc,
            StoreTick::CompactLockCf => RaftEventDurationType::compact_lock_cf,
            StoreTick::ConsistencyCheck => RaftEventDurationType::consistency_check,
            StoreTick::CleanupImportSST => RaftEventDurationType::cleanup_import_sst,
        }
    }
}

/// Some significant messages sent to raftstore. Raftstore will dispatch these messages to Raft
/// groups to update some important internal status.
#[derive(Debug)]
pub enum SignificantMsg {
    /// Reports whether the snapshot sending is successful or not.
    SnapshotStatus {
        region_id: u64,
        to_peer_id: u64,
        status: SnapshotStatus,
    },
    StoreUnreachable {
        store_id: u64,
    },
    /// Reports `to_peer_id` is unreachable.
    Unreachable {
        region_id: u64,
        to_peer_id: u64,
    },
    /// Source region catch up logs for merging
    CatchUpLogs(CatchUpLogs),
    /// Result of the fact that the region is merged.
    MergeResult {
        target: metapb::Peer,
        // True means it's a stale merge source.
        // False means it came from target region.
        stale: bool,
    },
    StoreResolved {
        store_id: u64,
        group_id: u64,
    },
    /// Capture the changes of the region.
    CaptureChange {
        cmd: ChangeCmd,
        region_epoch: RegionEpoch,
        callback: Callback<RocksSnapshot>,
    },
    LeaderCallback(Callback<RocksSnapshot>),
}

/// Message that will be sent to a peer.
///
/// These messages are not significant and can be dropped occasionally.
pub enum CasualMessage<E: KvEngine> {
    /// Split the target region into several partitions.
    SplitRegion {
        region_epoch: RegionEpoch,
        // It's an encoded key.
        // TODO: support meta key.
        split_keys: Vec<Vec<u8>>,
        callback: Callback<E::Snapshot>,
    },

    /// Hash result of ComputeHash command.
    ComputeHashResult {
        index: u64,
        hash: Vec<u8>,
    },

    /// Approximate size of target region.
    RegionApproximateSize {
        size: u64,
    },

    /// Approximate key count of target region.
    RegionApproximateKeys {
        keys: u64,
    },
    CompactionDeclinedBytes {
        bytes: u64,
    },
    /// Half split the target region.
    HalfSplitRegion {
        region_epoch: RegionEpoch,
        policy: CheckPolicy,
    },
    /// Remove snapshot files in `snaps`.
    GcSnap {
        snaps: Vec<(SnapKey, bool)>,
    },
    /// Clear region size cache.
    ClearRegionSize,
    /// Indicate a target region is overlapped.
    RegionOverlapped,
    /// Notifies that a new snapshot has been generated.
    SnapshotGenerated,

    /// A message to access peer's internal state.
    AccessPeer(Box<dyn FnOnce(&mut PeerFsm<E>) + Send + 'static>),
}

impl<E: KvEngine> fmt::Debug for CasualMessage<E> {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            CasualMessage::ComputeHashResult { index, ref hash } => write!(
                fmt,
                "ComputeHashResult [index: {}, hash: {}]",
                index,
                escape(hash)
            ),
            CasualMessage::SplitRegion { ref split_keys, .. } => write!(
                fmt,
                "Split region with {}",
                KeysInfoFormatter(split_keys.iter())
            ),
            CasualMessage::RegionApproximateSize { size } => {
                write!(fmt, "Region's approximate size [size: {:?}]", size)
            }
            CasualMessage::RegionApproximateKeys { keys } => {
                write!(fmt, "Region's approximate keys [keys: {:?}]", keys)
            }
            CasualMessage::CompactionDeclinedBytes { bytes } => {
                write!(fmt, "compaction declined bytes {}", bytes)
            }
            CasualMessage::HalfSplitRegion { .. } => write!(fmt, "Half Split"),
            CasualMessage::GcSnap { ref snaps } => write! {
                fmt,
                "gc snaps {:?}",
                snaps
            },
            CasualMessage::ClearRegionSize => write! {
                fmt,
                "clear region size"
            },
            CasualMessage::RegionOverlapped => write!(fmt, "RegionOverlapped"),
            CasualMessage::SnapshotGenerated => write!(fmt, "SnapshotGenerated"),
            CasualMessage::AccessPeer(_) => write!(fmt, "AccessPeer"),
        }
    }
}

/// Raft command is the command that is expected to be proposed by the
/// leader of the target raft group.
#[derive(Debug)]
pub struct RaftCommand<S: Snapshot> {
    pub send_time: Instant,
    pub request: RaftCmdRequest,
    pub callback: Callback<S>,
}

impl<S: Snapshot> RaftCommand<S> {
    #[inline]
    pub fn new(request: RaftCmdRequest, callback: Callback<S>) -> RaftCommand<S> {
        RaftCommand {
            request,
            callback,
            send_time: Instant::now(),
        }
    }
}

/// Message that can be sent to a peer.
pub enum PeerMsg<E: KvEngine> {
    /// Raft message is the message sent between raft nodes in the same
    /// raft group. Messages need to be redirected to raftstore if target
    /// peer doesn't exist.
    RaftMessage(RaftMessage),
    /// Raft command is the command that is expected to be proposed by the
    /// leader of the target raft group. If it's failed to be sent, callback
    /// usually needs to be called before dropping in case of resource leak.
    RaftCommand(RaftCommand<E::Snapshot>),
    /// Tick is periodical task. If target peer doesn't exist there is a potential
    /// that the raft node will not work anymore.
    Tick(PeerTicks),
    /// Result of applying committed entries. The message can't be lost.
    ApplyRes { res: ApplyTaskRes<E> },
    /// Message that can't be lost but rarely created. If they are lost, real bad
    /// things happen like some peers will be considered dead in the group.
    SignificantMsg(SignificantMsg),
    /// Start the FSM.
    Start,
    /// A message only used to notify a peer.
    Noop,
    /// Message that is not important and can be dropped occasionally.
    CasualMessage(CasualMessage<E>),
    /// Ask region to report a heartbeat to PD.
    HeartbeatPd,
    /// Asks region to change replication mode.
    UpdateReplicationMode,
}

impl<E: KvEngine> fmt::Debug for PeerMsg<E> {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            PeerMsg::RaftMessage(_) => write!(fmt, "Raft Message"),
            PeerMsg::RaftCommand(_) => write!(fmt, "Raft Command"),
            PeerMsg::Tick(tick) => write! {
                fmt,
                "{:?}",
                tick
            },
            PeerMsg::SignificantMsg(msg) => write!(fmt, "{:?}", msg),
            PeerMsg::ApplyRes { res } => write!(fmt, "ApplyRes {:?}", res),
            PeerMsg::Start => write!(fmt, "Startup"),
            PeerMsg::Noop => write!(fmt, "Noop"),
            PeerMsg::CasualMessage(msg) => write!(fmt, "CasualMessage {:?}", msg),
            PeerMsg::HeartbeatPd => write!(fmt, "HeartbeatPd"),
            PeerMsg::UpdateReplicationMode => write!(fmt, "UpdateReplicationMode"),
        }
    }
}

pub enum StoreMsg {
    RaftMessage(RaftMessage),
    // For snapshot stats.
    SnapshotStats,

    ValidateSSTResult {
        invalid_ssts: Vec<SstMeta>,
    },

    // Clear region size and keys for all regions in the range, so we can force them to re-calculate
    // their size later.
    ClearRegionSizeInRange {
        start_key: Vec<u8>,
        end_key: Vec<u8>,
    },
    StoreUnreachable {
        store_id: u64,
    },

    // Compaction finished event
    CompactedEvent(CompactedEvent),
    Tick(StoreTick),
    Start {
        store: metapb::Store,
    },

    /// Message only used for test.
    #[cfg(any(test, feature = "testexport"))]
    Validate(Box<dyn FnOnce(&crate::store::Config) + Send>),
    /// Asks the store to update replication mode.
    UpdateReplicationMode(ReplicationStatus),
}

impl fmt::Debug for StoreMsg {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            StoreMsg::RaftMessage(_) => write!(fmt, "Raft Message"),
            StoreMsg::SnapshotStats => write!(fmt, "Snapshot stats"),
            StoreMsg::StoreUnreachable { store_id } => {
                write!(fmt, "Store {}  is unreachable", store_id)
            }
            StoreMsg::CompactedEvent(ref event) => write!(fmt, "CompactedEvent cf {}", event.cf),
            StoreMsg::ValidateSSTResult { .. } => write!(fmt, "Validate SST Result"),
            StoreMsg::ClearRegionSizeInRange {
                ref start_key,
                ref end_key,
            } => write!(
                fmt,
                "Clear Region size in range {:?} to {:?}",
                start_key, end_key
            ),
            StoreMsg::Tick(tick) => write!(fmt, "StoreTick {:?}", tick),
            StoreMsg::Start { ref store } => write!(fmt, "Start store {:?}", store),
            #[cfg(any(test, feature = "testexport"))]
            StoreMsg::Validate(_) => write!(fmt, "Validate config"),
            StoreMsg::UpdateReplicationMode(_) => write!(fmt, "UpdateReplicationMode"),
        }
    }
}
<|endoftext|>


<commit_before>use super::{
    child_properties::ChildProperties, imports::Imports, info_base::InfoBase,
    signatures::Signatures, *,
};
use crate::{config::gobjects::GObject, env::Env, library, nameutil::*, traits::*};
use log::info;
use std::ops::Deref;

#[derive(Debug, Default)]
pub struct Info {
    pub base: InfoBase,
    pub c_type: String,
    pub c_class_type: Option<String>,
    pub get_type: String,
    pub is_interface: bool,
    pub supertypes: Vec<general::StatusedTypeId>,
    pub final_type: bool,
    pub generate_trait: bool,
    pub trait_name: String,
    pub has_constructors: bool,
    pub has_functions: bool,
    pub signals: Vec<signals::Info>,
    pub notify_signals: Vec<signals::Info>,
    pub properties: Vec<properties::Property>,
    pub builder_properties: Vec<properties::Property>,
    pub builder_postprocess: Option<String>,
    pub child_properties: ChildProperties,
    pub signatures: Signatures,
}

impl Info {
    pub fn has_signals(&self) -> bool {
        self.signals.iter().any(|s| s.trampoline.is_ok())
            || self.notify_signals.iter().any(|s| s.trampoline.is_ok())
    }

    pub fn has_action_signals(&self) -> bool {
        self.signals.iter().any(|s| s.action_emit_name.is_some())
    }
}

impl Deref for Info {
    type Target = InfoBase;

    fn deref(&self) -> &InfoBase {
        &self.base
    }
}

pub fn class(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option<Info> {
    info!("Analyzing class {}", obj.name);
    let full_name = obj.name.clone();

    let class_tid = env.library.find_type(0, &full_name)?;

    let type_ = env.type_(class_tid);

    let name: String = split_namespace_name(&full_name).1.into();

    let klass: &library::Class = type_.maybe_ref()?;

    let mut imports = Imports::with_defined(&env.library, &name);
    if obj.generate_display_trait {
        imports.add("std::fmt");
    }

    let supertypes = supertypes::analyze(env, class_tid, &mut imports);

    let final_type = klass.final_type;
    let trait_name = obj
        .trait_name
        .as_ref()
        .cloned()
        .unwrap_or_else(|| format!("{}Ext", name));

    let mut signatures = Signatures::with_capacity(klass.functions.len());

    let mut functions = functions::analyze(
        env,
        &klass.functions,
        class_tid,
        !final_type,
        false,
        obj,
        &mut imports,
        Some(&mut signatures),
        Some(deps),
    );
    let mut specials = special_functions::extract(&mut functions, type_, obj);
    // `copy` will duplicate an object while `clone` just adds a reference
    special_functions::unhide(&mut functions, &specials, special_functions::Type::Copy);
    // these are all automatically derived on objects and compare by pointer. If such functions
    // exist they will provide additional functionality
    for t in &[
        special_functions::Type::Hash,
        special_functions::Type::Equal,
        special_functions::Type::Compare,
    ] {
        special_functions::unhide(&mut functions, &specials, *t);
        specials.traits_mut().remove(t);
    }
    special_functions::analyze_imports(&specials, &mut imports);

    let signals = signals::analyze(
        env,
        &klass.signals,
        class_tid,
        !final_type,
        obj,
        &mut imports,
    );
    let (properties, notify_signals) = properties::analyze(
        env,
        &klass.properties,
        class_tid,
        !final_type,
        obj,
        &mut imports,
        &signatures,
        deps,
    );

    let builder_properties =
        class_builder::analyze(env, &klass.properties, class_tid, obj, &mut imports);

    let (version, deprecated_version) = info_base::versions(
        env,
        obj,
        &functions,
        klass.version,
        klass.deprecated_version,
    );

    let child_properties =
        child_properties::analyze(env, obj.child_properties.as_ref(), class_tid, &mut imports);

    let has_methods = functions
        .iter()
        .any(|f| f.kind == library::FunctionKind::Method && f.status.need_generate());
    let has_signals = signals.iter().any(|s| s.trampoline.is_ok())
        || notify_signals.iter().any(|s| s.trampoline.is_ok());

    // There's no point in generating a trait if there are no signals, methods, properties
    // and child properties: it would be empty
    //
    // There's also no point in generating a trait for final types: there are no possible subtypes
    let generate_trait = !final_type
        && (has_signals || has_methods || !properties.is_empty() || !child_properties.is_empty());

    if !builder_properties.is_empty() {
        imports.add("glib::object::Cast");
        imports.add("glib::StaticType");
        imports.add("glib::ToValue");
    }

    if generate_trait {
        imports.add("glib::object::IsA");
    }

    if obj.concurrency == library::Concurrency::SendUnique {
        imports.add("glib::ObjectExt");
    }

    let base = InfoBase {
        full_name,
        type_id: class_tid,
        name,
        functions,
        specials,
        imports,
        version,
        deprecated_version,
        cfg_condition: obj.cfg_condition.clone(),
        concurrency: obj.concurrency,
    };

    // patch up trait methods in the symbol table
    if generate_trait {
        let mut symbols = env.symbols.borrow_mut();
        for func in base.methods() {
            if let Some(symbol) = symbols.by_c_name_mut(&func.glib_name) {
                symbol.make_trait_method(&trait_name);
            }
        }
    }

    let has_constructors = !base.constructors().is_empty();
    let has_functions = !base.functions().is_empty();

    let info = Info {
        base,
        c_type: klass.c_type.clone(),
        c_class_type: klass.c_class_type.clone(),
        get_type: klass.glib_get_type.clone(),
        is_interface: false,
        supertypes,
        final_type,
        generate_trait,
        trait_name,
        has_constructors,
        has_functions,
        signals,
        notify_signals,
        properties,
        builder_properties,
        builder_postprocess: obj.builder_postprocess.clone(),
        child_properties,
        signatures,
    };

    Some(info)
}

pub fn interface(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option<Info> {
    info!("Analyzing interface {}", obj.name);
    let full_name = obj.name.clone();

    let iface_tid = env.library.find_type(0, &full_name)?;

    let type_ = env.type_(iface_tid);

    let name: String = split_namespace_name(&full_name).1.into();

    let iface: &library::Interface = type_.maybe_ref()?;

    let mut imports = Imports::with_defined(&env.library, &name);
    imports.add("glib::object::IsA");
    if obj.generate_display_trait {
        imports.add("std::fmt");
    }

    let supertypes = supertypes::analyze(env, iface_tid, &mut imports);

    let trait_name = obj
        .trait_name
        .as_ref()
        .cloned()
        .unwrap_or_else(|| format!("{}Ext", name));

    let mut signatures = Signatures::with_capacity(iface.functions.len());

    let functions = functions::analyze(
        env,
        &iface.functions,
        iface_tid,
        true,
        false,
        obj,
        &mut imports,
        Some(&mut signatures),
        Some(deps),
    );

    let signals = signals::analyze(env, &iface.signals, iface_tid, true, obj, &mut imports);
    let (properties, notify_signals) = properties::analyze(
        env,
        &iface.properties,
        iface_tid,
        true,
        obj,
        &mut imports,
        &signatures,
        deps,
    );

    let (version, deprecated_version) = info_base::versions(
        env,
        obj,
        &functions,
        iface.version,
        iface.deprecated_version,
    );

    if obj.concurrency == library::Concurrency::SendUnique {
        imports.add("glib::ObjectExt");
    }

    let base = InfoBase {
        full_name,
        type_id: iface_tid,
        name,
        functions,
        specials: Default::default(),
        imports,
        version,
        deprecated_version,
        cfg_condition: obj.cfg_condition.clone(),
        concurrency: obj.concurrency,
    };

    let has_functions = !base.functions().is_empty();

    let info = Info {
        base,
        c_type: iface.c_type.clone(),
        c_class_type: None,
        get_type: iface.glib_get_type.clone(),
        is_interface: true,
        supertypes,
        final_type: false,
        generate_trait: true,
        trait_name,
        has_functions,
        signals,
        notify_signals,
        properties,
        signatures,
        ..Default::default()
    };

    Some(info)
}
<commit_msg>Also populate interface structs in addition to class structs<commit_after>use super::{
    child_properties::ChildProperties, imports::Imports, info_base::InfoBase,
    signatures::Signatures, *,
};
use crate::{config::gobjects::GObject, env::Env, library, nameutil::*, traits::*};
use log::info;
use std::ops::Deref;

#[derive(Debug, Default)]
pub struct Info {
    pub base: InfoBase,
    pub c_type: String,
    pub c_class_type: Option<String>,
    pub get_type: String,
    pub is_interface: bool,
    pub supertypes: Vec<general::StatusedTypeId>,
    pub final_type: bool,
    pub generate_trait: bool,
    pub trait_name: String,
    pub has_constructors: bool,
    pub has_functions: bool,
    pub signals: Vec<signals::Info>,
    pub notify_signals: Vec<signals::Info>,
    pub properties: Vec<properties::Property>,
    pub builder_properties: Vec<properties::Property>,
    pub builder_postprocess: Option<String>,
    pub child_properties: ChildProperties,
    pub signatures: Signatures,
}

impl Info {
    pub fn has_signals(&self) -> bool {
        self.signals.iter().any(|s| s.trampoline.is_ok())
            || self.notify_signals.iter().any(|s| s.trampoline.is_ok())
    }

    pub fn has_action_signals(&self) -> bool {
        self.signals.iter().any(|s| s.action_emit_name.is_some())
    }
}

impl Deref for Info {
    type Target = InfoBase;

    fn deref(&self) -> &InfoBase {
        &self.base
    }
}

pub fn class(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option<Info> {
    info!("Analyzing class {}", obj.name);
    let full_name = obj.name.clone();

    let class_tid = env.library.find_type(0, &full_name)?;

    let type_ = env.type_(class_tid);

    let name: String = split_namespace_name(&full_name).1.into();

    let klass: &library::Class = type_.maybe_ref()?;

    let mut imports = Imports::with_defined(&env.library, &name);
    if obj.generate_display_trait {
        imports.add("std::fmt");
    }

    let supertypes = supertypes::analyze(env, class_tid, &mut imports);

    let final_type = klass.final_type;
    let trait_name = obj
        .trait_name
        .as_ref()
        .cloned()
        .unwrap_or_else(|| format!("{}Ext", name));

    let mut signatures = Signatures::with_capacity(klass.functions.len());

    let mut functions = functions::analyze(
        env,
        &klass.functions,
        class_tid,
        !final_type,
        false,
        obj,
        &mut imports,
        Some(&mut signatures),
        Some(deps),
    );
    let mut specials = special_functions::extract(&mut functions, type_, obj);
    // `copy` will duplicate an object while `clone` just adds a reference
    special_functions::unhide(&mut functions, &specials, special_functions::Type::Copy);
    // these are all automatically derived on objects and compare by pointer. If such functions
    // exist they will provide additional functionality
    for t in &[
        special_functions::Type::Hash,
        special_functions::Type::Equal,
        special_functions::Type::Compare,
    ] {
        special_functions::unhide(&mut functions, &specials, *t);
        specials.traits_mut().remove(t);
    }
    special_functions::analyze_imports(&specials, &mut imports);

    let signals = signals::analyze(
        env,
        &klass.signals,
        class_tid,
        !final_type,
        obj,
        &mut imports,
    );
    let (properties, notify_signals) = properties::analyze(
        env,
        &klass.properties,
        class_tid,
        !final_type,
        obj,
        &mut imports,
        &signatures,
        deps,
    );

    let builder_properties =
        class_builder::analyze(env, &klass.properties, class_tid, obj, &mut imports);

    let (version, deprecated_version) = info_base::versions(
        env,
        obj,
        &functions,
        klass.version,
        klass.deprecated_version,
    );

    let child_properties =
        child_properties::analyze(env, obj.child_properties.as_ref(), class_tid, &mut imports);

    let has_methods = functions
        .iter()
        .any(|f| f.kind == library::FunctionKind::Method && f.status.need_generate());
    let has_signals = signals.iter().any(|s| s.trampoline.is_ok())
        || notify_signals.iter().any(|s| s.trampoline.is_ok());

    // There's no point in generating a trait if there are no signals, methods, properties
    // and child properties: it would be empty
    //
    // There's also no point in generating a trait for final types: there are no possible subtypes
    let generate_trait = !final_type
        && (has_signals || has_methods || !properties.is_empty() || !child_properties.is_empty());

    if !builder_properties.is_empty() {
        imports.add("glib::object::Cast");
        imports.add("glib::StaticType");
        imports.add("glib::ToValue");
    }

    if generate_trait {
        imports.add("glib::object::IsA");
    }

    if obj.concurrency == library::Concurrency::SendUnique {
        imports.add("glib::ObjectExt");
    }

    let base = InfoBase {
        full_name,
        type_id: class_tid,
        name,
        functions,
        specials,
        imports,
        version,
        deprecated_version,
        cfg_condition: obj.cfg_condition.clone(),
        concurrency: obj.concurrency,
    };

    // patch up trait methods in the symbol table
    if generate_trait {
        let mut symbols = env.symbols.borrow_mut();
        for func in base.methods() {
            if let Some(symbol) = symbols.by_c_name_mut(&func.glib_name) {
                symbol.make_trait_method(&trait_name);
            }
        }
    }

    let has_constructors = !base.constructors().is_empty();
    let has_functions = !base.functions().is_empty();

    let info = Info {
        base,
        c_type: klass.c_type.clone(),
        c_class_type: klass.c_class_type.clone(),
        get_type: klass.glib_get_type.clone(),
        is_interface: false,
        supertypes,
        final_type,
        generate_trait,
        trait_name,
        has_constructors,
        has_functions,
        signals,
        notify_signals,
        properties,
        builder_properties,
        builder_postprocess: obj.builder_postprocess.clone(),
        child_properties,
        signatures,
    };

    Some(info)
}

pub fn interface(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option<Info> {
    info!("Analyzing interface {}", obj.name);
    let full_name = obj.name.clone();

    let iface_tid = env.library.find_type(0, &full_name)?;

    let type_ = env.type_(iface_tid);

    let name: String = split_namespace_name(&full_name).1.into();

    let iface: &library::Interface = type_.maybe_ref()?;

    let mut imports = Imports::with_defined(&env.library, &name);
    imports.add("glib::object::IsA");
    if obj.generate_display_trait {
        imports.add("std::fmt");
    }

    let supertypes = supertypes::analyze(env, iface_tid, &mut imports);

    let trait_name = obj
        .trait_name
        .as_ref()
        .cloned()
        .unwrap_or_else(|| format!("{}Ext", name));

    let mut signatures = Signatures::with_capacity(iface.functions.len());

    let functions = functions::analyze(
        env,
        &iface.functions,
        iface_tid,
        true,
        false,
        obj,
        &mut imports,
        Some(&mut signatures),
        Some(deps),
    );

    let signals = signals::analyze(env, &iface.signals, iface_tid, true, obj, &mut imports);
    let (properties, notify_signals) = properties::analyze(
        env,
        &iface.properties,
        iface_tid,
        true,
        obj,
        &mut imports,
        &signatures,
        deps,
    );

    let (version, deprecated_version) = info_base::versions(
        env,
        obj,
        &functions,
        iface.version,
        iface.deprecated_version,
    );

    if obj.concurrency == library::Concurrency::SendUnique {
        imports.add("glib::ObjectExt");
    }

    let base = InfoBase {
        full_name,
        type_id: iface_tid,
        name,
        functions,
        specials: Default::default(),
        imports,
        version,
        deprecated_version,
        cfg_condition: obj.cfg_condition.clone(),
        concurrency: obj.concurrency,
    };

    let has_functions = !base.functions().is_empty();

    let info = Info {
        base,
        c_type: iface.c_type.clone(),
        c_class_type: iface.c_class_type.clone(),
        get_type: iface.glib_get_type.clone(),
        is_interface: true,
        supertypes,
        final_type: false,
        generate_trait: true,
        trait_name,
        has_functions,
        signals,
        notify_signals,
        properties,
        signatures,
        ..Default::default()
    };

    Some(info)
}
<|endoftext|>


<commit_before>use criterion::Bencher;
use criterion_cycles_per_byte::CyclesPerByte;
use time::format_description::{modifier, Component};
use time::parsing::Parsed;

setup_benchmark! {
    "Parsing",

    fn parse_component(ben: &mut Bencher<'_, CyclesPerByte>) {
        macro_rules! component {
            ($name:ident {$($field:ident : $value:expr),+ $(,)? }) => {{
                const COMPONENT: Component = Component::$name({
                    let mut modifier = modifier::$name::default();
                    $(modifier.$field = $value;)+
                    modifier
                });
                COMPONENT
            }};
        }

        let mut parsed = Parsed::new();

        ben.iter(|| {
            parsed.parse_component(b"2021", component!(Year {
                padding: modifier::Padding::Zero,
                repr: modifier::YearRepr::Full,
                iso_week_based: false,
                sign_is_mandatory: false,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"21", component!(Year {
                padding: modifier::Padding::Zero,
                repr: modifier::YearRepr::LastTwo,
                iso_week_based: false,
                sign_is_mandatory: false,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"2021", component!(Year {
                padding: modifier::Padding::Zero,
                repr: modifier::YearRepr::Full,
                iso_week_based: true,
                sign_is_mandatory: false,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"21", component!(Year {
                padding: modifier::Padding::Zero,
                repr: modifier::YearRepr::LastTwo,
                iso_week_based: true,
                sign_is_mandatory: false,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b" 1", component!(Month {
                padding: modifier::Padding::Space,
                repr: modifier::MonthRepr::Numerical,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"Jan", component!(Month {
                padding: modifier::Padding::None,
                repr: modifier::MonthRepr::Short,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"January", component!(Month {
                padding: modifier::Padding::None,
                repr: modifier::MonthRepr::Long,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"012", component!(Ordinal {
                padding: modifier::Padding::Zero,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"Sun", component!(Weekday {
                repr: modifier::WeekdayRepr::Short,
                one_indexed: false,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"Sunday", component!(Weekday {
                repr: modifier::WeekdayRepr::Long,
                one_indexed: false,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"0", component!(Weekday {
                repr: modifier::WeekdayRepr::Sunday,
                one_indexed: false,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"1", component!(Weekday {
                repr: modifier::WeekdayRepr::Sunday,
                one_indexed: true,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"6", component!(Weekday {
                repr: modifier::WeekdayRepr::Monday,
                one_indexed: false,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"7", component!(Weekday {
                repr: modifier::WeekdayRepr::Monday,
                one_indexed: true,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"2", component!(WeekNumber {
                padding: modifier::Padding::None,
                repr: modifier::WeekNumberRepr::Sunday,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"2", component!(WeekNumber {
                padding: modifier::Padding::None,
                repr: modifier::WeekNumberRepr::Monday,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"2", component!(WeekNumber {
                padding: modifier::Padding::None,
                repr: modifier::WeekNumberRepr::Iso,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"1", component!(Subsecond {
                digits: modifier::SubsecondDigits::One,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"12", component!(Subsecond {
                digits: modifier::SubsecondDigits::Two,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"123", component!(Subsecond {
                digits: modifier::SubsecondDigits::Three,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"1234", component!(Subsecond {
                digits: modifier::SubsecondDigits::Four,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"12345", component!(Subsecond {
                digits: modifier::SubsecondDigits::Five,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"123456", component!(Subsecond {
                digits: modifier::SubsecondDigits::Six,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"1234567", component!(Subsecond {
                digits: modifier::SubsecondDigits::Seven,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"12345678", component!(Subsecond {
                digits: modifier::SubsecondDigits::Eight,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"123456789", component!(Subsecond {
                digits: modifier::SubsecondDigits::Nine,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"123456789", component!(Subsecond {
                digits: modifier::SubsecondDigits::OneOrMore,
            }))
        });
    }
}
<commit_msg>Split parsing benchmark by component<commit_after>use criterion::Bencher;
use criterion_cycles_per_byte::CyclesPerByte;
use time::format_description::{modifier, Component};
use time::parsing::Parsed;

macro_rules! component {
    ($name:ident {$($field:ident : $value:expr),+ $(,)? }) => {{
        const COMPONENT: Component = Component::$name({
            let mut modifier = modifier::$name::default();
            $(modifier.$field = $value;)+
            modifier
        });
        COMPONENT
    }};
}

setup_benchmark! {
    "Parsing",

    fn parse_component_year(ben: &mut Bencher<'_, CyclesPerByte>) {
        let mut parsed = Parsed::new();
        ben.iter(|| {
            parsed.parse_component(b"2021", component!(Year {
                padding: modifier::Padding::Zero,
                repr: modifier::YearRepr::Full,
                iso_week_based: false,
                sign_is_mandatory: false,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"21", component!(Year {
                padding: modifier::Padding::Zero,
                repr: modifier::YearRepr::LastTwo,
                iso_week_based: false,
                sign_is_mandatory: false,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"2021", component!(Year {
                padding: modifier::Padding::Zero,
                repr: modifier::YearRepr::Full,
                iso_week_based: true,
                sign_is_mandatory: false,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"21", component!(Year {
                padding: modifier::Padding::Zero,
                repr: modifier::YearRepr::LastTwo,
                iso_week_based: true,
                sign_is_mandatory: false,
            }))
        });
    }

    fn parse_component_month(ben: &mut Bencher<'_, CyclesPerByte>) {
        let mut parsed = Parsed::new();
        ben.iter(|| {
            parsed.parse_component(b" 1", component!(Month {
                padding: modifier::Padding::Space,
                repr: modifier::MonthRepr::Numerical,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"Jan", component!(Month {
                padding: modifier::Padding::None,
                repr: modifier::MonthRepr::Short,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"January", component!(Month {
                padding: modifier::Padding::None,
                repr: modifier::MonthRepr::Long,
            }))
        });
    }

    fn parse_component_ordinal(ben: &mut Bencher<'_, CyclesPerByte>) {
        let mut parsed = Parsed::new();
        ben.iter(|| {
            parsed.parse_component(b"012", component!(Ordinal {
                padding: modifier::Padding::Zero,
            }))
        });
    }

    fn parse_component_weekday(ben: &mut Bencher<'_, CyclesPerByte>) {
        let mut parsed = Parsed::new();
        ben.iter(|| {
            parsed.parse_component(b"Sun", component!(Weekday {
                repr: modifier::WeekdayRepr::Short,
                one_indexed: false,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"Sunday", component!(Weekday {
                repr: modifier::WeekdayRepr::Long,
                one_indexed: false,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"0", component!(Weekday {
                repr: modifier::WeekdayRepr::Sunday,
                one_indexed: false,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"1", component!(Weekday {
                repr: modifier::WeekdayRepr::Sunday,
                one_indexed: true,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"6", component!(Weekday {
                repr: modifier::WeekdayRepr::Monday,
                one_indexed: false,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"7", component!(Weekday {
                repr: modifier::WeekdayRepr::Monday,
                one_indexed: true,
            }))
        });
    }

    fn parse_component_week_number(ben: &mut Bencher<'_, CyclesPerByte>) {
        let mut parsed = Parsed::new();
        ben.iter(|| {
            parsed.parse_component(b"2", component!(WeekNumber {
                padding: modifier::Padding::None,
                repr: modifier::WeekNumberRepr::Sunday,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"2", component!(WeekNumber {
                padding: modifier::Padding::None,
                repr: modifier::WeekNumberRepr::Monday,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"2", component!(WeekNumber {
                padding: modifier::Padding::None,
                repr: modifier::WeekNumberRepr::Iso,
            }))
        });
    }

    fn parse_component_subsecond(ben: &mut Bencher<'_, CyclesPerByte>) {
        let mut parsed = Parsed::new();
        ben.iter(|| {
            parsed.parse_component(b"1", component!(Subsecond {
                digits: modifier::SubsecondDigits::One,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"12", component!(Subsecond {
                digits: modifier::SubsecondDigits::Two,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"123", component!(Subsecond {
                digits: modifier::SubsecondDigits::Three,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"1234", component!(Subsecond {
                digits: modifier::SubsecondDigits::Four,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"12345", component!(Subsecond {
                digits: modifier::SubsecondDigits::Five,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"123456", component!(Subsecond {
                digits: modifier::SubsecondDigits::Six,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"1234567", component!(Subsecond {
                digits: modifier::SubsecondDigits::Seven,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"12345678", component!(Subsecond {
                digits: modifier::SubsecondDigits::Eight,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"123456789", component!(Subsecond {
                digits: modifier::SubsecondDigits::Nine,
            }))
        });
        ben.iter(|| {
            parsed.parse_component(b"123456789", component!(Subsecond {
                digits: modifier::SubsecondDigits::OneOrMore,
            }))
        });
    }
}
<|endoftext|>


<commit_before>use std::fs::create_dir_all;
use std::path::Path;
use std::process::Command;
use std::sync::mpsc::channel;
use std::sync::{Arc, Mutex};
use std::thread;

use anyhow::Result;
use simplelog::{Config, LevelFilter, SimpleLogger};
use structopt::StructOpt;

use pueue::message::Message;
use pueue::settings::Settings;
use pueue::state::State;

use crate::cli::Opt;
use crate::socket::accept_incoming;
use crate::task_handler::TaskHandler;

mod aliasing;
mod cli;
mod instructions;
mod platform;
mod response_helper;
mod socket;
mod streaming;
mod task_handler;

#[async_std::main]
async fn main() -> Result<()> {
    // Get settings from the configuration file and the program defaults.
    let settings = Settings::new()?;
    // Immediately save it. This also creates the save file in case it didn't exist yet.
    if let Err(error) = settings.save() {
        println!("Failed saving config file.");
        println!("{:?}", error);
    }

    // Parse commandline options.
    let opt = Opt::from_args();

    if opt.daemonize {
        fork_daemon(&opt)?;
    }

    // Set the verbosity level for the client app.
    if opt.verbose >= 3 {
        SimpleLogger::init(LevelFilter::Debug, Config::default())?;
    } else if opt.verbose == 2 {
        SimpleLogger::init(LevelFilter::Info, Config::default())?;
    } else if opt.verbose == 1 {
        SimpleLogger::init(LevelFilter::Warn, Config::default())?;
    } else if opt.verbose == 0 {
        SimpleLogger::init(LevelFilter::Error, Config::default())?;
    }

    init_directories(&settings.shared.pueue_directory);

    let state = State::new(&settings);
    let state = Arc::new(Mutex::new(state));

    let (sender, receiver) = channel();
    let mut task_handler = TaskHandler::new(state.clone(), receiver);

    // This section handles Shutdown via SigTerm/SigInt process signals
    // 1. Remove the unix socket (if it exists).
    // 2. Notify the TaskHandler, so it can shutdown gracefully.
    //
    // The actual program exit will be done via the TaskHandler.
    let unix_socket_path = settings.shared.unix_socket_path.clone();
    let sender_clone = sender.clone();
    ctrlc::set_handler(move || {
        // Clean up the unix socket if we're using it and it exists.
        if settings.shared.use_unix_socket && std::path::PathBuf::from(&unix_socket_path).exists() {
            std::fs::remove_file(&unix_socket_path)
                .expect("Failed to remove unix socket on shutdown");
        }

        // Notify the task handler
        sender_clone
            .send(Message::DaemonShutdown)
            .expect("Failed to send Message to TaskHandler on Shutdown");
    })?;

    thread::spawn(move || {
        task_handler.run();
    });

    accept_incoming(sender, state.clone(), opt).await?;

    Ok(())
}

/// Initialize all directories needed for normal operation.
fn init_directories(path: &str) {
    // Pueue base path
    let pueue_dir = Path::new(path);
    if !pueue_dir.exists() {
        if let Err(error) = create_dir_all(&pueue_dir) {
            panic!(
                "Failed to create main directory at {:?} error: {:?}",
                pueue_dir, error
            );
        }
    }

    // Task log dir
    let log_dir = pueue_dir.join("log");
    if !log_dir.exists() {
        if let Err(error) = create_dir_all(&log_dir) {
            panic!(
                "Failed to create log directory at {:?} error: {:?}",
                log_dir, error
            );
        }
    }

    // Task log dir
    let logs_dir = pueue_dir.join("task_logs");
    if !logs_dir.exists() {
        if let Err(error) = create_dir_all(&logs_dir) {
            panic!(
                "Failed to create task logs directory at {:?} error: {:?}",
                logs_dir, error
            );
        }
    }
}

/// This is a simple and cheap custom fork method.
/// Simply spawn a new child with identical arguments and exit right away.
fn fork_daemon(opt: &Opt) -> Result<()> {
    let mut arguments = Vec::<String>::new();

    if let Some(port) = &opt.port {
        arguments.push("--port".to_string());
        arguments.push(port.clone());
    }

    if opt.verbose > 0 {
        arguments.push("-".to_string() + &" ".repeat(opt.verbose as usize));
    }

    Command::new("pueued").args(&arguments).spawn()?;

    println!("Pueued is now running in the background");
    std::process::exit(0);
}
<commit_msg>Exit program as soon as the TaskHandler panics<commit_after>use std::fs::create_dir_all;
use std::path::Path;
use std::process::Command;
use std::sync::mpsc::channel;
use std::sync::{Arc, Mutex};

use anyhow::Result;
use simplelog::{Config, LevelFilter, SimpleLogger};
use structopt::StructOpt;

use pueue::message::Message;
use pueue::settings::Settings;
use pueue::state::State;

use crate::cli::Opt;
use crate::socket::accept_incoming;
use crate::task_handler::TaskHandler;

mod aliasing;
mod cli;
mod instructions;
mod platform;
mod response_helper;
mod socket;
mod streaming;
mod task_handler;

#[async_std::main]
async fn main() -> Result<()> {
    // Get settings from the configuration file and the program defaults.
    let settings = Settings::new()?;
    // Immediately save it. This also creates the save file in case it didn't exist yet.
    if let Err(error) = settings.save() {
        println!("Failed saving config file.");
        println!("{:?}", error);
    }

    // Parse commandline options.
    let opt = Opt::from_args();

    if opt.daemonize {
        fork_daemon(&opt)?;
    }

    // Set the verbosity level for the client app.
    if opt.verbose >= 3 {
        SimpleLogger::init(LevelFilter::Debug, Config::default())?;
    } else if opt.verbose == 2 {
        SimpleLogger::init(LevelFilter::Info, Config::default())?;
    } else if opt.verbose == 1 {
        SimpleLogger::init(LevelFilter::Warn, Config::default())?;
    } else if opt.verbose == 0 {
        SimpleLogger::init(LevelFilter::Error, Config::default())?;
    }

    init_directories(&settings.shared.pueue_directory);

    let state = State::new(&settings);
    let state = Arc::new(Mutex::new(state));

    let (sender, receiver) = channel();
    let mut task_handler = TaskHandler::new(state.clone(), receiver);

    // This section handles Shutdown via SigTerm/SigInt process signals
    // 1. Remove the unix socket (if it exists).
    // 2. Notify the TaskHandler, so it can shutdown gracefully.
    //
    // The actual program exit will be done via the TaskHandler.
    let unix_socket_path = settings.shared.unix_socket_path.clone();
    let sender_clone = sender.clone();
    ctrlc::set_handler(move || {
        // Clean up the unix socket if we're using it and it exists.
        if settings.shared.use_unix_socket && std::path::PathBuf::from(&unix_socket_path).exists() {
            std::fs::remove_file(&unix_socket_path)
                .expect("Failed to remove unix socket on shutdown");
        }

        // Notify the task handler
        sender_clone
            .send(Message::DaemonShutdown)
            .expect("Failed to send Message to TaskHandler on Shutdown");
    })?;

    let orig_hook = std::panic::take_hook();
    std::panic::set_hook(Box::new(move |panic_info| {
        // invoke the default handler and exit the process
        orig_hook(panic_info);
        std::process::exit(1);
    }));

    std::thread::spawn(move || {
        task_handler.run();
    });

    accept_incoming(sender, state.clone(), opt).await?;

    Ok(())
}

/// Initialize all directories needed for normal operation.
fn init_directories(path: &str) {
    // Pueue base path
    let pueue_dir = Path::new(path);
    if !pueue_dir.exists() {
        if let Err(error) = create_dir_all(&pueue_dir) {
            panic!(
                "Failed to create main directory at {:?} error: {:?}",
                pueue_dir, error
            );
        }
    }

    // Task log dir
    let log_dir = pueue_dir.join("log");
    if !log_dir.exists() {
        if let Err(error) = create_dir_all(&log_dir) {
            panic!(
                "Failed to create log directory at {:?} error: {:?}",
                log_dir, error
            );
        }
    }

    // Task log dir
    let logs_dir = pueue_dir.join("task_logs");
    if !logs_dir.exists() {
        if let Err(error) = create_dir_all(&logs_dir) {
            panic!(
                "Failed to create task logs directory at {:?} error: {:?}",
                logs_dir, error
            );
        }
    }
}

/// This is a simple and cheap custom fork method.
/// Simply spawn a new child with identical arguments and exit right away.
fn fork_daemon(opt: &Opt) -> Result<()> {
    let mut arguments = Vec::<String>::new();

    if let Some(port) = &opt.port {
        arguments.push("--port".to_string());
        arguments.push(port.clone());
    }

    if opt.verbose > 0 {
        arguments.push("-".to_string() + &" ".repeat(opt.verbose as usize));
    }

    Command::new("pueued").args(&arguments).spawn()?;

    println!("Pueued is now running in the background");
    std::process::exit(0);
}
<|endoftext|>


<commit_before>use std::{
    io::{self, BufReader},
    net::TcpStream,
    thread,
};

use crossbeam_channel::{bounded, Receiver, Sender};

use crate::{
    stdio::{make_io_threads, IoThreads},
    Message,
};

pub(crate) fn socket_transport(
    stream: TcpStream,
) -> (Sender<Message>, Receiver<Message>, IoThreads) {
    let (reader_receiver, reader) = make_reader(stream.try_clone().unwrap());
    let (writer_sender, writer) = make_write(stream.try_clone().unwrap());
    let io_threads = make_io_threads(reader, writer);
    (writer_sender, reader_receiver, io_threads)
}

fn make_reader(stream: TcpStream) -> (Receiver<Message>, thread::JoinHandle<io::Result<()>>) {
    let (reader_sender, reader_receiver) = bounded::<Message>(0);
    let reader = thread::spawn(move || {
        let mut buf_read = BufReader::new(stream);
        while let Some(msg) = Message::read(&mut buf_read).unwrap() {
            let is_exit = matches!(&msg, Message::Notification(n) if n.is_exit());
            reader_sender.send(msg).unwrap();
            if is_exit {
                break;
            }
        }
        Ok(())
    });
    (reader_receiver, reader)
}

fn make_write(mut stream: TcpStream) -> (Sender<Message>, thread::JoinHandle<io::Result<()>>) {
    let (writer_sender, writer_receiver) = bounded::<Message>(0);
    let writer = thread::spawn(move || {
        writer_receiver.into_iter().try_for_each(|it| it.write(&mut stream)).unwrap();
        Ok(())
    });
    (writer_sender, writer)
}
<commit_msg>internal: remove unnecessary stream writer try_clone in lsp-server<commit_after>use std::{
    io::{self, BufReader},
    net::TcpStream,
    thread,
};

use crossbeam_channel::{bounded, Receiver, Sender};

use crate::{
    stdio::{make_io_threads, IoThreads},
    Message,
};

pub(crate) fn socket_transport(
    stream: TcpStream,
) -> (Sender<Message>, Receiver<Message>, IoThreads) {
    let (reader_receiver, reader) = make_reader(stream.try_clone().unwrap());
    let (writer_sender, writer) = make_write(stream);
    let io_threads = make_io_threads(reader, writer);
    (writer_sender, reader_receiver, io_threads)
}

fn make_reader(stream: TcpStream) -> (Receiver<Message>, thread::JoinHandle<io::Result<()>>) {
    let (reader_sender, reader_receiver) = bounded::<Message>(0);
    let reader = thread::spawn(move || {
        let mut buf_read = BufReader::new(stream);
        while let Some(msg) = Message::read(&mut buf_read).unwrap() {
            let is_exit = matches!(&msg, Message::Notification(n) if n.is_exit());
            reader_sender.send(msg).unwrap();
            if is_exit {
                break;
            }
        }
        Ok(())
    });
    (reader_receiver, reader)
}

fn make_write(mut stream: TcpStream) -> (Sender<Message>, thread::JoinHandle<io::Result<()>>) {
    let (writer_sender, writer_receiver) = bounded::<Message>(0);
    let writer = thread::spawn(move || {
        writer_receiver.into_iter().try_for_each(|it| it.write(&mut stream)).unwrap();
        Ok(())
    });
    (writer_sender, writer)
}
<|endoftext|>


<commit_before>use indoc::indoc;
use serde_derive::Deserialize;
use std::fmt::Debug;

fn test_error<T>(yaml: &str, expected: &str)
where
    T: serde::de::DeserializeOwned + Debug,
{
    let result = serde_yaml::from_str::<T>(yaml);
    assert_eq!(expected, format!("{}", result.unwrap_err()));
}

#[test]
fn test_incorrect_type() {
    let yaml = indoc! {"
        ---
        str
    "};
    let expected = "invalid type: string \"str\", expected i16 at line 2 column 1";
    test_error::<i16>(yaml, expected);
}

#[test]
fn test_incorrect_nested_type() {
    #[derive(Deserialize, Debug)]
    struct A {
        #[allow(dead_code)]
        b: Vec<B>,
    }
    #[derive(Deserialize, Debug)]
    enum B {
        C(C),
    }
    #[derive(Deserialize, Debug)]
    struct C {
        #[allow(dead_code)]
        d: bool,
    }
    let yaml = indoc! {"
        ---
        b:
          - C:
              d: fase
    "};
    let expected =
        "b[0].C.d: invalid type: string \"fase\", expected a boolean at line 4 column 10";
    test_error::<A>(yaml, expected);
}

#[test]
fn test_empty() {
    let expected = "EOF while parsing a value";
    test_error::<String>("", expected);
}

#[test]
fn test_missing_field() {
    #[derive(Deserialize, Debug)]
    struct Basic {
        #[allow(dead_code)]
        v: bool,
        #[allow(dead_code)]
        w: bool,
    }
    let yaml = indoc! {"
        ---
        v: true
    "};
    let expected = "missing field `w` at line 2 column 1";
    test_error::<Basic>(yaml, expected);
}

#[test]
fn test_unknown_anchor() {
    let yaml = indoc! {"
        ---
        *some
    "};
    let expected = "unknown anchor at line 2 column 1";
    test_error::<String>(yaml, expected);
}

#[test]
fn test_ignored_unknown_anchor() {
    #[derive(Deserialize, Debug)]
    struct Wrapper {
        #[allow(dead_code)]
        c: (),
    }
    let yaml = indoc! {"
        ---
        b: [*a]
        c: ~
    "};
    let expected = "unknown anchor at line 2 column 5";
    test_error::<Wrapper>(yaml, expected);
}

#[test]
fn test_two_documents() {
    let yaml = indoc! {"
        ---
        0
        ---
        1
    "};
    let expected = "deserializing from YAML containing more than one document is not supported";
    test_error::<usize>(yaml, expected);
}

#[test]
fn test_variant_map_wrong_size() {
    #[derive(Deserialize, Debug)]
    enum E {
        V(usize),
    }
    let yaml = indoc! {r#"
        ---
        "V": 16
        "other": 32
    "#};
    let expected = "invalid length 2, expected map containing 1 entry";
    test_error::<E>(yaml, expected);
}

#[test]
fn test_variant_not_a_map() {
    #[derive(Deserialize, Debug)]
    enum E {
        V(usize),
    }
    let yaml = indoc! {r#"
        ---
        - "V"
    "#};
    let expected = "invalid type: sequence, expected string or singleton map at line 2 column 1";
    test_error::<E>(yaml, expected);
}

#[test]
fn test_variant_not_string() {
    #[derive(Deserialize, Debug)]
    enum E {
        V(bool),
    }
    let yaml = indoc! {r#"
        ---
        {}: true
    "#};
    let expected = "invalid type: map, expected variant of enum `E` at line 2 column 1";
    test_error::<E>(yaml, expected);
}

#[test]
fn test_bad_bool() {
    let yaml = indoc! {"
        ---
        !!bool str
    "};
    let expected = "invalid value: string \"str\", expected a boolean at line 2 column 1";
    test_error::<bool>(yaml, expected);
}

#[test]
fn test_bad_int() {
    let yaml = indoc! {"
        ---
        !!int str
    "};
    let expected = "invalid value: string \"str\", expected an integer at line 2 column 1";
    test_error::<i64>(yaml, expected);
}

#[test]
fn test_bad_float() {
    let yaml = indoc! {"
        ---
        !!float str
    "};
    let expected = "invalid value: string \"str\", expected a float at line 2 column 1";
    test_error::<f64>(yaml, expected);
}

#[test]
fn test_bad_null() {
    let yaml = indoc! {"
        ---
        !!null str
    "};
    let expected = "invalid value: string \"str\", expected null at line 2 column 1";
    test_error::<()>(yaml, expected);
}

#[test]
fn test_short_tuple() {
    let yaml = indoc! {"
        ---
        [0, 0]
    "};
    let expected = "invalid length 2, expected a tuple of size 3 at line 2 column 1";
    test_error::<(u8, u8, u8)>(yaml, expected);
}

#[test]
fn test_long_tuple() {
    let yaml = indoc! {"
        ---
        [0, 0, 0]
    "};
    let expected = "invalid length 3, expected sequence of 2 elements at line 2 column 1";
    test_error::<(u8, u8)>(yaml, expected);
}

#[test]
fn test_invalid_scalar_type() {
    #[derive(Deserialize, Debug)]
    struct S {
        #[allow(dead_code)]
        x: [(); 1],
    }

    let yaml = "x:\n";
    let expected = "x: invalid type: unit value, expected an array of length 1 at line 1 column 3";
    test_error::<S>(yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_infinite_recursion_objects() {
    #[derive(Deserialize, Debug)]
    struct S {
        #[allow(dead_code)]
        x: Option<Box<S>>,
    }

    let yaml = "&a {'x': *a}";
    let expected = "recursion limit exceeded at position 0";
    test_error::<S>(yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_infinite_recursion_arrays() {
    #[derive(Deserialize, Debug)]
    struct S {
        #[allow(dead_code)]
        x: Option<Box<S>>,
    }

    let yaml = "&a [*a]";
    let expected = "recursion limit exceeded at position 0";
    test_error::<S>(yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_finite_recursion_objects() {
    #[derive(Deserialize, Debug)]
    struct S {
        #[allow(dead_code)]
        x: Option<Box<S>>,
    }

    let yaml = "{'x':".repeat(1_000) + &"}".repeat(1_000);
    let expected = "recursion limit exceeded at line 1 column 641";
    test_error::<S>(&yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_finite_recursion_arrays() {
    #[derive(Deserialize, Debug)]
    struct S {
        #[allow(dead_code)]
        x: Option<Box<S>>,
    }

    let yaml = "[".repeat(1_000) + &"]".repeat(1_000);
    let expected = "recursion limit exceeded at line 1 column 129";
    test_error::<S>(&yaml, expected);
}
<commit_msg>Add test of syntax error in second document<commit_after>use indoc::indoc;
use serde_derive::Deserialize;
use serde_yaml::Deserializer;
use std::fmt::Debug;

fn test_error<T>(yaml: &str, expected: &str)
where
    T: serde::de::DeserializeOwned + Debug,
{
    let result = serde_yaml::from_str::<T>(yaml);
    assert_eq!(expected, format!("{}", result.unwrap_err()));
}

#[test]
fn test_incorrect_type() {
    let yaml = indoc! {"
        ---
        str
    "};
    let expected = "invalid type: string \"str\", expected i16 at line 2 column 1";
    test_error::<i16>(yaml, expected);
}

#[test]
fn test_incorrect_nested_type() {
    #[derive(Deserialize, Debug)]
    struct A {
        #[allow(dead_code)]
        b: Vec<B>,
    }
    #[derive(Deserialize, Debug)]
    enum B {
        C(C),
    }
    #[derive(Deserialize, Debug)]
    struct C {
        #[allow(dead_code)]
        d: bool,
    }
    let yaml = indoc! {"
        ---
        b:
          - C:
              d: fase
    "};
    let expected =
        "b[0].C.d: invalid type: string \"fase\", expected a boolean at line 4 column 10";
    test_error::<A>(yaml, expected);
}

#[test]
fn test_empty() {
    let expected = "EOF while parsing a value";
    test_error::<String>("", expected);
}

#[test]
fn test_missing_field() {
    #[derive(Deserialize, Debug)]
    struct Basic {
        #[allow(dead_code)]
        v: bool,
        #[allow(dead_code)]
        w: bool,
    }
    let yaml = indoc! {"
        ---
        v: true
    "};
    let expected = "missing field `w` at line 2 column 1";
    test_error::<Basic>(yaml, expected);
}

#[test]
fn test_unknown_anchor() {
    let yaml = indoc! {"
        ---
        *some
    "};
    let expected = "unknown anchor at line 2 column 1";
    test_error::<String>(yaml, expected);
}

#[test]
fn test_ignored_unknown_anchor() {
    #[derive(Deserialize, Debug)]
    struct Wrapper {
        #[allow(dead_code)]
        c: (),
    }
    let yaml = indoc! {"
        ---
        b: [*a]
        c: ~
    "};
    let expected = "unknown anchor at line 2 column 5";
    test_error::<Wrapper>(yaml, expected);
}

#[test]
fn test_two_documents() {
    let yaml = indoc! {"
        ---
        0
        ---
        1
    "};
    let expected = "deserializing from YAML containing more than one document is not supported";
    test_error::<usize>(yaml, expected);
}

#[test]
fn test_second_document_syntax_error() {
    let yaml = indoc! {"
        ---
        0
        ---
        ]
    "};

    let mut de = Deserializer::from_str(yaml);
    let first_doc = de.next().unwrap();
    let result = <usize as serde::Deserialize>::deserialize(first_doc);
    assert_eq!(0, result.unwrap());

    let second_doc = de.next().unwrap();
    let result = <usize as serde::Deserialize>::deserialize(second_doc);
    let expected = "did not find expected node content at line 4 column 1, while parsing a block node at line 4 column 1";
    assert_eq!(expected, result.unwrap_err().to_string());
}

#[test]
fn test_variant_map_wrong_size() {
    #[derive(Deserialize, Debug)]
    enum E {
        V(usize),
    }
    let yaml = indoc! {r#"
        ---
        "V": 16
        "other": 32
    "#};
    let expected = "invalid length 2, expected map containing 1 entry";
    test_error::<E>(yaml, expected);
}

#[test]
fn test_variant_not_a_map() {
    #[derive(Deserialize, Debug)]
    enum E {
        V(usize),
    }
    let yaml = indoc! {r#"
        ---
        - "V"
    "#};
    let expected = "invalid type: sequence, expected string or singleton map at line 2 column 1";
    test_error::<E>(yaml, expected);
}

#[test]
fn test_variant_not_string() {
    #[derive(Deserialize, Debug)]
    enum E {
        V(bool),
    }
    let yaml = indoc! {r#"
        ---
        {}: true
    "#};
    let expected = "invalid type: map, expected variant of enum `E` at line 2 column 1";
    test_error::<E>(yaml, expected);
}

#[test]
fn test_bad_bool() {
    let yaml = indoc! {"
        ---
        !!bool str
    "};
    let expected = "invalid value: string \"str\", expected a boolean at line 2 column 1";
    test_error::<bool>(yaml, expected);
}

#[test]
fn test_bad_int() {
    let yaml = indoc! {"
        ---
        !!int str
    "};
    let expected = "invalid value: string \"str\", expected an integer at line 2 column 1";
    test_error::<i64>(yaml, expected);
}

#[test]
fn test_bad_float() {
    let yaml = indoc! {"
        ---
        !!float str
    "};
    let expected = "invalid value: string \"str\", expected a float at line 2 column 1";
    test_error::<f64>(yaml, expected);
}

#[test]
fn test_bad_null() {
    let yaml = indoc! {"
        ---
        !!null str
    "};
    let expected = "invalid value: string \"str\", expected null at line 2 column 1";
    test_error::<()>(yaml, expected);
}

#[test]
fn test_short_tuple() {
    let yaml = indoc! {"
        ---
        [0, 0]
    "};
    let expected = "invalid length 2, expected a tuple of size 3 at line 2 column 1";
    test_error::<(u8, u8, u8)>(yaml, expected);
}

#[test]
fn test_long_tuple() {
    let yaml = indoc! {"
        ---
        [0, 0, 0]
    "};
    let expected = "invalid length 3, expected sequence of 2 elements at line 2 column 1";
    test_error::<(u8, u8)>(yaml, expected);
}

#[test]
fn test_invalid_scalar_type() {
    #[derive(Deserialize, Debug)]
    struct S {
        #[allow(dead_code)]
        x: [(); 1],
    }

    let yaml = "x:\n";
    let expected = "x: invalid type: unit value, expected an array of length 1 at line 1 column 3";
    test_error::<S>(yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_infinite_recursion_objects() {
    #[derive(Deserialize, Debug)]
    struct S {
        #[allow(dead_code)]
        x: Option<Box<S>>,
    }

    let yaml = "&a {'x': *a}";
    let expected = "recursion limit exceeded at position 0";
    test_error::<S>(yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_infinite_recursion_arrays() {
    #[derive(Deserialize, Debug)]
    struct S {
        #[allow(dead_code)]
        x: Option<Box<S>>,
    }

    let yaml = "&a [*a]";
    let expected = "recursion limit exceeded at position 0";
    test_error::<S>(yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_finite_recursion_objects() {
    #[derive(Deserialize, Debug)]
    struct S {
        #[allow(dead_code)]
        x: Option<Box<S>>,
    }

    let yaml = "{'x':".repeat(1_000) + &"}".repeat(1_000);
    let expected = "recursion limit exceeded at line 1 column 641";
    test_error::<S>(&yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_finite_recursion_arrays() {
    #[derive(Deserialize, Debug)]
    struct S {
        #[allow(dead_code)]
        x: Option<Box<S>>,
    }

    let yaml = "[".repeat(1_000) + &"]".repeat(1_000);
    let expected = "recursion limit exceeded at line 1 column 129";
    test_error::<S>(&yaml, expected);
}
<|endoftext|>


<commit_before>// Copyright 2015 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use kernel::*;
use search::search_tree_visitor::*;
use search::search_tree_visitor::Status::*;
use search::branching::branch::*;
use search::engine::PartialExploration;
use gcollections::ops::sequence::*;
use std::marker::PhantomData;

struct PhantomData3<T1,T2,T3> {
  t1: PhantomData<T1>,
  t2: PhantomData<T2>,
  t3: PhantomData<T3>
}

impl<T1,T2,T3> PhantomData3<T1,T2,T3> {
  fn new() -> PhantomData3<T1,T2,T3> {
    PhantomData3 {
      t1: PhantomData,
      t2: PhantomData,
      t3: PhantomData
    }
  }
}

pub struct OneSolution<C, Q, Space, OrderPush, OrderPop> {
  child: C,
  queue: Q,
  exploring: bool,
  phantom_types: PhantomData3<Space, OrderPush, OrderPop>
}

impl<C, Q, Space, OrderPush, OrderPop> PartialExploration for OneSolution<C, Q, Space, OrderPush, OrderPop> {}

impl<C, Q, Space, OrderPush, OrderPop> OneSolution<C, Q, Space, OrderPush, OrderPop> where
 Space: State,
 C: SearchTreeVisitor<Space>,
 Q: Sequence<OrderPush, OrderPop, Branch<Space>>
{
  pub fn new(child: C) -> OneSolution<C, Q, Space, OrderPush, OrderPop>
  {
    OneSolution {
      queue: Q::empty(),
      child: child,
      exploring: false,
      phantom_types: PhantomData3::new()
    }
  }

  fn push_branches(&mut self, branches: Vec<Branch<Space>>)
  {
    for branch in branches {
      self.queue.push(branch);
    }
  }

  fn enter_child(&mut self, current: Space, status: &mut Status<Space>) -> Space
  {
    let (current, child_status) = self.child.enter(current);
    match child_status {
      Unknown(branches) => self.push_branches(branches),
      Satisfiable => *status = Satisfiable,
      Pruned => *status = Pruned,
      _ => ()
    }
    current
  }

  // Only visit the root if we didn't visit it before (based on the queue emptiness).
  fn enter_root(&mut self, root: Space, status: &mut Status<Space>) -> Space
  {
    if self.queue.is_empty() && !self.exploring {
      self.exploring = true;
      self.enter_child(root, status)
    } else {
      root
    }
  }
}

impl<C, Q, Space, OrderPush, OrderPop> SearchTreeVisitor<Space> for OneSolution<C, Q, Space, OrderPush, OrderPop> where
 Space: State,
 C: SearchTreeVisitor<Space>,
 Q: Sequence<OrderPush, OrderPop, Branch<Space>>
{
  fn start(&mut self, root: &Space) {
    self.queue = Q::empty();
    self.exploring = false;
    self.child.start(root);
  }

  fn enter(&mut self, root: Space) -> (Space, Status<Space>) {
    let mut status = Unsatisfiable;
    let mut current = self.enter_root(root, &mut status);
    while status != Satisfiable && !self.queue.is_empty() {
      let branch = self.queue.pop().unwrap();
      let child = branch.commit(current);
      current = self.enter_child(child, &mut status);
    }
    (current, status)
  }
}

#[cfg(test)]
mod test {
  use super::*;
  use interval::interval::*;
  use interval::ops::*;
  use gcollections::wrappers::vector::*;
  use gcollections::ops::sequence::ordering::*;
  use kernel::*;
  use propagation::store::Store;
  use propagation::events::*;
  use propagation::reactors::*;
  use propagation::schedulers::*;
  use propagators::cmp::*;
  use propagators::distinct::*;
  use variable::ops::*;
  use variable::delta_store::DeltaStore;
  use term::*;
  use search::search_tree_visitor::*;
  use search::search_tree_visitor::Status::*;
  use search::space::*;
  use search::propagation::*;
  use search::branching::binary_split::*;
  use search::branching::brancher::*;
  use search::branching::first_smallest_var::*;
  use test::Bencher;

  type VStore = DeltaStore<Interval<i32>, FDEvent>;
  type CStore = Store<VStore, FDEvent, IndexedDeps, RelaxedFifo>;
  type FDSpace = Space<VStore, CStore>;

  #[test]
  fn example_nqueens() {
    nqueens(1, Satisfiable);
    nqueens(2, Unsatisfiable);
    nqueens(3, Unsatisfiable);
    for i in 4..12 {
      nqueens(i, Satisfiable);
    }
  }

  #[bench]
  fn bench_nqueens10(b: &mut Bencher) {
    b.iter(|| {
        nqueens(10, Satisfiable)
    });
  }

  fn nqueens(n: usize, expect: Status<FDSpace>) {
    let mut space = FDSpace::default();
    let mut queens = vec![];
    // 2 queens can't share the same line.
    for _ in 0..n {
      queens.push(space.vstore.alloc((1, n as i32).to_interval()));
    }
    for i in 0..n-1 {
      for j in i + 1..n {
        // 2 queens can't share the same diagonal.
        let q1 = (i + 1) as i32;
        let q2 = (j + 1) as i32;
        // Xi + i != Xj + j
        space.cstore.alloc(XNeqY::new(queens[i].clone(), Addition::new(queens[j].clone(), q2 - q1)));
        // Xi - i != Xj - j
        space.cstore.alloc(XNeqY::new(queens[i].clone(), Addition::new(queens[j].clone(), -q2 + q1)));
      }
    }
    // 2 queens can't share the same column.
    space.cstore.alloc(Distinct::new(queens));

    let mut search: OneSolution<_, Vector<_>, FDSpace, Back, Back> = OneSolution::new(Propagation::new(Brancher::new(FirstSmallestVar, BinarySplit)));
    search.start(&space);
    let (_, status) = search.enter(space);
    assert_eq!(status, expect);
  }
}
<commit_msg>[Search][Engine] Use Multiset requirements, less type parameters needed.<commit_after>// Copyright 2015 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use kernel::*;
use search::search_tree_visitor::*;
use search::search_tree_visitor::Status::*;
use search::branching::branch::*;
use search::engine::PartialExploration;
use gcollections::ops::multiset::*;
use std::marker::PhantomData;

pub struct OneSolution<C, Q, Space> {
  child: C,
  queue: Q,
  exploring: bool,
  phantom_space: PhantomData<Space>
}

impl<C, Q, Space> PartialExploration for OneSolution<C, Q, Space> {}

impl<C, Q, Space> OneSolution<C, Q, Space> where
 Space: State,
 C: SearchTreeVisitor<Space>,
 Q: Multiset<Branch<Space>>
{
  pub fn new(child: C) -> OneSolution<C, Q, Space>
  {
    OneSolution {
      queue: Q::empty(),
      child: child,
      exploring: false,
      phantom_space: PhantomData
    }
  }

  fn push_branches(&mut self, branches: Vec<Branch<Space>>)
  {
    for branch in branches {
      self.queue.insert(branch);
    }
  }

  fn enter_child(&mut self, current: Space, status: &mut Status<Space>) -> Space
  {
    let (current, child_status) = self.child.enter(current);
    match child_status {
      Unknown(branches) => self.push_branches(branches),
      Satisfiable => *status = Satisfiable,
      Pruned => *status = Pruned,
      _ => ()
    }
    current
  }

  // Only visit the root if we didn't visit it before (based on the queue emptiness).
  fn enter_root(&mut self, root: Space, status: &mut Status<Space>) -> Space
  {
    if self.queue.is_empty() && !self.exploring {
      self.exploring = true;
      self.enter_child(root, status)
    } else {
      root
    }
  }
}

impl<C, Q, Space> SearchTreeVisitor<Space> for OneSolution<C, Q, Space> where
 Space: State,
 C: SearchTreeVisitor<Space>,
 Q: Multiset<Branch<Space>>
{
  fn start(&mut self, root: &Space) {
    self.queue = Q::empty();
    self.exploring = false;
    self.child.start(root);
  }

  fn enter(&mut self, root: Space) -> (Space, Status<Space>) {
    let mut status = Unsatisfiable;
    let mut current = self.enter_root(root, &mut status);
    while status != Satisfiable && !self.queue.is_empty() {
      let branch = self.queue.extract().unwrap();
      let child = branch.commit(current);
      current = self.enter_child(child, &mut status);
    }
    (current, status)
  }
}

#[cfg(test)]
mod test {
  use super::*;
  use interval::interval::*;
  use interval::ops::*;
  use gcollections::wrappers::Vector;
  use kernel::*;
  use propagation::store::Store;
  use propagation::events::*;
  use propagation::reactors::*;
  use propagation::schedulers::*;
  use propagators::cmp::*;
  use propagators::distinct::*;
  use variable::ops::*;
  use variable::delta_store::DeltaStore;
  use term::*;
  use search::search_tree_visitor::*;
  use search::search_tree_visitor::Status::*;
  use search::space::*;
  use search::propagation::*;
  use search::branching::binary_split::*;
  use search::branching::brancher::*;
  use search::branching::first_smallest_var::*;
  use test::Bencher;

  type VStore = DeltaStore<Interval<i32>, FDEvent>;
  type CStore = Store<VStore, FDEvent, IndexedDeps, RelaxedFifo>;
  type FDSpace = Space<VStore, CStore>;

  #[test]
  fn example_nqueens() {
    nqueens(1, Satisfiable);
    nqueens(2, Unsatisfiable);
    nqueens(3, Unsatisfiable);
    for i in 4..12 {
      nqueens(i, Satisfiable);
    }
  }

  #[bench]
  fn bench_nqueens10(b: &mut Bencher) {
    b.iter(|| {
        nqueens(10, Satisfiable)
    });
  }

  fn nqueens(n: usize, expect: Status<FDSpace>) {
    let mut space = FDSpace::default();
    let mut queens = vec![];
    // 2 queens can't share the same line.
    for _ in 0..n {
      queens.push(space.vstore.alloc((1, n as i32).to_interval()));
    }
    for i in 0..n-1 {
      for j in i + 1..n {
        // 2 queens can't share the same diagonal.
        let q1 = (i + 1) as i32;
        let q2 = (j + 1) as i32;
        // Xi + i != Xj + j
        space.cstore.alloc(XNeqY::new(queens[i].clone(), Addition::new(queens[j].clone(), q2 - q1)));
        // Xi - i != Xj - j
        space.cstore.alloc(XNeqY::new(queens[i].clone(), Addition::new(queens[j].clone(), -q2 + q1)));
      }
    }
    // 2 queens can't share the same column.
    space.cstore.alloc(Distinct::new(queens));

    let mut search: OneSolution<_, Vector<_>, FDSpace> = OneSolution::new(Propagation::new(Brancher::new(FirstSmallestVar, BinarySplit)));
    search.start(&space);
    let (_, status) = search.enter(space);
    assert_eq!(status, expect);
  }
}
<|endoftext|>