<commit_before>
mod alias {
    pub enum Commands {
        NewBeacon = 15,
        DelBeacon = 17,
        RegisterAction = 60,
        Action = 62,
        ActionTxStatus = 64,
    }
}

// Commands
// Do not change order; acts as ABI
pub enum Commands {
    Unspec,
    GetWiPhy,
    SetWiPhy,
    NewWiPhy,
    DelWiPhy,

    GetInterface,
    SetInterface,
    NewInterface,
    DelIntreface,

    GetKey,
    SetKey,
    NewKey,
    DelKey,

    GetBeacon,
    SetBeacon,
    StartAp,
    AliasNewBeacon, // StartAp alias
    StopAp,
    AliasDelBeacon, // StopAp alias

    GetStation,
    SetStation,
    NewStation,
    DelStation,

    GetMPath,
    SetMPath,
    NewMPath,
    DelMPath,

    SetBss,

    SetReg,
    ReqSetReg,

    GetMeshConfig,
    SetMeshConfig,

    SetMgmtExtraIe, // Reserved; not used

    GetReg,

    GetScan,
    TriggerScan,
    NewScanResults,
    ScanAborted,

    RegChange,

    Authenticate,
    Associate,
    Deauthenticate,
    Disassociate,

    MichaelMicFailure,

    RegBeaconHint,

    JoinIbss,
    LeaveIbss,

    TestMode,
    Connect,
    Roam,
    Disconnect,

    SetWiPhyNetNs,

    GetSurvey,
    NewSurveyResults,

    SetPmksa,
    DelPmksa,
    FlushPmksa,

    RemainOnChannel,
    CancelRemainOnChannel,

    SetTxBitrateMask,

    RegisterFrame,
    AliasRegisterAction, // RegisterFrame alias
    Frame,
    AliasAction,         // Frame alias
    FrameTxStatus,
    AliasActionTxStatus, // FrameTxStatus

    SetPowerSave,
    GetPowerSave,

    SetCqm,
    NotifyCqm,

    SetChannel,
    SetWdsPeer,

    FrameWaitCancel,

    JoinMesh,
    LeaveMesh,

    UnprotDeathenticate,
    UnProtDisassociate,

    NewPeerCandidate,

    GetWowLan,
    SetWowLan,

    StartSchedScan,
    StopSchedScan,
    SchedScanResults,
    SchedScanStopped,

    SetRekeyOffload,

    PmksaCandidate,

    TdlsOper,
    TdlsMgmt,

    UnexpectedFrame,

    ProbeClient,

    RegisterBeacons,

    Unexpected4AddrFrame,

    SetNoAckMap,

    ChSwitchNotify,

    StartP2pDevice,
    StopP2pDevice,

    ConnFailed,

    SetMcastRate,

    SetMacAcl,

    RadarDetect,

    GetProtocolFeatures,

    UpdateFtIes,
    FtEvent,

    CritProtocolState,
    CritProtocolStop,

    GetCoalesce,
    SetCoalesce,

    Vendor,

    SetQosMap,

    AddTxTs,
    DelTxTs,

    GetMpp,

    AfterLast
}

// attributes
// Do not change order; acts as ABI
pub enum Attrs {
    Unspec,

    WiPhy,
    WiPhyName,

    IfIndex,
    IfName,
    IfType,

    Mac,

    KeyData,
    KeyIdx,
    KeyCipher,
    KeySeq,
    KeyDefault,

    BeaconInterval,
    DtimPeriod,
    BeaconHead,
    BeaconTail,

    StaAid,
    StaFlags,
    StaListenInterval,
    StaSupportedRates,
    StaVlan,
    StaInfo,

    WiPhyBands,

    MntrFlags,

    MeshId,
    StaPlinkAction,
    MpathNextHop,
    MpathInfo,

    BssCtsProt,
    BssShortPreamble,
    BssShortSlotTime,

    HtCapability,

    SupportedIfTypes,

    RegAlpha2,
    RegRules,

    MeshConfig,

    BssBasicRates,

    WiPhyTxqParams,
    WiPhyFreq,
    WiPhyChannelType,

    KeyDefaultMgmt,

    MgmtSubtype,
    Ie,

    MaxNumScanSsids,

    ScanFrequencies,
    ScanSsids,
    Generation,
    Bss,

    RegInitiator,
    RegType,

    SupportedCommands,

    Frame,
    Ssid,
    AuthType,
    ReasonCode,

    KeyType,

    MaxScanIeLen,
    CipherSuites,

    FreqBefore,
    FreqAfter,

    FreqFixed,

    WiPhyRetryShort,
    WiPhyRetryLong,
    WiPhyFragThreshold,
    WiPhyRtsThreshold,

    TimedOut,

    UseMfp,

    StaFlags2,

    ControlPort,

    TestData,

    Privacy,

    DisconnectedByAp,

    StatusCode,

    CipherSuitesPairwise,
    CipherSuiteGroup,
    WpaVersions,
    AkmSuites,

    ReqIe,
    RespIe,

    PrevBssid,

    Key,
    Keys,

    Pid,

    Addr4,

    SurveyInfo,

    PmkId,
    MaxNumPmkIds,

    Duration,

    Cookie,

    WiPhyCoverageClass,

    TxRates,

    FrameMatch,

    Ack,

    PsState,

    Cqm,

    LocalStateChange,

    ApIsolate,

    WiPhyTxPowerSetting,
    WiPhyTxPowerLevel,

    TxFrameTypes,
    RxFrameTypes,
    FrameType,

    ControlPortEthertype,
    ControlPortNoEncrypt,

    SupportIbssRsn,

    WiPhyAntennaTx,
    WiPhyAntennaRx,

    McastRate,

    OffChannelTxOk,

    BssHtOpmode,

    KeyDefaultTypes,

    MaxRemainOnChannelDuration,

    MeshSetup,

    WiPhyAntennaAvailTx,
    WiPhyAntennaAvailRx,

    SupportMeshAuth,
    StaPlinkState,

    WowLanTriggers,
    WowLanTriggersSupported,

    SchedScanInterval,

    InterfaceCombinations,
    SoftwareIfTypes,

    RekeyData,

    MaxNumSchedScanSsids,
    MaxSchedScanIeLen,

    ScanSuppRates,

    HiddenSsid,

    IeProbeResp,
    IeAssocResp,

    StaWme,
    SupportApUapsd,

    RoamSupport,

    AttrSchedScanMatch,
    MaxMatchSets,

    PmksaCandidate,

    TxNoCckRate,

    TdlsAction,
    TdlsDialogToken,
    TdlsOperation,
    TdlsSupport,
    TdlsExternalSetup,

    DeviceApSme,

    DontWaitForAck,

    FeatureFlags,

    ProbeRespOffload,

    ProbeResp,

    DfsRegion,

    DisableHt,
    HtCapabilityMask,

    NoackMap,

    InactivityTimeout,

    RxSignalDbm,

    BgScanPeriod,

    Wdev,

    UserRegHintType,

    ConnFailedReason,

    SaeData,

    VhtCapability,

    ScanFlags,

    ChannelWidth,
    CenterFreq1,
    CenterFreq2,

    P2pCtwindow,
    P2pOppps,

    LocalMeshPowerMode,

    AclPolicy,

    MacAddrs,

    MacAclMax,

    RadarEvent,

    ExtCapa,

    ExtCapaMask,

    StaCapability,
    StaExtCapability,

    ProtocolFeatures,
    SplitWiphyDump,

    DisableVht,
    VhtCapabilityMask,

    Mdid,

    IeRic,

    CritProtId,
    MaxCritProtDuration,

    PeerAid,

    CoalesceRule,

    ChSwitchCount,
    ChSwitchBlockTx,
    CsaIes,
    CsaCOffBeacon,
    CsaCOffPresp,

    RxmgmtFlags,

    StaSupportedChannels,
    StaSipportedOperClasses,

    HandleDfs,

    Support5Mhz,
    Support10Mhz,

    OpmodeNotif,

    VendorId,
    VendorSubcmd,
    VendorData,
    VendorEvents,

    QodMap,

    MacHint,
    WiPhyFreqHint,

    MaxApAssocSta,

    TdlsPeerCapability,

    IfaceSocketOwnder,
    CsaCOffsetsTx,
    MaxCsaCounters,

    TdlsInitiator,

    UseRrm,

    WiPhyDynAck,

    Tsid,
    UserPrio,
    AdmittedTime,

    SmpsMode,

    AfterLast
}

// Interface types
pub enum IfType {
    Unspecified,
    AdHoc,
    Station,
    Ap,
    ApVlan,
    Wds,
    Monitor,
    MeshPoint,
    P2pClient,
    P2pGo,
    P2pDevice,

    NumIfTypes
}

// Station flags
pub enum StaFlags {
    __Invalid,
    Authorized,
    ShortPreamble,
    Wme,
    Mfp,
    Authenticated,
    TdlsPeer,
    Associated,
    AfterLast
}

#[repr(C, packed)]
pub struct StaFlagUpdate {
    mask: u32,
    set: u32,
}

// attrubtes for getting station bitrate information
pub enum RateInfo {
    __Invalid,
    Bitrate,
    Mcs,
    Width40Mhz,
    ShortGi,
    Bitrate32,
    VhtMcs,
    VhtNss,
    Width80Mhz,
    Width80P80Mhz,
    Width160Mhz,

    AfterLast
}

pub enum StaBssParam {
    __Invalid,
    CtsProt,
    ShortPreamble,
    ShortSlotTime,
    DtimPeriod,
    BeaconInterval,

    AfterLast
}

pub enum StaInfo {
    __Invalid,
    InactiveTime,
    RxBytes,
    TxBytes,
    Llid,
    Plid,
    PlinkState,
    Signal,
    TxBitrate,
    RxPackets,
    TxPackets,
    TxRetries,
    TxFailed,
    SignalAvg,
    RxBitrate,
    BssParam,
    ConnectedTime,
    StaFlags,
    BeaconLoss,
    TOffset,
    LocalPm,
    PeerPm,
    NonpeerPm,
    RxBytes64,
    TxBytes64,
    ChainSignal,
    ChainSignalAvg,
    ExpectedThroughput,

    AfterLast
}

pub enum MpathFlags {
    Active = 1,
    Resolving = 2,
    SnValid = 4,
    Fixed = 8,
    Resolved = 16
}

pub enum MpathInfo {
    __Invalid,
    FrameQlen,
    Sn,
    Metric,
    Exptime,
    Flags,
    DiscoveryTimeout,
    DiscoveryRetries,

    AfterLast,
}

<commit_msg>include Band attributes<commit_after>
mod alias {
    pub enum Commands {
        NewBeacon = 15,
        DelBeacon = 17,
        RegisterAction = 60,
        Action = 62,
        ActionTxStatus = 64,
    }
}

// Commands
// Do not change order; acts as ABI
pub enum Commands {
    Unspec,
    GetWiPhy,
    SetWiPhy,
    NewWiPhy,
    DelWiPhy,

    GetInterface,
    SetInterface,
    NewInterface,
    DelIntreface,

    GetKey,
    SetKey,
    NewKey,
    DelKey,

    GetBeacon,
    SetBeacon,
    StartAp,
    AliasNewBeacon, // StartAp alias
    StopAp,
    AliasDelBeacon, // StopAp alias

    GetStation,
    SetStation,
    NewStation,
    DelStation,

    GetMPath,
    SetMPath,
    NewMPath,
    DelMPath,

    SetBss,

    SetReg,
    ReqSetReg,

    GetMeshConfig,
    SetMeshConfig,

    SetMgmtExtraIe, // Reserved; not used

    GetReg,

    GetScan,
    TriggerScan,
    NewScanResults,
    ScanAborted,

    RegChange,

    Authenticate,
    Associate,
    Deauthenticate,
    Disassociate,

    MichaelMicFailure,

    RegBeaconHint,

    JoinIbss,
    LeaveIbss,

    TestMode,
    Connect,
    Roam,
    Disconnect,

    SetWiPhyNetNs,

    GetSurvey,
    NewSurveyResults,

    SetPmksa,
    DelPmksa,
    FlushPmksa,

    RemainOnChannel,
    CancelRemainOnChannel,

    SetTxBitrateMask,

    RegisterFrame,
    AliasRegisterAction, // RegisterFrame alias
    Frame,
    AliasAction,         // Frame alias
    FrameTxStatus,
    AliasActionTxStatus, // FrameTxStatus

    SetPowerSave,
    GetPowerSave,

    SetCqm,
    NotifyCqm,

    SetChannel,
    SetWdsPeer,

    FrameWaitCancel,

    JoinMesh,
    LeaveMesh,

    UnprotDeathenticate,
    UnProtDisassociate,

    NewPeerCandidate,

    GetWowLan,
    SetWowLan,

    StartSchedScan,
    StopSchedScan,
    SchedScanResults,
    SchedScanStopped,

    SetRekeyOffload,

    PmksaCandidate,

    TdlsOper,
    TdlsMgmt,

    UnexpectedFrame,

    ProbeClient,

    RegisterBeacons,

    Unexpected4AddrFrame,

    SetNoAckMap,

    ChSwitchNotify,

    StartP2pDevice,
    StopP2pDevice,

    ConnFailed,

    SetMcastRate,

    SetMacAcl,

    RadarDetect,

    GetProtocolFeatures,

    UpdateFtIes,
    FtEvent,

    CritProtocolState,
    CritProtocolStop,

    GetCoalesce,
    SetCoalesce,

    Vendor,

    SetQosMap,

    AddTxTs,
    DelTxTs,

    GetMpp,

    AfterLast
}

// attributes
// Do not change order; acts as ABI
pub enum Attrs {
    Unspec,

    WiPhy,
    WiPhyName,

    IfIndex,
    IfName,
    IfType,

    Mac,

    KeyData,
    KeyIdx,
    KeyCipher,
    KeySeq,
    KeyDefault,

    BeaconInterval,
    DtimPeriod,
    BeaconHead,
    BeaconTail,

    StaAid,
    StaFlags,
    StaListenInterval,
    StaSupportedRates,
    StaVlan,
    StaInfo,

    WiPhyBands,

    MntrFlags,

    MeshId,
    StaPlinkAction,
    MpathNextHop,
    MpathInfo,

    BssCtsProt,
    BssShortPreamble,
    BssShortSlotTime,

    HtCapability,

    SupportedIfTypes,

    RegAlpha2,
    RegRules,

    MeshConfig,

    BssBasicRates,

    WiPhyTxqParams,
    WiPhyFreq,
    WiPhyChannelType,

    KeyDefaultMgmt,

    MgmtSubtype,
    Ie,

    MaxNumScanSsids,

    ScanFrequencies,
    ScanSsids,
    Generation,
    Bss,

    RegInitiator,
    RegType,

    SupportedCommands,

    Frame,
    Ssid,
    AuthType,
    ReasonCode,

    KeyType,

    MaxScanIeLen,
    CipherSuites,

    FreqBefore,
    FreqAfter,

    FreqFixed,

    WiPhyRetryShort,
    WiPhyRetryLong,
    WiPhyFragThreshold,
    WiPhyRtsThreshold,

    TimedOut,

    UseMfp,

    StaFlags2,

    ControlPort,

    TestData,

    Privacy,

    DisconnectedByAp,

    StatusCode,

    CipherSuitesPairwise,
    CipherSuiteGroup,
    WpaVersions,
    AkmSuites,

    ReqIe,
    RespIe,

    PrevBssid,

    Key,
    Keys,

    Pid,

    Addr4,

    SurveyInfo,

    PmkId,
    MaxNumPmkIds,

    Duration,

    Cookie,

    WiPhyCoverageClass,

    TxRates,

    FrameMatch,

    Ack,

    PsState,

    Cqm,

    LocalStateChange,

    ApIsolate,

    WiPhyTxPowerSetting,
    WiPhyTxPowerLevel,

    TxFrameTypes,
    RxFrameTypes,
    FrameType,

    ControlPortEthertype,
    ControlPortNoEncrypt,

    SupportIbssRsn,

    WiPhyAntennaTx,
    WiPhyAntennaRx,

    McastRate,

    OffChannelTxOk,

    BssHtOpmode,

    KeyDefaultTypes,

    MaxRemainOnChannelDuration,

    MeshSetup,

    WiPhyAntennaAvailTx,
    WiPhyAntennaAvailRx,

    SupportMeshAuth,
    StaPlinkState,

    WowLanTriggers,
    WowLanTriggersSupported,

    SchedScanInterval,

    InterfaceCombinations,
    SoftwareIfTypes,

    RekeyData,

    MaxNumSchedScanSsids,
    MaxSchedScanIeLen,

    ScanSuppRates,

    HiddenSsid,

    IeProbeResp,
    IeAssocResp,

    StaWme,
    SupportApUapsd,

    RoamSupport,

    AttrSchedScanMatch,
    MaxMatchSets,

    PmksaCandidate,

    TxNoCckRate,

    TdlsAction,
    TdlsDialogToken,
    TdlsOperation,
    TdlsSupport,
    TdlsExternalSetup,

    DeviceApSme,

    DontWaitForAck,

    FeatureFlags,

    ProbeRespOffload,

    ProbeResp,

    DfsRegion,

    DisableHt,
    HtCapabilityMask,

    NoackMap,

    InactivityTimeout,

    RxSignalDbm,

    BgScanPeriod,

    Wdev,

    UserRegHintType,

    ConnFailedReason,

    SaeData,

    VhtCapability,

    ScanFlags,

    ChannelWidth,
    CenterFreq1,
    CenterFreq2,

    P2pCtwindow,
    P2pOppps,

    LocalMeshPowerMode,

    AclPolicy,

    MacAddrs,

    MacAclMax,

    RadarEvent,

    ExtCapa,

    ExtCapaMask,

    StaCapability,
    StaExtCapability,

    ProtocolFeatures,
    SplitWiphyDump,

    DisableVht,
    VhtCapabilityMask,

    Mdid,

    IeRic,

    CritProtId,
    MaxCritProtDuration,

    PeerAid,

    CoalesceRule,

    ChSwitchCount,
    ChSwitchBlockTx,
    CsaIes,
    CsaCOffBeacon,
    CsaCOffPresp,

    RxmgmtFlags,

    StaSupportedChannels,
    StaSipportedOperClasses,

    HandleDfs,

    Support5Mhz,
    Support10Mhz,

    OpmodeNotif,

    VendorId,
    VendorSubcmd,
    VendorData,
    VendorEvents,

    QodMap,

    MacHint,
    WiPhyFreqHint,

    MaxApAssocSta,

    TdlsPeerCapability,

    IfaceSocketOwnder,
    CsaCOffsetsTx,
    MaxCsaCounters,

    TdlsInitiator,

    UseRrm,

    WiPhyDynAck,

    Tsid,
    UserPrio,
    AdmittedTime,

    SmpsMode,

    AfterLast
}

// Interface types
pub enum IfType {
    Unspecified,
    AdHoc,
    Station,
    Ap,
    ApVlan,
    Wds,
    Monitor,
    MeshPoint,
    P2pClient,
    P2pGo,
    P2pDevice,

    NumIfTypes
}

// Station flags
pub enum StaFlags {
    __Invalid,
    Authorized,
    ShortPreamble,
    Wme,
    Mfp,
    Authenticated,
    TdlsPeer,
    Associated,
    AfterLast
}

#[repr(C, packed)]
pub struct StaFlagUpdate {
    mask: u32,
    set: u32,
}

// attrubtes for getting station bitrate information
pub enum RateInfo {
    __Invalid,
    Bitrate,
    Mcs,
    Width40Mhz,
    ShortGi,
    Bitrate32,
    VhtMcs,
    VhtNss,
    Width80Mhz,
    Width80P80Mhz,
    Width160Mhz,

    AfterLast
}

pub enum StaBssParam {
    __Invalid,
    CtsProt,
    ShortPreamble,
    ShortSlotTime,
    DtimPeriod,
    BeaconInterval,

    AfterLast
}

pub enum StaInfo {
    __Invalid,
    InactiveTime,
    RxBytes,
    TxBytes,
    Llid,
    Plid,
    PlinkState,
    Signal,
    TxBitrate,
    RxPackets,
    TxPackets,
    TxRetries,
    TxFailed,
    SignalAvg,
    RxBitrate,
    BssParam,
    ConnectedTime,
    StaFlags,
    BeaconLoss,
    TOffset,
    LocalPm,
    PeerPm,
    NonpeerPm,
    RxBytes64,
    TxBytes64,
    ChainSignal,
    ChainSignalAvg,
    ExpectedThroughput,

    AfterLast
}

pub enum MpathFlags {
    Active = 1,
    Resolving = 2,
    SnValid = 4,
    Fixed = 8,
    Resolved = 16
}

pub enum MpathInfo {
    __Invalid,
    FrameQlen,
    Sn,
    Metric,
    Exptime,
    Flags,
    DiscoveryTimeout,
    DiscoveryRetries,

    AfterLast,
}

pub enum BandAttr {
    __Invalid,
    Freq,
    Rates,

    HtMcsSet,
    HdCapa,
    HtAmpduFactor,
    HtAmpduDensity,

    VhtMcsSet,
    VhtCapa,

    AfterLast,
}

<|endoftext|>


<commit_before>#![allow(dead_code)]
#![allow(unused_variables)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]

extern crate libc;
extern crate rustc_serialize;

use rustc_serialize::json;
use std::ffi::CString;

pub mod postgres;
pub mod postgres_bindings;
pub mod types;

use types::{
    Change,
};

use postgres::{
    pg_tuple_to_rspgod_tuple,
};

use postgres_bindings::{
    LogicalDecodingContext,
    OutputPluginOptions,
    Relation,
    ReorderBufferChange,
    ReorderBufferTXN,
    Struct_StringInfoData,
    OUTPUT_PLUGIN_TEXTUAL_OUTPUT,
    REORDER_BUFFER_CHANGE_DELETE,
    REORDER_BUFFER_CHANGE_INSERT,
    REORDER_BUFFER_CHANGE_UPDATE,
};

extern {
  fn OutputPluginPrepareWrite(ctx: &LogicalDecodingContext, last_write: bool);
  fn OutputPluginWrite(ctx: &LogicalDecodingContext, last_write: bool);
  fn appendStringInfoString(str: *mut Struct_StringInfoData, s: *const i8);
}

#[no_mangle]
pub extern fn pg_decode_startup(ctx: &LogicalDecodingContext, opt: &mut OutputPluginOptions, is_init: bool) {
	opt.output_type = OUTPUT_PLUGIN_TEXTUAL_OUTPUT;
}

#[no_mangle]
pub extern fn pg_decode_change(ctx:      &LogicalDecodingContext,
                               txn:      &ReorderBufferTXN,
                               relation: Relation,
                               change:   &mut ReorderBufferChange) {

    let change = match change.action {
        REORDER_BUFFER_CHANGE_INSERT => {
            let tuple = pg_tuple_to_rspgod_tuple(
                unsafe { (*relation).rd_att },
                unsafe { (*change.data.tp()).newtuple }
            );

            match tuple {
                Some(t) => { Some(Change::Insert { new_row: t }) },
                None    => { None },
            }
        },
        REORDER_BUFFER_CHANGE_UPDATE => {
            let new_tuple = pg_tuple_to_rspgod_tuple(
                unsafe { (*relation).rd_att },
                unsafe { (*change.data.tp()).newtuple }
            );

            let old_tuple = pg_tuple_to_rspgod_tuple(
                unsafe { (*relation).rd_att },
                unsafe { (*change.data.tp()).newtuple }
            );

            match (new_tuple, old_tuple) {
                (Some(n), Some(o)) => {
                    Some(Change::Update { new_row: n, old_row: o })
                },
                _ => { None },
            }
        },
        REORDER_BUFFER_CHANGE_DELETE => {
            let tuple = pg_tuple_to_rspgod_tuple(
                unsafe { (*relation).rd_att },
                unsafe { (*change.data.tp()).oldtuple }
            );

            match tuple {
                Some(t) => { Some(Change::Delete { old_row: t }) },
                None    => { None },
            }
        },
        _ => { None },
    };

    match change {
        None    => {},
        Some(c) => {
            let output         = format!("{}", json::encode(&c).unwrap());
            let c_tuple_string = CString::new(&output[..]).unwrap();

            unsafe {
                OutputPluginPrepareWrite(ctx, true);
                appendStringInfoString(ctx.out, c_tuple_string.as_ptr());
                OutputPluginWrite(ctx, true);
            }
        }
    }

}

#[no_mangle]
pub extern fn pg_decode_commit_txn(ctx: &LogicalDecodingContext, txn: &ReorderBufferTXN, commit_lsn: u64) {
}

#[no_mangle]
pub extern fn pg_decode_begin_txn(ctx: &LogicalDecodingContext, txn: &ReorderBufferTXN) {
}

#[no_mangle]
pub extern fn pg_decode_shutdown(ctx: &LogicalDecodingContext) {
}
<commit_msg>Replaces a level of nesting with an<commit_after>#![allow(dead_code)]
#![allow(unused_variables)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]

extern crate libc;
extern crate rustc_serialize;

use rustc_serialize::json;
use std::ffi::CString;

pub mod postgres;
pub mod postgres_bindings;
pub mod types;

use types::{
    Change,
};

use postgres::{
    pg_tuple_to_rspgod_tuple,
};

use postgres_bindings::{
    LogicalDecodingContext,
    OutputPluginOptions,
    Relation,
    ReorderBufferChange,
    ReorderBufferTXN,
    Struct_StringInfoData,
    OUTPUT_PLUGIN_TEXTUAL_OUTPUT,
    REORDER_BUFFER_CHANGE_DELETE,
    REORDER_BUFFER_CHANGE_INSERT,
    REORDER_BUFFER_CHANGE_UPDATE,
};

extern {
  fn OutputPluginPrepareWrite(ctx: &LogicalDecodingContext, last_write: bool);
  fn OutputPluginWrite(ctx: &LogicalDecodingContext, last_write: bool);
  fn appendStringInfoString(str: *mut Struct_StringInfoData, s: *const i8);
}

#[no_mangle]
pub extern fn pg_decode_startup(ctx: &LogicalDecodingContext, opt: &mut OutputPluginOptions, is_init: bool) {
	opt.output_type = OUTPUT_PLUGIN_TEXTUAL_OUTPUT;
}

#[no_mangle]
pub extern fn pg_decode_change(ctx:      &LogicalDecodingContext,
                               txn:      &ReorderBufferTXN,
                               relation: Relation,
                               change:   &mut ReorderBufferChange) {

    let change = match change.action {
        REORDER_BUFFER_CHANGE_INSERT => {
            let tuple = pg_tuple_to_rspgod_tuple(
                unsafe { (*relation).rd_att },
                unsafe { (*change.data.tp()).newtuple }
            );

            match tuple {
                Some(t) => { Some(Change::Insert { new_row: t }) },
                None    => { None },
            }
        },
        REORDER_BUFFER_CHANGE_UPDATE => {
            let new_tuple = pg_tuple_to_rspgod_tuple(
                unsafe { (*relation).rd_att },
                unsafe { (*change.data.tp()).newtuple }
            );

            let old_tuple = pg_tuple_to_rspgod_tuple(
                unsafe { (*relation).rd_att },
                unsafe { (*change.data.tp()).newtuple }
            );

            match (new_tuple, old_tuple) {
                (Some(n), Some(o)) => {
                    Some(Change::Update { new_row: n, old_row: o })
                },
                _ => { None },
            }
        },
        REORDER_BUFFER_CHANGE_DELETE => {
            let tuple = pg_tuple_to_rspgod_tuple(
                unsafe { (*relation).rd_att },
                unsafe { (*change.data.tp()).oldtuple }
            );

            match tuple {
                Some(t) => { Some(Change::Delete { old_row: t }) },
                None    => { None },
            }
        },
        _ => { None },
    };

    if let Some(c) = change {
        let output         = format!("{}", json::encode(&c).unwrap());
        let c_tuple_string = CString::new(&output[..]).unwrap();

        unsafe {
            OutputPluginPrepareWrite(ctx, true);
            appendStringInfoString(ctx.out, c_tuple_string.as_ptr());
            OutputPluginWrite(ctx, true);
        }
    }
}

#[no_mangle]
pub extern fn pg_decode_commit_txn(ctx: &LogicalDecodingContext, txn: &ReorderBufferTXN, commit_lsn: u64) {
}

#[no_mangle]
pub extern fn pg_decode_begin_txn(ctx: &LogicalDecodingContext, txn: &ReorderBufferTXN) {
}

#[no_mangle]
pub extern fn pg_decode_shutdown(ctx: &LogicalDecodingContext) {
}
<|endoftext|>


<commit_before>#![crate_id = "graphics"]
#![deny(missing_doc)]

//! A library for 2D graphics that works with multiple back-ends.

pub use AddBevel
    = add_bevel::AddBevel;
pub use AddBevelBorder
    = add_bevel_border::AddBevelBorder;
pub use AddBorder
    = add_border::AddBorder;
pub use AddColor
    = add_color::AddColor;
pub use AddEllipse
    = add_ellipse::AddEllipse;
pub use AddImage
    = add_image::AddImage;
pub use AddLine
    = add_line::AddLine;
pub use AddPolygon
    = add_polygon::AddPolygon;
pub use AddPolygons
    = add_polygons::AddPolygons;
pub use AddRectangle
    = add_rectangle::AddRectangle;
pub use AddRound
    = add_round::AddRound;
pub use AddRoundBorder
    = add_round_border::AddRoundBorder;
pub use AddSquareBorder
    = add_square_border::AddSquareBorder;
pub use AddTween
    = add_tween::AddTween;
pub use BackEnd
    = back_end::BackEnd;
pub use BevelBorderLineColorContext
    = bevel_border_line_color_context::BevelBorderLineColorContext;
pub use BevelBorderLineContext
    = bevel_border_line_context::BevelBorderLineContext;
pub use BevelRectangleBorderColorContext
    = bevel_rectangle_border_color_context::BevelRectangleBorderColorContext;
pub use BevelRectangleBorderContext
    = bevel_rectangle_border_context::BevelRectangleBorderContext;
pub use BevelRectangleColorContext
    = bevel_rectangle_color_context::BevelRectangleColorContext;
pub use BevelRectangleContext
    = bevel_rectangle_context::BevelRectangleContext;
pub use ColorContext
    = color_context::ColorContext;
pub use Context
    = context::Context;
pub use Draw
    = draw::Draw;
pub use EllipseContext
    = ellipse_context::EllipseContext;
pub use EllipseBorderContext
    = ellipse_border_context::EllipseBorderContext;
pub use EllipseColorContext
    = ellipse_color_context::EllipseColorContext;
pub use EllipseBorderColorContext
    = ellipse_border_color_context::EllipseBorderColorContext;
pub use ImageSize
    = image_size::ImageSize;
pub use ImageContext
    = image_context::ImageContext;
pub use ImageColorContext
    = image_color_context::ImageColorContext;
pub use ImageRectangleContext
    = image_rectangle_context::ImageRectangleContext;
pub use ImageRectangleColorContext
    = image_rectangle_color_context::ImageRectangleColorContext;
pub use LerpTweenContext
    = lerp_tween_context::LerpTweenContext;
pub use LerpTweenColorContext
    = lerp_tween_color_context::LerpTweenColorContext;
pub use LerpTweenPolygonsContext
    = lerp_tween_polygons_context::LerpTweenPolygonsContext;
pub use LerpTweenPolygonsColorContext
    = lerp_tween_polygons_color_context::LerpTweenPolygonsColorContext;
pub use LineContext
    = line_context::LineContext;
pub use LineColorContext
    = line_color_context::LineColorContext;
pub use PolygonContext
    = polygon_context::PolygonContext;
pub use PolygonColorContext
    = polygon_color_context::PolygonColorContext;
pub use RectangleBorderContext
    = rectangle_border_context::RectangleBorderContext;
pub use RectangleBorderColorContext
    = rectangle_border_color_context::RectangleBorderColorContext;
pub use RectangleContext
    = rectangle_context::RectangleContext;
pub use RectangleColorContext
    = rectangle_color_context::RectangleColorContext;
pub use RelativeColor
    = relative_color::RelativeColor;
pub use RelativeRectangle
    = relative_rectangle::RelativeRectangle;
pub use RelativeSourceRectangle
    = relative_source_rectangle::RelativeSourceRectangle;
pub use RelativeTransform2d
    = relative_transform2d::RelativeTransform2d;
pub use RoundBorderLineContext
    = round_border_line_context::RoundBorderLineContext;
pub use RoundBorderLineColorContext
    = round_border_line_color_context::RoundBorderLineColorContext;
pub use RoundRectangleBorderColorContext
    = round_rectangle_border_color_context::RoundRectangleBorderColorContext;
pub use RoundRectangleBorderContext
    = round_rectangle_border_context::RoundRectangleBorderContext;
pub use RoundRectangleColorContext
    = round_rectangle_color_context::RoundRectangleColorContext;
pub use RoundRectangleContext
    = round_rectangle_context::RoundRectangleContext;
pub use SquareBorderLineColorContext
    = square_border_line_color_context::SquareBorderLineColorContext;
pub use SquareBorderLineContext
    = square_border_line_context::SquareBorderLineContext;
pub use View
    = view::View;

mod add_bevel;
mod add_bevel_border;
mod add_border;
mod add_color;
mod add_ellipse;
mod add_image;
mod add_line;
mod add_polygon;
mod add_polygons;
mod add_rectangle;
mod add_round;
mod add_round_border;
mod add_square_border;
mod add_tween;
mod back_end;
mod bevel_border_line_color_context;
mod bevel_border_line_context;
mod bevel_rectangle_border_color_context;
mod bevel_rectangle_border_context;
mod bevel_rectangle_color_context;
mod bevel_rectangle_context;
mod color_context;
mod context;
mod draw;
mod ellipse_border_context;
mod ellipse_border_color_context;
mod ellipse_color_context;
mod ellipse_context;
mod image_size;
mod image_context;
mod image_color_context;
mod image_rectangle_color_context;
mod image_rectangle_context;
mod line_color_context;
mod line_context;
mod polygon_color_context;
mod polygon_context;
mod rectangle_border_context;
mod rectangle_border_color_context;
mod rectangle_color_context;
mod rectangle_context;
mod relative_color;
mod relative_rectangle;
mod relative_source_rectangle;
mod relative_transform2d;
mod round_border_line_color_context;
mod round_border_line_context;
mod round_rectangle_border_color_context;
mod round_rectangle_border_context;
mod round_rectangle_color_context;
mod round_rectangle_context;
mod square_border_line_color_context;
mod square_border_line_context;
mod lerp_tween_color_context;
mod lerp_tween_context;
mod lerp_tween_polygons_color_context;
mod lerp_tween_polygons_context;
mod view;

pub mod internal;
pub mod interpolation;
pub mod modular_index;
pub mod triangulation;
pub mod vecmath;

/// A structure that might contain a value or a borrowed value.
/// This is to used as building block to create data structure
/// that is partially based on an existing structure.
pub enum Field<T> {
    /// Contains a value.
    Value(T),
}

impl<T: Copy> Field<T> {
    /// Gets a read only value.
    #[inline(always)]
    pub fn get(&self) -> T {
        match *self {
            Value(val) => val,
        }
    }
}

/* Uncomment when lifetime traits problem is solved.
pub enum Field<'a, T> {
    /// Contains a value.
    Value(T),
    /// Contains a borrowed pointer.
    Borrowed(&'a T),
}

impl<'a, T> Field<'a, T> {
    /// Gets a read only value.
    #[inline(always)]
    pub fn get(&'a self) -> &'a T {
        match *self {
            Value(val) => val,
        }
    }
}
*/

<commit_msg>Fixed use statements<commit_after>#![crate_id = "graphics"]
#![deny(missing_doc)]

//! A library for 2D graphics that works with multiple back-ends.

pub use add_bevel::AddBevel;
pub use add_bevel_border::AddBevelBorder;
pub use add_border::AddBorder;
pub use add_color::AddColor;
pub use add_ellipse::AddEllipse;
pub use add_image::AddImage;
pub use add_line::AddLine;
pub use add_polygon::AddPolygon;
pub use add_polygons::AddPolygons;
pub use add_rectangle::AddRectangle;
pub use add_round::AddRound;
pub use add_round_border::AddRoundBorder;
pub use add_square_border::AddSquareBorder;
pub use add_tween::AddTween;
pub use back_end::BackEnd;
pub use bevel_border_line_color_context::BevelBorderLineColorContext;
pub use bevel_border_line_context::BevelBorderLineContext;
pub use bevel_rectangle_border_color_context::BevelRectangleBorderColorContext;
pub use bevel_rectangle_border_context::BevelRectangleBorderContext;
pub use bevel_rectangle_color_context::BevelRectangleColorContext;
pub use bevel_rectangle_context::BevelRectangleContext;
pub use color_context::ColorContext;
pub use context::Context;
pub use draw::Draw;
pub use ellipse_context::EllipseContext;
pub use ellipse_border_context::EllipseBorderContext;
pub use ellipse_color_context::EllipseColorContext;
pub use ellipse_border_color_context::EllipseBorderColorContext;
pub use image_size::ImageSize;
pub use image_context::ImageContext;
pub use image_color_context::ImageColorContext;
pub use image_rectangle_context::ImageRectangleContext;
pub use image_rectangle_color_context::ImageRectangleColorContext;
pub use lerp_tween_context::LerpTweenContext;
pub use lerp_tween_color_context::LerpTweenColorContext;
pub use lerp_tween_polygons_context::LerpTweenPolygonsContext;
pub use lerp_tween_polygons_color_context::LerpTweenPolygonsColorContext;
pub use line_context::LineContext;
pub use line_color_context::LineColorContext;
pub use polygon_context::PolygonContext;
pub use polygon_color_context::PolygonColorContext;
pub use rectangle_border_context::RectangleBorderContext;
pub use rectangle_border_color_context::RectangleBorderColorContext;
pub use rectangle_context::RectangleContext;
pub use rectangle_color_context::RectangleColorContext;
pub use relative_color::RelativeColor;
pub use relative_rectangle::RelativeRectangle;
pub use relative_source_rectangle::RelativeSourceRectangle;
pub use relative_transform2d::RelativeTransform2d;
pub use round_border_line_context::RoundBorderLineContext;
pub use round_border_line_color_context::RoundBorderLineColorContext;
pub use round_rectangle_border_color_context::RoundRectangleBorderColorContext;
pub use round_rectangle_border_context::RoundRectangleBorderContext;
pub use round_rectangle_color_context::RoundRectangleColorContext;
pub use round_rectangle_context::RoundRectangleContext;
pub use square_border_line_color_context::SquareBorderLineColorContext;
pub use square_border_line_context::SquareBorderLineContext;
pub use view::View;

mod add_bevel;
mod add_bevel_border;
mod add_border;
mod add_color;
mod add_ellipse;
mod add_image;
mod add_line;
mod add_polygon;
mod add_polygons;
mod add_rectangle;
mod add_round;
mod add_round_border;
mod add_square_border;
mod add_tween;
mod back_end;
mod bevel_border_line_color_context;
mod bevel_border_line_context;
mod bevel_rectangle_border_color_context;
mod bevel_rectangle_border_context;
mod bevel_rectangle_color_context;
mod bevel_rectangle_context;
mod color_context;
mod context;
mod draw;
mod ellipse_border_context;
mod ellipse_border_color_context;
mod ellipse_color_context;
mod ellipse_context;
mod image_size;
mod image_context;
mod image_color_context;
mod image_rectangle_color_context;
mod image_rectangle_context;
mod line_color_context;
mod line_context;
mod polygon_color_context;
mod polygon_context;
mod rectangle_border_context;
mod rectangle_border_color_context;
mod rectangle_color_context;
mod rectangle_context;
mod relative_color;
mod relative_rectangle;
mod relative_source_rectangle;
mod relative_transform2d;
mod round_border_line_color_context;
mod round_border_line_context;
mod round_rectangle_border_color_context;
mod round_rectangle_border_context;
mod round_rectangle_color_context;
mod round_rectangle_context;
mod square_border_line_color_context;
mod square_border_line_context;
mod lerp_tween_color_context;
mod lerp_tween_context;
mod lerp_tween_polygons_color_context;
mod lerp_tween_polygons_context;
mod view;

pub mod internal;
pub mod interpolation;
pub mod modular_index;
pub mod triangulation;
pub mod vecmath;

/// A structure that might contain a value or a borrowed value.
/// This is to used as building block to create data structure
/// that is partially based on an existing structure.
pub enum Field<T> {
    /// Contains a value.
    Value(T),
}

impl<T: Copy> Field<T> {
    /// Gets a read only value.
    #[inline(always)]
    pub fn get(&self) -> T {
        match *self {
            Value(val) => val,
        }
    }
}

/* Uncomment when lifetime traits problem is solved.
pub enum Field<'a, T> {
    /// Contains a value.
    Value(T),
    /// Contains a borrowed pointer.
    Borrowed(&'a T),
}

impl<'a, T> Field<'a, T> {
    /// Gets a read only value.
    #[inline(always)]
    pub fn get(&'a self) -> &'a T {
        match *self {
            Value(val) => val,
        }
    }
}
*/

<|endoftext|>


<commit_before>use super::*;
use error::*;
use ffi::*;

#[derive(Debug, Clone)]
struct Alignment {
    in_: i32,
    out: i32,
}

impl Alignment {
    fn new<A: FFTW, B: FFTW>(in_: &[A], out: &[B]) -> Self {
        Self {
            in_: A::alignment_of(in_),
            out: B::alignment_of(out),
        }
    }
    fn check<A: FFTW, B: FFTW>(&self, in_: &[A], out: &[B]) -> Result<()> {
        if self.in_ != A::alignment_of(in_) || self.out != B::alignment_of(out) {
            Err(AlignmentMismatchError::new().into())
        } else {
            Ok(())
        }
    }
}

#[derive(Debug, Clone)]
struct Shape(Vec<i32>);

impl Shape {
    fn new(s: &[i32]) -> Self {
        Shape(s.to_vec())
    }
    fn check<A: FFTW, B: FFTW>(&self, in_: &[A], out: &[B]) -> Result<()>{
        let n = self.0.len();
        if in_.len() != n || out.len() != n {
            Err(SizeMismatchError::new().into())
        } else {
            Ok(())
        }
    }
}

#[derive(Debug)]
pub struct C2CPlan<C: FFTW> {
    plan: C::Plan,
    shape: Shape,
    sign: Sign,
    flag: FLAG,
    alignment: Alignment,
}

impl<C: FFTW<Complex = C>> C2CPlan<C> {
    pub fn new(shape: &[i32], in_: &[C], out: &[C], sign: Sign, flag: FLAG) -> Self {
        Self {
            plan: C::plan_c2c(&shape, in_, out, sign, flag),
            shape: Shape::new(shape),
            sign,
            flag,
            alignment: Alignment::new(in_, out),
        }
    }
    pub fn c2c(&mut self, in_: &[C], out: &mut [C]) -> Result<()> {
        self.alignment.check(in_, out)?;
        self.shape.check(in_, out)?;
        C::exec_c2c(self.plan, in_, out);
        Ok(())
    }
}

#[derive(Debug)]
pub struct C2RPlan<C, R>
where
    C: FFTW<Real = R, Complex = C>,
    R: FFTW<Real = R, Complex = C, Plan = C::Plan>,
{
    plan: C::Plan,
    shape: Shape,
    flag: FLAG,
    alignment: Alignment,
}

impl<C, R> C2RPlan<C, R>
where
    C: FFTW<Real = R, Complex = C>,
    R: FFTW<Real = R, Complex = C, Plan = C::Plan>,
{
    pub fn new(shape: &[i32], in_: &[C], out: &[R], flag: FLAG) -> Self {
        Self {
            plan: C::plan_c2r(&shape, in_, out, flag),
            shape: Shape::new(shape),
            flag,
            alignment: Alignment::new(in_, out),
        }
    }
    pub fn c2r(&mut self, in_: &[C], out: &mut [R]) -> Result<()> {
        self.alignment.check(in_, out)?;
        self.shape.check(in_, out)?;
        C::exec_c2r(self.plan, in_, out);
        Ok(())
    }
}

#[derive(Debug)]
pub struct R2CPlan<R, C>
where
    C: FFTW<Real = R, Complex = C>,
    R: FFTW<Real = R, Complex = C, Plan = C::Plan>,
{
    plan: C::Plan,
    shape: Shape,
    flag: FLAG,
    alignment: Alignment,
}

impl<R, C> R2CPlan<R, C>
where
    C: FFTW<Real = R, Complex = C>,
    R: FFTW<Real = R, Complex = C, Plan = C::Plan>,
{
    pub fn new(shape: &[i32], in_: &[R], out: &[C], flag: FLAG) -> Self {
        Self {
            plan: C::plan_r2c(&shape, in_, out, flag),
            shape: Shape::new(shape),
            flag,
            alignment: Alignment::new(in_, out),
        }
    }
    pub fn r2c(&mut self, in_: &[R], out: &mut [C]) -> Result<()> {
        self.alignment.check(in_, out)?;
        self.shape.check(in_, out)?;
        C::exec_r2c(self.plan, in_, out);
        Ok(())
    }
}

/// Switch `fftw_*` and `fftwf_*`
pub trait FFTW {
    type Plan: Copy;
    type Real;
    type Complex;
    fn destroy_plan(Self::Plan);
    fn print_plan(Self::Plan);
    fn plan_c2c(shape: &[i32], in_: &[Self::Complex], out: &[Self::Complex], sign: Sign, flags: FLAG) -> Self::Plan;
    fn plan_c2r(shape: &[i32], in_: &[Self::Complex], out: &[Self::Real], flags: FLAG) -> Self::Plan;
    fn plan_r2c(shape: &[i32], in_: &[Self::Real], out: &[Self::Complex], flags: FLAG) -> Self::Plan;
    fn exec_c2c(p: Self::Plan, in_: &[Self::Complex], &mut [Self::Complex]);
    fn exec_c2r(p: Self::Plan, in_: &[Self::Complex], &mut [Self::Real]);
    fn exec_r2c(p: Self::Plan, in_: &[Self::Real], &mut [Self::Complex]);
    fn alignment_of<T>(&[T]) -> i32;
}

macro_rules! excall {
    ($call:expr) => {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        unsafe { $call }
    }
}

impl FFTW for c64 {
    type Plan = fftw_plan;
    type Real = f64;
    type Complex = c64;
    fn destroy_plan(p: Self::Plan) {
        excall!{ fftw_destroy_plan(p) };
    }
    fn print_plan(p: Self::Plan) {
        excall!{ fftw_print_plan(p) };
    }
    fn plan_c2c(shape: &[i32], in_: &[Self::Complex], out: &[Self::Complex], sign: Sign, flag: FLAG) -> Self::Plan {
        excall!{ fftw_plan_dft(shape.len() as i32, shape.as_ptr(), in_.as_ptr() as *mut _, out.as_ptr() as *mut _, sign, flag) }
    }
    fn plan_c2r(shape: &[i32], in_: &[Self::Complex], out: &[Self::Real], flag: FLAG) -> Self::Plan {
        excall!{ fftw_plan_dft_c2r(shape.len() as i32, shape.as_ptr(), in_.as_ptr() as *mut _, out.as_ptr() as *mut _, flag) }
    }
    fn plan_r2c(shape: &[i32], in_: &[Self::Real], out: &[Self::Complex], flag: FLAG) -> Self::Plan {
        excall!{ fftw_plan_dft_r2c(shape.len() as i32, shape.as_ptr(), in_.as_ptr() as *mut _, out.as_ptr() as *mut _, flag) }
    }
    fn exec_c2c(p: Self::Plan, in_: &[Self::Complex], out: &mut [Self::Complex]) {
        unsafe { fftw_execute_dft(p, in_.as_ptr() as *mut _, out.as_mut_ptr()) };
    }
    fn exec_c2r(p: Self::Plan, in_: &[Self::Complex], out: &mut [Self::Real]) {
        unsafe { fftw_execute_dft_c2r(p, in_.as_ptr() as *mut _, out.as_mut_ptr()) };
    }
    fn exec_r2c(p: Self::Plan, in_: &[Self::Real], out: &mut [Self::Complex]) {
        unsafe { fftw_execute_dft_r2c(p, in_.as_ptr() as *mut _, out.as_mut_ptr()) };
    }
    fn alignment_of<T>(s: &[T]) -> i32 {
        unsafe { fftw_alignment_of(s.as_ptr() as *mut _) }
    }
}
<commit_msg>Add check if plan is NULL<commit_after>use super::*;
use error::*;
use ffi::*;

#[derive(Debug, Clone)]
struct Alignment {
    in_: i32,
    out: i32,
}

impl Alignment {
    fn new<A: FFTW, B: FFTW>(in_: &[A], out: &[B]) -> Self {
        Self {
            in_: A::alignment_of(in_),
            out: B::alignment_of(out),
        }
    }
    fn check<A: FFTW, B: FFTW>(&self, in_: &[A], out: &[B]) -> Result<()> {
        if self.in_ != A::alignment_of(in_) || self.out != B::alignment_of(out) {
            Err(AlignmentMismatchError::new().into())
        } else {
            Ok(())
        }
    }
}

#[derive(Debug, Clone)]
struct Shape(Vec<i32>);

impl Shape {
    fn new(s: &[i32]) -> Self {
        Shape(s.to_vec())
    }
    fn check<A: FFTW, B: FFTW>(&self, in_: &[A], out: &[B]) -> Result<()> {
        let n = self.0.len();
        if in_.len() != n || out.len() != n {
            Err(SizeMismatchError::new().into())
        } else {
            Ok(())
        }
    }
}

#[derive(Debug)]
pub struct C2CPlan<C: FFTW> {
    plan: C::Plan,
    shape: Shape,
    sign: Sign,
    flag: FLAG,
    alignment: Alignment,
}

impl<C: FFTW<Complex = C>> C2CPlan<C> {
    pub fn new(shape: &[i32], in_: &[C], out: &[C], sign: Sign, flag: FLAG) -> Result<Self> {
        Ok(Self {
            plan: C::plan_c2c(&shape, in_, out, sign, flag)?,
            shape: Shape::new(shape),
            sign,
            flag,
            alignment: Alignment::new(in_, out),
        })
    }
    pub fn c2c(&mut self, in_: &[C], out: &mut [C]) -> Result<()> {
        self.alignment.check(in_, out)?;
        self.shape.check(in_, out)?;
        C::exec_c2c(self.plan, in_, out);
        Ok(())
    }
}

#[derive(Debug)]
pub struct C2RPlan<C, R>
where
    C: FFTW<Real = R, Complex = C>,
    R: FFTW<Real = R, Complex = C, Plan = C::Plan>,
{
    plan: C::Plan,
    shape: Shape,
    flag: FLAG,
    alignment: Alignment,
}

impl<C, R> C2RPlan<C, R>
where
    C: FFTW<Real = R, Complex = C>,
    R: FFTW<Real = R, Complex = C, Plan = C::Plan>,
{
    pub fn new(shape: &[i32], in_: &[C], out: &[R], flag: FLAG) -> Result<Self> {
        Ok(Self {
            plan: C::plan_c2r(&shape, in_, out, flag)?,
            shape: Shape::new(shape),
            flag,
            alignment: Alignment::new(in_, out),
        })
    }
    pub fn c2r(&mut self, in_: &[C], out: &mut [R]) -> Result<()> {
        self.alignment.check(in_, out)?;
        self.shape.check(in_, out)?;
        C::exec_c2r(self.plan, in_, out);
        Ok(())
    }
}

#[derive(Debug)]
pub struct R2CPlan<R, C>
where
    C: FFTW<Real = R, Complex = C>,
    R: FFTW<Real = R, Complex = C, Plan = C::Plan>,
{
    plan: C::Plan,
    shape: Shape,
    flag: FLAG,
    alignment: Alignment,
}

impl<R, C> R2CPlan<R, C>
where
    C: FFTW<Real = R, Complex = C>,
    R: FFTW<Real = R, Complex = C, Plan = C::Plan>,
{
    pub fn new(shape: &[i32], in_: &[R], out: &[C], flag: FLAG) -> Result<Self> {
        Ok(Self {
            plan: C::plan_r2c(&shape, in_, out, flag)?,
            shape: Shape::new(shape),
            flag,
            alignment: Alignment::new(in_, out),
        })
    }
    pub fn r2c(&mut self, in_: &[R], out: &mut [C]) -> Result<()> {
        self.alignment.check(in_, out)?;
        self.shape.check(in_, out)?;
        C::exec_r2c(self.plan, in_, out);
        Ok(())
    }
}

pub trait Plan: Sized {
    fn check_null(self) -> Result<Self>;
}

impl Plan for fftw_plan {
    fn check_null(self) -> Result<Self> {
        if self.is_null() {
            Err(InvalidPlanError::new().into())
        } else {
            Ok(self)
        }
    }
}

impl Plan for fftwf_plan {
    fn check_null(self) -> Result<Self> {
        if self.is_null() {
            Err(InvalidPlanError::new().into())
        } else {
            Ok(self)
        }
    }
}

/// Switch `fftw_*` and `fftwf_*`
pub trait FFTW {
    type Plan: Plan + Copy;
    type Real;
    type Complex;
    fn destroy_plan(Self::Plan);
    fn print_plan(Self::Plan);
    fn plan_c2c(
        shape: &[i32],
        in_: &[Self::Complex],
        out: &[Self::Complex],
        sign: Sign,
        flags: FLAG,
    ) -> Result<Self::Plan>;
    fn plan_c2r(shape: &[i32], in_: &[Self::Complex], out: &[Self::Real], flags: FLAG) -> Result<Self::Plan>;
    fn plan_r2c(shape: &[i32], in_: &[Self::Real], out: &[Self::Complex], flags: FLAG) -> Result<Self::Plan>;
    fn exec_c2c(p: Self::Plan, in_: &[Self::Complex], &mut [Self::Complex]);
    fn exec_c2r(p: Self::Plan, in_: &[Self::Complex], &mut [Self::Real]);
    fn exec_r2c(p: Self::Plan, in_: &[Self::Real], &mut [Self::Complex]);
    fn alignment_of<T>(&[T]) -> i32;
}

macro_rules! excall {
    ($call:expr) => {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        unsafe { $call }
    }
}

impl FFTW for c64 {
    type Plan = fftw_plan;
    type Real = f64;
    type Complex = c64;
    fn destroy_plan(p: Self::Plan) {
        excall!{ fftw_destroy_plan(p) };
    }
    fn print_plan(p: Self::Plan) {
        excall!{ fftw_print_plan(p) };
    }
    fn plan_c2c(
        shape: &[i32],
        in_: &[Self::Complex],
        out: &[Self::Complex],
        sign: Sign,
        flag: FLAG,
    ) -> Result<Self::Plan> {
        excall!{ fftw_plan_dft(shape.len() as i32, shape.as_ptr(), in_.as_ptr() as *mut _, out.as_ptr() as *mut _, sign, flag).check_null() }
    }
    fn plan_c2r(shape: &[i32], in_: &[Self::Complex], out: &[Self::Real], flag: FLAG) -> Result<Self::Plan> {
        excall!{ fftw_plan_dft_c2r(shape.len() as i32, shape.as_ptr(), in_.as_ptr() as *mut _, out.as_ptr() as *mut _, flag).check_null() }
    }
    fn plan_r2c(shape: &[i32], in_: &[Self::Real], out: &[Self::Complex], flag: FLAG) -> Result<Self::Plan> {
        excall!{ fftw_plan_dft_r2c(shape.len() as i32, shape.as_ptr(), in_.as_ptr() as *mut _, out.as_ptr() as *mut _, flag).check_null() }
    }
    fn exec_c2c(p: Self::Plan, in_: &[Self::Complex], out: &mut [Self::Complex]) {
        unsafe { fftw_execute_dft(p, in_.as_ptr() as *mut _, out.as_mut_ptr()) };
    }
    fn exec_c2r(p: Self::Plan, in_: &[Self::Complex], out: &mut [Self::Real]) {
        unsafe { fftw_execute_dft_c2r(p, in_.as_ptr() as *mut _, out.as_mut_ptr()) };
    }
    fn exec_r2c(p: Self::Plan, in_: &[Self::Real], out: &mut [Self::Complex]) {
        unsafe { fftw_execute_dft_r2c(p, in_.as_ptr() as *mut _, out.as_mut_ptr()) };
    }
    fn alignment_of<T>(s: &[T]) -> i32 {
        unsafe { fftw_alignment_of(s.as_ptr() as *mut _) }
    }
}
<|endoftext|>


<commit_before>#![desc = "Omnomnom incremental byte parser"]
#![license = "MIT"]
#![macro_escape]

extern crate collections;

use std::fmt::Show;
use internal::*;
use internal::IResult::*;

#[macro_export]
macro_rules! tag(
  ($name:ident $inp:expr) => (
    fn $name(i:&[u8]) -> IResult<&[u8], &[u8]>{
      if i.len() >= $inp.len() && i.slice(0, $inp.len()) == $inp {
        Done(i.slice_from($inp.len()), i.slice(0, 0))
      } else {
        Error(0)
      }
    }
  )
)

macro_rules! o (
  ($name:ident<$i:ty,$o:ty> $f1:expr $($rest:tt)*) => (
    fn $name(input:$i) -> IResult<$i, $o>{
      match $f1(input) {
        Error(e)  => Error(e),
        Incomplete(i) => Incomplete(i),
        Done(i,o) => {
          o_parser!(i o $($rest)*)
        }
      }
    }
  );
)

macro_rules! o_parser (
  ($i:expr $o:expr) => (Done($i,$o));

  ($i:expr $o:expr ~ $e:expr ~ $($rest:tt)*) => (
    match $e($i) {
      Error(e)  => Error(e),
      Incomplete(i) => Incomplete(i),
      Done(i,o) => {
        o_parser!(i o $($rest)*)
      }
    }

   );
  ($i:expr $o:expr $e:expr $($rest:tt)*) => (
    match $e($i) {
      Error(e)  => Error(e),
      Incomplete(i) => Incomplete(i),
      Done(i,_) => {
        o_parser!(i $o $($rest)*)
      }
    }
   );
)

macro_rules! chain (
  ($name:ident<$i:ty,$o:ty>, $assemble:expr, $($rest:tt)*) => (
    fn $name(i:$i) -> IResult<$i,$o>{
      chaining_parser!(i, $assemble, $($rest)*)
    }
  );
)

macro_rules! chaining_parser (
  ($i:expr, $assemble:expr, $field:ident : $e:expr, $($rest:tt)*) => (
    match $e($i) {
      Error(e)  => Error(e),
      Incomplete(i) => Incomplete(i),
      Done(i,o) => {
        let $field = o;
        chaining_parser!(i, $assemble, $($rest)*)
      }
    }
  );

  ($i:expr, $assemble:expr, ) => (
    Done($i, $assemble())
  )
)

macro_rules! alt (
  ($name:ident<$i:ty,$o:ty>, $($rest:tt)*) => (
    fn $name(i:$i) -> IResult<$i,$o>{
      alt_parser!(i, $($rest)*)
    }
  );
)

macro_rules! alt_parser (
  ($i:expr, $e:expr $($rest:tt)*) => (
    match $e($i) {
      Error(_)  => alt_parser!($i, $($rest)*),
      Incomplete(_) => alt_parser!($i, $($rest)*),
      Done(i,o) => Done(i,o)
    }
  );

  ($i:expr, ) => (
    Error(1)
  )
)

pub fn print<'a,T: Show>(input: T) -> IResult<T, ()> {
  println!("{}", input);
  Done(input, ())
}

pub fn begin<'a>(input: &'a [u8]) -> IResult<(), &'a [u8]> {
  Done((), input)
}

#[macro_export]
macro_rules! is_not(
  ($name:ident $arr:expr) => (
    fn $name(input:&[u8]) -> IResult<&[u8], &[u8]> {
      for idx in range(0, input.len()) {
        for &i in $arr.iter() {
          if input[idx] == i {
            return Done(input.slice_from(idx), input.slice(0, idx))
          }
        }
      }
      Done("".as_bytes(), input)
    }
  )
)

#[macro_export]
macro_rules! is_a(
  ($name:ident $arr:expr) => (
    fn $name(input:&[u8]) -> IResult<&[u8], &[u8]> {
      for idx in range(0, input.len()) {
        var res = false
        for &i in $arr.iter() {
          if input[idx] == i {
            res = true
          }
        }
        if !res {
          return Done(input.slice_from(idx), input.slice(0, idx))
        }
      }
      Done("".as_bytes(), input)
    }
  )
)

#[macro_export]
macro_rules! filter(
  ($name:ident $f:ident) => (
    fn $name(input:&[u8]) -> IResult<&[u8], &[u8]> {
      for idx in range(0, input.len()) {
        if !$f(input[idx]) {
          return Done(input.slice_from(idx), input.slice(0, idx))
        }
      }
      Done("".as_bytes(), input)
    }
  )
)

// FIXME: when rust-lang/rust#17436 is fixed, macros will be able to export
// public methods
//pub is_not!(line_ending "\r\n".as_bytes())
pub fn line_ending(input:&[u8]) -> IResult<&[u8], &[u8]> {
  for idx in range(0, input.len()) {
    for &i in "\r\n".as_bytes().iter() {
      if input[idx] == i {
        return Done(input.slice_from(idx), input.slice(0, idx))
      }
    }
  }
  Done("".as_bytes(), input)
}

pub fn is_alphabetic(chr:u8) -> bool {
  (chr >= 0x41 && chr <= 0x5A) || (chr >= 0x61 && chr <= 0x7A)
}

pub fn is_digit(chr: u8) -> bool {
  chr >= 0x30 && chr <= 0x39
}

pub fn is_alphanumeric(chr: u8) -> bool {
  is_alphabetic(chr) || is_digit(chr)
}

// FIXME: when rust-lang/rust#17436 is fixed, macros will be able to export
//pub filter!(alpha is_alphabetic)
//pub filter!(digit is_digit)
//pub filter!(alphanumeric is_alphanumeric)
pub fn alpha(input:&[u8]) -> IResult<&[u8], &[u8]> {
  for idx in range(0, input.len()) {
    if !is_alphabetic(input[idx]) {
      return Done(input.slice_from(idx), input.slice(0, idx))
    }
  }
  Done("".as_bytes(), input)
}

pub fn digit(input:&[u8]) -> IResult<&[u8], &[u8]> {
  for idx in range(0, input.len()) {
    if !is_digit(input[idx]) {
      return Done(input.slice_from(idx), input.slice(0, idx))
    }
  }
  Done("".as_bytes(), input)
}

pub fn alphanumeric(input:&[u8]) -> IResult<&[u8], &[u8]> {
  for idx in range(0, input.len()) {
    if !is_alphanumeric(input[idx]) {
      return Done(input.slice_from(idx), input.slice(0, idx))
    }
  }
  Done("".as_bytes(), input)
}

pub fn sized_buffer(input:&[u8]) -> IResult<&[u8], &[u8]> {
  if input.len() == 0 {
    //FIXME: should return Incomplete
    return Error(0)
  }

  let len = input[0] as uint;

  if input.len() >= len + 1 {
    return Done(input.slice_from(len+1), input.slice(1, len+1))
  } else {
    //FIXME: should return Incomplete
    return Error(0)
  }
}

#[test]
fn character_test() {
  let empty = "".as_bytes();
  let a = "abcd".as_bytes();
  let b = "1234".as_bytes();
  let c = "a123".as_bytes();
  let d = "azé12".as_bytes();
  assert_eq!(Done((),a).flat_map(alpha), Done(empty, a))
  assert_eq!(Done((),b).flat_map(alpha), Done(b, empty))
  assert_eq!(Done((),c).flat_map(alpha), Done(c.slice_from(1), "a".as_bytes()))
  assert_eq!(Done((),d).flat_map(alpha), Done("é12".as_bytes(), "az".as_bytes()))
  assert_eq!(Done((),a).flat_map(digit), Done(a, empty))
  assert_eq!(Done((),b).flat_map(digit), Done(empty, b))
  assert_eq!(Done((),c).flat_map(digit), Done(c, empty))
  assert_eq!(Done((),d).flat_map(digit), Done(d, empty))
  assert_eq!(Done((),a).flat_map(alphanumeric), Done(empty, a))
  assert_eq!(Done((),b).flat_map(alphanumeric), Done(empty, b))
  assert_eq!(Done((),c).flat_map(alphanumeric), Done(empty, c))
  assert_eq!(Done((),d).flat_map(alphanumeric), Done("é12".as_bytes(), "az".as_bytes()))
}

#[test]
fn is_not_test() {
  let a = "ab12cd\nefgh".as_bytes();
  assert_eq!(Done((), a).flat_map(line_ending), Done("\nefgh".as_bytes(), "ab12cd".as_bytes()))
}

#[test]
fn sized_buffer_test() {
  let arr:[u8, ..6] = [3, 4, 5, 6, 7, 8];
  let res = Done((), arr.as_slice()).flat_map(sized_buffer);
  let i = [7,8];
  let o = [4,5,6];
  assert_eq!(res, Done(i.as_slice(), o.as_slice()))
}

#[test]
fn t1() {
  let v1:Vec<u8> = vec![1,2,3];
  let v2:Vec<u8> = vec![4,5,6];
  let d = Done(v1.as_slice(), v2.as_slice());
  let res = d.flat_map(print);
  assert_eq!(res, Done(v2.as_slice(), ()));
}

#[deriving(PartialEq,Eq,Show)]
struct B {
  a: int,
  b: int
}

#[test]
fn chain_and_ignore_test() {
  tag!(x "abcd".as_bytes());
  tag!(y "efgh".as_bytes());
  fn ret_int(i:&[u8]) -> IResult<&[u8], int> { Done(i,1) };
  //o!(z<&[u8], int>  x S x S retInt Z y);
  o!(z<&[u8], int>  x  x ~ret_int~ y);

  let r = Done((), "abcdabcdefgh".as_bytes()).flat_map(z);
  assert_eq!(r, Done("".as_bytes(), 1));
}

#[test]
fn chain_test() {
  tag!(x "abcd".as_bytes());
  fn temp_ret_int1(i:&[u8]) -> IResult<&[u8], int> { Done(i,1) };
  o!(ret_int1<&[u8],int> x ~ temp_ret_int1 ~);
  fn ret_int2(i:&[u8]) -> IResult<&[u8], int> { Done(i,2) };
  chain!(f<&[u8],B>, ||{B{a: aa, b: bb}}, aa: ret_int1, bb: ret_int2,);

  let r = Done((), "abcde".as_bytes()).flat_map(f);
  assert_eq!(r, Done("e".as_bytes(), B{a: 1, b: 2}));
}

#[test]
fn alt_test() {
  fn work(input: &[u8]) -> IResult<&[u8],&[u8]> {
    Done("".as_bytes(), input)
  }
  fn dont_work(input: &[u8]) -> IResult<&[u8],&[u8]> {
    Error(3)
  }
  fn work2(input: &[u8]) -> IResult<&[u8],&[u8]> {
    Done(input, "".as_bytes())
  }

  alt!(alt1<&[u8],&[u8]>, dont_work dont_work)
  alt!(alt2<&[u8],&[u8]>, dont_work work)
  alt!(alt3<&[u8],&[u8]>, dont_work dont_work work2 dont_work)

  let a = "abcd".as_bytes();
  assert_eq!(Done((), a).flat_map(alt1), Error(1))
  assert_eq!(Done((), a).flat_map(alt2), Done("".as_bytes(), a))
  assert_eq!(Done((), a).flat_map(alt3), Done(a, "".as_bytes()))
}

/* FIXME: this makes rustc weep
fn pr(par: IResult<(),&[u8]>) -> IResult<&[u8], ()> {
  Error(0)
}

#[test]
fn rustc_panic_test() {
  FileProducer::new("links.txt", 20).map(|producer: FileProducer| {
    let mut p = producer;
    p.push(pr);
  });
}*/

<commit_msg>move tests from src/nom.rs in a submodule<commit_after>#![desc = "Omnomnom incremental byte parser"]
#![license = "MIT"]
#![macro_escape]

extern crate collections;

use std::fmt::Show;
use internal::*;
use internal::IResult::*;

#[macro_export]
macro_rules! tag(
  ($name:ident $inp:expr) => (
    fn $name(i:&[u8]) -> IResult<&[u8], &[u8]>{
      if i.len() >= $inp.len() && i.slice(0, $inp.len()) == $inp {
        Done(i.slice_from($inp.len()), i.slice(0, 0))
      } else {
        Error(0)
      }
    }
  )
)

macro_rules! o (
  ($name:ident<$i:ty,$o:ty> $f1:expr $($rest:tt)*) => (
    fn $name(input:$i) -> IResult<$i, $o>{
      match $f1(input) {
        Error(e)  => Error(e),
        Incomplete(i) => Incomplete(i),
        Done(i,o) => {
          o_parser!(i o $($rest)*)
        }
      }
    }
  );
)

macro_rules! o_parser (
  ($i:expr $o:expr) => (Done($i,$o));

  ($i:expr $o:expr ~ $e:expr ~ $($rest:tt)*) => (
    match $e($i) {
      Error(e)  => Error(e),
      Incomplete(i) => Incomplete(i),
      Done(i,o) => {
        o_parser!(i o $($rest)*)
      }
    }

   );
  ($i:expr $o:expr $e:expr $($rest:tt)*) => (
    match $e($i) {
      Error(e)  => Error(e),
      Incomplete(i) => Incomplete(i),
      Done(i,_) => {
        o_parser!(i $o $($rest)*)
      }
    }
   );
)

macro_rules! chain (
  ($name:ident<$i:ty,$o:ty>, $assemble:expr, $($rest:tt)*) => (
    fn $name(i:$i) -> IResult<$i,$o>{
      chaining_parser!(i, $assemble, $($rest)*)
    }
  );
)

macro_rules! chaining_parser (
  ($i:expr, $assemble:expr, $field:ident : $e:expr, $($rest:tt)*) => (
    match $e($i) {
      Error(e)  => Error(e),
      Incomplete(i) => Incomplete(i),
      Done(i,o) => {
        let $field = o;
        chaining_parser!(i, $assemble, $($rest)*)
      }
    }
  );

  ($i:expr, $assemble:expr, ) => (
    Done($i, $assemble())
  )
)

macro_rules! alt (
  ($name:ident<$i:ty,$o:ty>, $($rest:tt)*) => (
    fn $name(i:$i) -> IResult<$i,$o>{
      alt_parser!(i, $($rest)*)
    }
  );
)

macro_rules! alt_parser (
  ($i:expr, $e:expr $($rest:tt)*) => (
    match $e($i) {
      Error(_)  => alt_parser!($i, $($rest)*),
      Incomplete(_) => alt_parser!($i, $($rest)*),
      Done(i,o) => Done(i,o)
    }
  );

  ($i:expr, ) => (
    Error(1)
  )
)

pub fn print<'a,T: Show>(input: T) -> IResult<T, ()> {
  println!("{}", input);
  Done(input, ())
}

pub fn begin<'a>(input: &'a [u8]) -> IResult<(), &'a [u8]> {
  Done((), input)
}

#[macro_export]
macro_rules! is_not(
  ($name:ident $arr:expr) => (
    fn $name(input:&[u8]) -> IResult<&[u8], &[u8]> {
      for idx in range(0, input.len()) {
        for &i in $arr.iter() {
          if input[idx] == i {
            return Done(input.slice_from(idx), input.slice(0, idx))
          }
        }
      }
      Done("".as_bytes(), input)
    }
  )
)

#[macro_export]
macro_rules! is_a(
  ($name:ident $arr:expr) => (
    fn $name(input:&[u8]) -> IResult<&[u8], &[u8]> {
      for idx in range(0, input.len()) {
        var res = false
        for &i in $arr.iter() {
          if input[idx] == i {
            res = true
          }
        }
        if !res {
          return Done(input.slice_from(idx), input.slice(0, idx))
        }
      }
      Done("".as_bytes(), input)
    }
  )
)

#[macro_export]
macro_rules! filter(
  ($name:ident $f:ident) => (
    fn $name(input:&[u8]) -> IResult<&[u8], &[u8]> {
      for idx in range(0, input.len()) {
        if !$f(input[idx]) {
          return Done(input.slice_from(idx), input.slice(0, idx))
        }
      }
      Done("".as_bytes(), input)
    }
  )
)

// FIXME: when rust-lang/rust#17436 is fixed, macros will be able to export
// public methods
//pub is_not!(line_ending "\r\n".as_bytes())
pub fn line_ending(input:&[u8]) -> IResult<&[u8], &[u8]> {
  for idx in range(0, input.len()) {
    for &i in "\r\n".as_bytes().iter() {
      if input[idx] == i {
        return Done(input.slice_from(idx), input.slice(0, idx))
      }
    }
  }
  Done("".as_bytes(), input)
}

pub fn is_alphabetic(chr:u8) -> bool {
  (chr >= 0x41 && chr <= 0x5A) || (chr >= 0x61 && chr <= 0x7A)
}

pub fn is_digit(chr: u8) -> bool {
  chr >= 0x30 && chr <= 0x39
}

pub fn is_alphanumeric(chr: u8) -> bool {
  is_alphabetic(chr) || is_digit(chr)
}

// FIXME: when rust-lang/rust#17436 is fixed, macros will be able to export
//pub filter!(alpha is_alphabetic)
//pub filter!(digit is_digit)
//pub filter!(alphanumeric is_alphanumeric)
pub fn alpha(input:&[u8]) -> IResult<&[u8], &[u8]> {
  for idx in range(0, input.len()) {
    if !is_alphabetic(input[idx]) {
      return Done(input.slice_from(idx), input.slice(0, idx))
    }
  }
  Done("".as_bytes(), input)
}

pub fn digit(input:&[u8]) -> IResult<&[u8], &[u8]> {
  for idx in range(0, input.len()) {
    if !is_digit(input[idx]) {
      return Done(input.slice_from(idx), input.slice(0, idx))
    }
  }
  Done("".as_bytes(), input)
}

pub fn alphanumeric(input:&[u8]) -> IResult<&[u8], &[u8]> {
  for idx in range(0, input.len()) {
    if !is_alphanumeric(input[idx]) {
      return Done(input.slice_from(idx), input.slice(0, idx))
    }
  }
  Done("".as_bytes(), input)
}

pub fn sized_buffer(input:&[u8]) -> IResult<&[u8], &[u8]> {
  if input.len() == 0 {
    //FIXME: should return Incomplete
    return Error(0)
  }

  let len = input[0] as uint;

  if input.len() >= len + 1 {
    return Done(input.slice_from(len+1), input.slice(1, len+1))
  } else {
    //FIXME: should return Incomplete
    return Error(0)
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use map::*;
  use internal::IResult;
  use internal::IResult::*;

  use std::str;

  #[test]
  fn character_test() {
    let empty = "".as_bytes();
    let a = "abcd".as_bytes();
    let b = "1234".as_bytes();
    let c = "a123".as_bytes();
    let d = "azé12".as_bytes();
    assert_eq!(Done((),a).flat_map(alpha), Done(empty, a))
    assert_eq!(Done((),b).flat_map(alpha), Done(b, empty))
    assert_eq!(Done((),c).flat_map(alpha), Done(c.slice_from(1), "a".as_bytes()))
    assert_eq!(Done((),d).flat_map(alpha), Done("é12".as_bytes(), "az".as_bytes()))
    assert_eq!(Done((),a).flat_map(digit), Done(a, empty))
    assert_eq!(Done((),b).flat_map(digit), Done(empty, b))
    assert_eq!(Done((),c).flat_map(digit), Done(c, empty))
    assert_eq!(Done((),d).flat_map(digit), Done(d, empty))
    assert_eq!(Done((),a).flat_map(alphanumeric), Done(empty, a))
    assert_eq!(Done((),b).flat_map(alphanumeric), Done(empty, b))
    assert_eq!(Done((),c).flat_map(alphanumeric), Done(empty, c))
    assert_eq!(Done((),d).flat_map(alphanumeric), Done("é12".as_bytes(), "az".as_bytes()))
  }

  #[test]
  fn is_not_test() {
    let a = "ab12cd\nefgh".as_bytes();
    assert_eq!(Done((), a).flat_map(line_ending), Done("\nefgh".as_bytes(), "ab12cd".as_bytes()))
  }

  #[test]
  fn sized_buffer_test() {
    let arr:[u8, ..6] = [3, 4, 5, 6, 7, 8];
    let res = Done((), arr.as_slice()).flat_map(sized_buffer);
    let i = [7,8];
    let o = [4,5,6];
    assert_eq!(res, Done(i.as_slice(), o.as_slice()))
  }

  #[test]
  fn t1() {
    let v1:Vec<u8> = vec![1,2,3];
    let v2:Vec<u8> = vec![4,5,6];
    let d = Done(v1.as_slice(), v2.as_slice());
    let res = d.flat_map(print);
    assert_eq!(res, Done(v2.as_slice(), ()));
  }

  #[deriving(PartialEq,Eq,Show)]
  struct B {
    a: int,
    b: int
  }

  #[test]
  fn chain_and_ignore_test() {
    tag!(x "abcd".as_bytes());
    tag!(y "efgh".as_bytes());
    fn ret_int(i:&[u8]) -> IResult<&[u8], int> { Done(i,1) };
    //o!(z<&[u8], int>  x S x S retInt Z y);
    o!(z<&[u8], int>  x  x ~ret_int~ y);

    let r = Done((), "abcdabcdefgh".as_bytes()).flat_map(z);
    assert_eq!(r, Done("".as_bytes(), 1));
  }

  #[test]
  fn chain_test() {
    tag!(x "abcd".as_bytes());
    fn temp_ret_int1(i:&[u8]) -> IResult<&[u8], int> { Done(i,1) };
    o!(ret_int1<&[u8],int> x ~ temp_ret_int1 ~);
    fn ret_int2(i:&[u8]) -> IResult<&[u8], int> { Done(i,2) };
    chain!(f<&[u8],B>, ||{B{a: aa, b: bb}}, aa: ret_int1, bb: ret_int2,);

    let r = Done((), "abcde".as_bytes()).flat_map(f);
    assert_eq!(r, Done("e".as_bytes(), B{a: 1, b: 2}));
  }

  #[test]
  fn alt_test() {
    fn work(input: &[u8]) -> IResult<&[u8],&[u8]> {
      Done("".as_bytes(), input)
    }
    fn dont_work(input: &[u8]) -> IResult<&[u8],&[u8]> {
      Error(3)
    }
    fn work2(input: &[u8]) -> IResult<&[u8],&[u8]> {
      Done(input, "".as_bytes())
    }

    alt!(alt1<&[u8],&[u8]>, dont_work dont_work)
    alt!(alt2<&[u8],&[u8]>, dont_work work)
    alt!(alt3<&[u8],&[u8]>, dont_work dont_work work2 dont_work)

    let a = "abcd".as_bytes();
    assert_eq!(Done((), a).flat_map(alt1), Error(1))
    assert_eq!(Done((), a).flat_map(alt2), Done("".as_bytes(), a))
    assert_eq!(Done((), a).flat_map(alt3), Done(a, "".as_bytes()))
  }

  /* FIXME: this makes rustc weep
  fn pr(par: IResult<(),&[u8]>) -> IResult<&[u8], ()> {
    Error(0)
  }

  #[test]
  fn rustc_panic_test() {
    FileProducer::new("links.txt", 20).map(|producer: FileProducer| {
      let mut p = producer;
      p.push(pr);
    });
  }*/
}
<|endoftext|>


<commit_before>//! The functions in this section provide optimized copying to persistent memory
//!
//! The `copy`, `copy_nonoverlapping`, and `write_bytes`, provide the same memory copying as
//! `memmove(3)`, `memcpy(3)`, and `memset(3)`, and ensure that the result has been flushed to persistence before returning.
//!
//! > **Warning:** Using these functions where `is_pmem(1)` returns false may not do anything useful.
//! >              Use the normal libc functions in that case.

use ::std::mem;
use ::std::io;
use ::std::marker::PhantomData;

use ::libc::{c_void, c_int};
use ::libc::size_t;
use ::pmem_sys as ffi;

use pmap::PersistentMap;

/// Persistent memory virtual pointer
///
/// This pointer is safe to store.
pub struct PmemConstVirtualPtr<T: ?Sized> {
    poolid: usize,
    offset: usize,
    _t: PhantomData<T>,
}

impl<T: ?Sized> PmemConstVirtualPtr<T> {
    pub unsafe fn new(poolid: usize, offset: usize) -> Self {
        assert!(poolid != 0, "Poolid 0 is reserved for null pointers");
        PmemConstVirtualPtr { poolid: poolid, offset: offset, _t: PhantomData }
    }

    pub fn null() -> Self { PmemConstVirtualPtr { poolid: 0, offset: 0, _t: PhantomData } }

    pub fn is_null(&self) -> bool { self.poolid == 0 }

    pub unsafe fn as_type<U>(self) -> PmemConstVirtualPtr<U> {
        PmemConstVirtualPtr { poolid: self.poolid, offset: self.offset, _t: PhantomData }
    }
}

impl<T> PmemConstVirtualPtr<T> {
    pub unsafe fn offset(&self, count: isize) -> Self {
        if self.is_null() {
            PmemConstVirtualPtr::null()
        } else {
            let new_offset = self.offset as isize + mem::size_of::<T>() as isize * count;
            PmemConstVirtualPtr { poolid: self.poolid, offset: new_offset as usize, _t: self._t }
        }
    }

    pub unsafe fn link(self, pool: &PersistentMap) -> PmemConstPtr<T> {
        PmemConstPtr { virt: self, pool: pool.as_ptr() }
    }
}

/// Persistent memory virtual mutable pointer
///
/// This pointer is safe to store.
pub struct PmemMutVirtualPtr<T: ?Sized> {
    poolid: usize,
    offset: usize,
    _t: PhantomData<T>,
}

impl<T: ?Sized> PmemMutVirtualPtr<T> {
    pub unsafe fn new(poolid: usize, offset: usize) -> Self {
        assert!(poolid != 0, "Poolid 0 is reserved for null pointers");
        PmemMutVirtualPtr { poolid: poolid, offset: offset, _t: PhantomData }
    }

    pub fn null() -> Self { PmemMutVirtualPtr { poolid: 0, offset: 0, _t: PhantomData } }

    pub fn is_null(&self) -> bool { self.poolid == 0 }

    pub unsafe fn as_type<U>(self) -> PmemMutVirtualPtr<U> {
        PmemMutVirtualPtr { poolid: self.poolid, offset: self.offset, _t: PhantomData }
    }
}

impl<T> PmemMutVirtualPtr<T> {
    pub unsafe fn offset(&self, count: isize) -> Self {
        if self.is_null() {
            PmemMutVirtualPtr::null()
        } else {
            let new_offset = self.offset as isize + mem::size_of::<T>() as isize * count;
            PmemMutVirtualPtr { poolid: self.poolid, offset: new_offset as usize, _t: self._t }
        }
    }

    pub unsafe fn link(self, pool: &mut PersistentMap) -> PmemMutPtr<T> {
        PmemMutPtr { virt: self, pool: pool.as_mut_ptr() }
    }
}

/// Direct `*const T` pointer to a pmem location
///
/// # Safety
///
/// This pointer is **not** safe to store directly on pmem.
/// You can get a _safe_ virtual pointer using `as_virtual()`.
pub struct PmemConstPtr<T: ?Sized> {
    virt: PmemConstVirtualPtr<T>,
    pool: *const T,
}

impl<T: ?Sized> PmemConstPtr<T> {
    pub fn is_null(&self) -> bool { self.virt.is_null() }
}

impl<T> PmemConstPtr<T> {
    pub unsafe fn direct(&self) -> *const T {
        if self.is_null() {
            ::std::ptr::null()
        } else {
            self.pool.offset(self.virt.offset as isize) as *const T
        }
    }

    pub fn as_virtual(self) -> PmemConstVirtualPtr<T> {
        self.virt
    }

    pub unsafe fn offset(&self, count: isize) -> Self {
        let new_virt = self.virt.offset(count);
        PmemConstPtr { virt: new_virt, pool: self.pool }
    }

    pub unsafe fn as_type<U>(self) -> PmemConstPtr<U> {
        let new_virt = self.virt.as_type();
        PmemConstPtr { virt: new_virt, pool: self.pool as *mut U }
    }
}

/// Direct `*mut T` pointer to a pmem location
///
/// # Safety
///
/// This pointer is **not** safe to store directly on pmem.
/// You can get a _safe_ virtual pointer using `as_virtual()`.
pub struct PmemMutPtr<T: ?Sized> {
    virt: PmemMutVirtualPtr<T>,
    pool: *mut T,
}

impl<T: ?Sized> PmemMutPtr<T> {
    pub fn is_null(&self) -> bool { self.virt.is_null() }
}

impl<T> PmemMutPtr<T> {
    pub unsafe fn direct(&self) -> *mut T {
        if self.is_null() {
            ::std::ptr::null_mut()
        } else {
            self.pool.offset(self.virt.offset as isize) as *mut T
        }
    }

    pub fn as_virtual(self) -> PmemMutVirtualPtr<T> {
        self.virt
    }

    pub unsafe fn offset(&self, count: isize) -> Self {
        let new_virt = self.virt.offset(count);
        PmemMutPtr { virt: new_virt, pool: self.pool }
    }

    pub unsafe fn as_type<U>(self) -> PmemMutPtr<U> {
        let new_virt = self.virt.as_type();
        PmemMutPtr { virt: new_virt, pool: self.pool as *mut U }
    }
}

pub fn null<T>() -> PmemConstVirtualPtr<T> {
    PmemConstVirtualPtr::null()
}

pub fn null_mut<T>() -> PmemMutVirtualPtr<T> {
    PmemMutVirtualPtr::null()
}

/// Copies `count * size_of<T>` bytes from `src` to `pmemdest`. The source and destination may overlap.
///
/// `copy` is semantically equivalent to C's `memmove` and is optimized for persitent memory.
///
/// Ensures that the result has been flushed to persistence before returning.
///
/// # Safety
///
/// Care must be taken with the ownership of `src` and `pmemdest`.
/// This method semantically moves the values of `src` into `pmemdest`.
/// However it does not drop the contents of `pmemdest`, or prevent the contents of `src` from being dropped or used.
pub unsafe fn copy<T>(src: *const T, pmemdest: *mut T, count: usize) {
    let len = mem::size_of::<T>() * count;
    ffi::pmem_memmove_persist(pmemdest as *mut c_void, src as *const c_void, len as size_t);
}

/// Copies `count * size_of<T>` bytes from `src` to `pmemdest`. The source and destination may _not_ overlap.
///
/// `copy_nonoverlapping` is semantically equivalent to C's `memcpy` and is optimized for persitent memory.
///
/// Ensures that the result has been flushed to persistence before returning.
///
/// # Safety
///
/// Beyond requiring that the program must be allowed to access both regions of memory,
/// it is _Undefined Behavior_ for source and destination to overlap.
/// Care must also be taken with the ownership of `src` and `pmemdest`.
/// This method semantically moves the values of `src` into `pmemdest`.
/// However it does not drop the contents of `pmemdest`, or prevent the contents of `src` from being dropped or used.
pub unsafe fn copy_nonoverlapping<T>(src: *const T, pmemdest: *mut T, count: usize) {
    let len = mem::size_of::<T>() * count;
    ffi::pmem_memcpy_persist(pmemdest as *mut c_void, src as *const c_void, len as size_t);
}

/// Invokes memset on the specified pointer, setting `count * size_of::<T>()` bytes of memory starting at `pmemdest` to `val`.
///
/// Ensures that the result has been flushed to persistence before returning.
pub unsafe fn write_bytes<T>(pmemdest: *mut T, val: u8, count: usize) {
    let len = mem::size_of::<T>() * count;
    ffi::pmem_memset_persist(pmemdest as *mut c_void, val as c_int, len as size_t);
}

/// Overwrites a memory location with the given value without reading or dropping the old value.
///
/// Ensures that the result has been flushed to persistence before returning.
///
/// # Safety
///
/// This operation is marked unsafe because it accepts a raw pointer.
///
/// It does not drop the contents of dst. This is safe, but it could leak allocations or resources,
/// so care must be taken not to overwrite an object that should be dropped.
///
/// This is appropriate for initializing uninitialized memory, or overwriting memory that has previously been read from.
pub unsafe fn write<T>(pmemdest: *mut T, val: T) { copy_nonoverlapping(&val as *const _, pmemdest, 1) }

pub unsafe fn msync<T>(pmemdest: *const T, count: usize) -> Result<(), io::Error> {
    let len = count * mem::size_of::<T>();
    let r = ffi::pmem_msync(pmemdest as *const c_void, len as size_t);
    if r == -1 {
        Err(io::Error::last_os_error())
    } else {
        Ok(())
    }
}
<commit_msg>feat: mut <-> const transitions<commit_after>//! The functions in this section provide optimized copying to persistent memory
//!
//! The `copy`, `copy_nonoverlapping`, and `write_bytes`, provide the same memory copying as
//! `memmove(3)`, `memcpy(3)`, and `memset(3)`, and ensure that the result has been flushed to persistence before returning.
//!
//! > **Warning:** Using these functions where `is_pmem(1)` returns false may not do anything useful.
//! >              Use the normal libc functions in that case.

use ::std::mem;
use ::std::io;
use ::std::marker::PhantomData;

use ::libc::{c_void, c_int};
use ::libc::size_t;
use ::pmem_sys as ffi;

use pmap::PersistentMap;

/// Persistent memory virtual pointer
///
/// This pointer is safe to store.
pub struct PmemConstVirtualPtr<T: ?Sized> {
    poolid: usize,
    offset: usize,
    _t: PhantomData<T>,
}

impl<T: ?Sized> PmemConstVirtualPtr<T> {
    pub unsafe fn new(poolid: usize, offset: usize) -> Self {
        assert!(poolid != 0, "Poolid 0 is reserved for null pointers");
        PmemConstVirtualPtr { poolid: poolid, offset: offset, _t: PhantomData }
    }

    pub fn null() -> Self { PmemConstVirtualPtr { poolid: 0, offset: 0, _t: PhantomData } }

    pub fn is_null(&self) -> bool { self.poolid == 0 }

    pub unsafe fn as_type<U>(self) -> PmemConstVirtualPtr<U> {
        PmemConstVirtualPtr { poolid: self.poolid, offset: self.offset, _t: PhantomData }
    }

    pub unsafe fn as_mut(self) -> PmemMutVirtualPtr<T> {
        PmemMutVirtualPtr { poolid: self.poolid, offset: self.offset, _t: PhantomData }
    }
}

impl<T> PmemConstVirtualPtr<T> {
    pub unsafe fn offset(&self, count: isize) -> Self {
        if self.is_null() {
            PmemConstVirtualPtr::null()
        } else {
            let new_offset = self.offset as isize + mem::size_of::<T>() as isize * count;
            PmemConstVirtualPtr { poolid: self.poolid, offset: new_offset as usize, _t: self._t }
        }
    }

    pub unsafe fn link(self, pool: &PersistentMap) -> PmemConstPtr<T> {
        PmemConstPtr { virt: self, pool: pool.as_ptr() }
    }
}

/// Persistent memory virtual mutable pointer
///
/// This pointer is safe to store.
pub struct PmemMutVirtualPtr<T: ?Sized> {
    poolid: usize,
    offset: usize,
    _t: PhantomData<T>,
}

impl<T: ?Sized> PmemMutVirtualPtr<T> {
    pub unsafe fn new(poolid: usize, offset: usize) -> Self {
        assert!(poolid != 0, "Poolid 0 is reserved for null pointers");
        PmemMutVirtualPtr { poolid: poolid, offset: offset, _t: PhantomData }
    }

    pub fn null() -> Self { PmemMutVirtualPtr { poolid: 0, offset: 0, _t: PhantomData } }

    pub fn is_null(&self) -> bool { self.poolid == 0 }

    pub unsafe fn as_type<U>(self) -> PmemMutVirtualPtr<U> {
        PmemMutVirtualPtr { poolid: self.poolid, offset: self.offset, _t: PhantomData }
    }

    pub unsafe fn as_const(self) -> PmemConstVirtualPtr<T> {
        PmemConstVirtualPtr { poolid: self.poolid, offset: self.offset, _t: PhantomData }
    }
}

impl<T> PmemMutVirtualPtr<T> {
    pub unsafe fn offset(&self, count: isize) -> Self {
        if self.is_null() {
            PmemMutVirtualPtr::null()
        } else {
            let new_offset = self.offset as isize + mem::size_of::<T>() as isize * count;
            PmemMutVirtualPtr { poolid: self.poolid, offset: new_offset as usize, _t: self._t }
        }
    }

    pub unsafe fn link(self, pool: &mut PersistentMap) -> PmemMutPtr<T> {
        PmemMutPtr { virt: self, pool: pool.as_mut_ptr() }
    }
}

/// Direct `*const T` pointer to a pmem location
///
/// # Safety
///
/// This pointer is **not** safe to store directly on pmem.
/// You can get a _safe_ virtual pointer using `as_virtual()`.
pub struct PmemConstPtr<T: ?Sized> {
    virt: PmemConstVirtualPtr<T>,
    pool: *const T,
}

impl<T: ?Sized> PmemConstPtr<T> {
    pub fn is_null(&self) -> bool { self.virt.is_null() }

    pub unsafe fn as_mut(self) -> PmemMutPtr<T> {
        PmemMutPtr { virt: self.virt.as_mut(), pool: self.pool as *mut T }
    }
}

impl<T> PmemConstPtr<T> {
    pub unsafe fn direct(&self) -> *const T {
        if self.is_null() {
            ::std::ptr::null()
        } else {
            self.pool.offset(self.virt.offset as isize) as *const T
        }
    }

    pub fn as_virtual(self) -> PmemConstVirtualPtr<T> {
        self.virt
    }

    pub unsafe fn offset(&self, count: isize) -> Self {
        let new_virt = self.virt.offset(count);
        PmemConstPtr { virt: new_virt, pool: self.pool }
    }

    pub unsafe fn as_type<U>(self) -> PmemConstPtr<U> {
        let new_virt = self.virt.as_type();
        PmemConstPtr { virt: new_virt, pool: self.pool as *mut U }
    }
}

/// Direct `*mut T` pointer to a pmem location
///
/// # Safety
///
/// This pointer is **not** safe to store directly on pmem.
/// You can get a _safe_ virtual pointer using `as_virtual()`.
pub struct PmemMutPtr<T: ?Sized> {
    virt: PmemMutVirtualPtr<T>,
    pool: *mut T,
}

impl<T: ?Sized> PmemMutPtr<T> {
    pub fn is_null(&self) -> bool { self.virt.is_null() }

    pub unsafe fn as_const(self) -> PmemConstPtr<T> {
        PmemConstPtr { virt: self.virt.as_const(), pool: self.pool as *const T }
    }
}

impl<T> PmemMutPtr<T> {
    pub unsafe fn direct(&self) -> *mut T {
        if self.is_null() {
            ::std::ptr::null_mut()
        } else {
            self.pool.offset(self.virt.offset as isize) as *mut T
        }
    }

    pub fn as_virtual(self) -> PmemMutVirtualPtr<T> {
        self.virt
    }

    pub unsafe fn offset(&self, count: isize) -> Self {
        let new_virt = self.virt.offset(count);
        PmemMutPtr { virt: new_virt, pool: self.pool }
    }

    pub unsafe fn as_type<U>(self) -> PmemMutPtr<U> {
        let new_virt = self.virt.as_type();
        PmemMutPtr { virt: new_virt, pool: self.pool as *mut U }
    }
}

pub fn null<T>() -> PmemConstVirtualPtr<T> {
    PmemConstVirtualPtr::null()
}

pub fn null_mut<T>() -> PmemMutVirtualPtr<T> {
    PmemMutVirtualPtr::null()
}

/// Copies `count * size_of<T>` bytes from `src` to `pmemdest`. The source and destination may overlap.
///
/// `copy` is semantically equivalent to C's `memmove` and is optimized for persitent memory.
///
/// Ensures that the result has been flushed to persistence before returning.
///
/// # Safety
///
/// Care must be taken with the ownership of `src` and `pmemdest`.
/// This method semantically moves the values of `src` into `pmemdest`.
/// However it does not drop the contents of `pmemdest`, or prevent the contents of `src` from being dropped or used.
pub unsafe fn copy<T>(src: *const T, pmemdest: *mut T, count: usize) {
    let len = mem::size_of::<T>() * count;
    ffi::pmem_memmove_persist(pmemdest as *mut c_void, src as *const c_void, len as size_t);
}

/// Copies `count * size_of<T>` bytes from `src` to `pmemdest`. The source and destination may _not_ overlap.
///
/// `copy_nonoverlapping` is semantically equivalent to C's `memcpy` and is optimized for persitent memory.
///
/// Ensures that the result has been flushed to persistence before returning.
///
/// # Safety
///
/// Beyond requiring that the program must be allowed to access both regions of memory,
/// it is _Undefined Behavior_ for source and destination to overlap.
/// Care must also be taken with the ownership of `src` and `pmemdest`.
/// This method semantically moves the values of `src` into `pmemdest`.
/// However it does not drop the contents of `pmemdest`, or prevent the contents of `src` from being dropped or used.
pub unsafe fn copy_nonoverlapping<T>(src: *const T, pmemdest: *mut T, count: usize) {
    let len = mem::size_of::<T>() * count;
    ffi::pmem_memcpy_persist(pmemdest as *mut c_void, src as *const c_void, len as size_t);
}

/// Invokes memset on the specified pointer, setting `count * size_of::<T>()` bytes of memory starting at `pmemdest` to `val`.
///
/// Ensures that the result has been flushed to persistence before returning.
pub unsafe fn write_bytes<T>(pmemdest: *mut T, val: u8, count: usize) {
    let len = mem::size_of::<T>() * count;
    ffi::pmem_memset_persist(pmemdest as *mut c_void, val as c_int, len as size_t);
}

/// Overwrites a memory location with the given value without reading or dropping the old value.
///
/// Ensures that the result has been flushed to persistence before returning.
///
/// # Safety
///
/// This operation is marked unsafe because it accepts a raw pointer.
///
/// It does not drop the contents of dst. This is safe, but it could leak allocations or resources,
/// so care must be taken not to overwrite an object that should be dropped.
///
/// This is appropriate for initializing uninitialized memory, or overwriting memory that has previously been read from.
pub unsafe fn write<T>(pmemdest: *mut T, val: T) { copy_nonoverlapping(&val as *const _, pmemdest, 1) }

pub unsafe fn msync<T>(pmemdest: *const T, count: usize) -> Result<(), io::Error> {
    let len = count * mem::size_of::<T>();
    let r = ffi::pmem_msync(pmemdest as *const c_void, len as size_t);
    if r == -1 {
        Err(io::Error::last_os_error())
    } else {
        Ok(())
    }
}
<|endoftext|>


<commit_before>//! Raw un-exported bindings to miniz for encoding/decoding

use std::io::prelude::*;
use std::io;
use libc;

use Compression;
use ffi;
use stream::{Stream, Compress, Decompress, Direction, Flush};

pub struct EncoderWriter<W: Write>(InnerWrite<W, Compress>);
pub struct DecoderWriter<W: Write>(InnerWrite<W, Decompress>);

struct InnerWrite<W, D: Direction> {
    inner: Option<W>,
    stream: Stream<D>,
    buf: Vec<u8>,
}

pub struct EncoderReader<R: Read>(InnerRead<R, Compress>);
pub struct DecoderReader<R: Read>(InnerRead<R, Decompress>);

struct InnerRead<R, D: Direction> {
    inner: R,
    stream: Stream<D>,
    buf: Vec<u8>, // TODO: this should be Box<[u8]>
    pos: usize,
    cap: usize,
}

impl<W: Write> EncoderWriter<W> {
    pub fn new(w: W, level: Compression, raw: bool, buf: Vec<u8>)
               -> EncoderWriter<W> {
        EncoderWriter(InnerWrite {
            inner: Some(w),
            stream: Stream::new_compress(level, raw),
            buf: buf,
        })
    }

    pub fn finish(&mut self) -> io::Result<()> {
        self.0.finish(&mut |stream, inner| {
            stream.compress_vec(&[], inner, Flush::Finish)
        })
    }

    pub fn into_inner(mut self) -> W { self.0.inner.take().unwrap() }

    pub fn take_inner(&mut self) -> W { self.0.inner.take().unwrap() }

    pub fn write_all_raw(&mut self, buf: &[u8]) -> io::Result<()> {
        self.0.inner.as_mut().unwrap().write_all(buf)
    }

    pub fn unwrapped(&self) -> bool {
        self.0.inner.is_none()
    }
}

impl<W: Write> Write for EncoderWriter<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        // miniz isn't guaranteed to actually write any of the buffer provided,
        // it may be in a flushing mode where it's just giving us data before
        // we're actually giving it any data. We don't want to spuriously return
        // `Ok(0)` when possible as it will cause calls to write_all() to fail.
        // As a result we execute this in a loop to ensure that we try our
        // darndest to write the data.
        loop {
            let n = try!(self.0.write(&mut |stream, inner| {
                stream.compress_vec(buf, inner, Flush::None)
            }));
            if buf.len() == 0 || n != 0 {
                return Ok(n)
            }
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        self.0.finish(&mut |stream, inner| {
            stream.compress_vec(&[], inner, Flush::Sync)
        }).and_then(|()| self.0.inner.as_mut().unwrap().flush())
    }
}

impl<W: Write> Drop for EncoderWriter<W> {
    fn drop(&mut self) {
        if self.0.inner.is_some() {
            let _ = self.finish();
        }
    }
}

impl<W: Write> DecoderWriter<W> {
    pub fn new(w: W, raw: bool, buf: Vec<u8>) -> DecoderWriter<W> {
        DecoderWriter(InnerWrite {
            inner: Some(w),
            stream: Stream::new_decompress(raw),
            buf: buf,
        })
    }

    pub fn finish(&mut self) -> io::Result<()> {
        self.0.finish(&mut |stream, inner| {
            stream.decompress_vec(&[], inner, Flush::Finish)
        })
    }

    pub fn into_inner(mut self) -> W { self.0.inner.take().unwrap() }
}

impl<W: Write> Write for DecoderWriter<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        // See EncoderWriter::write for why this is in a loop
        loop {
            let n = try!(self.0.write(&mut |stream, inner| {
                stream.decompress_vec(buf, inner, Flush::None)
            }));
            if buf.len() == 0 || n != 0 {
                return Ok(n)
            }
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        self.0.finish(&mut |stream, inner| {
            stream.decompress_vec(&[], inner, Flush::Sync)
        }).and_then(|()| self.0.inner.as_mut().unwrap().flush())
    }
}

impl<W: Write, D: Direction> InnerWrite<W, D> {
    fn write<F>(&mut self, f: &mut F) -> io::Result<usize>
        where F: FnMut(&mut Stream<D>, &mut Vec<u8>) -> libc::c_int
    {
        let writer = self.inner.as_mut().unwrap();
        if self.buf.len() > 0 {
            try!(writer.write_all(&self.buf));
            self.buf.truncate(0);
        }

        let before_in = self.stream.total_in();
        let ret = f(&mut self.stream, &mut self.buf);
        let written = (self.stream.total_in() - before_in) as usize;
        match ret {
            ffi::MZ_OK | ffi::MZ_BUF_ERROR | ffi::MZ_STREAM_END => Ok(written),
            n => panic!("unexpected return {}", n),
        }
    }

    fn finish<F>(&mut self, f: &mut F) -> io::Result<()>
        where F: FnMut(&mut Stream<D>, &mut Vec<u8>) -> libc::c_int
    {
        // Unfortunately miniz doesn't actually tell us when we're done with
        // pulling out all the data from the internal stream. To remedy this we
        // have to continually ask the stream for more memory until it doesn't
        // give us a chunk of memory the same size as our own internal buffer,
        // at which point we assume it's reached the end.
        let mut cont = true;
        while cont {
            try!(self.write(f));
            let inner = self.inner.as_mut().unwrap();
            if self.buf.len() > 0 {
                try!(inner.write_all(&self.buf));
            }
            cont = self.buf.len() == self.buf.capacity();
            self.buf.truncate(0);
        }
        Ok(())
    }
}

impl<R: Read> EncoderReader<R> {
    pub fn new(w: R, level: Compression, raw: bool, buf: Vec<u8>)
               -> EncoderReader<R> {
        EncoderReader(InnerRead {
            inner: w,
            stream: Stream::new_compress(level, raw),
            buf: buf,
            cap: 0,
            pos: 0,
        })
    }
    pub fn get_ref(&self) -> &R { &self.0.inner }
    pub fn into_inner(self) -> R { self.0.inner }
}

impl<R: Read> Read for EncoderReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(|stream, inner, flush| stream.compress(inner, buf, flush))
    }
}

impl<R: Read> DecoderReader<R> {
    pub fn new(r: R, raw: bool, buf: Vec<u8>) -> DecoderReader<R> {
        DecoderReader(InnerRead {
            inner: r,
            stream: Stream::new_decompress(raw),
            buf: buf,
            pos: 0,
            cap: 0,
        })
    }

    pub fn into_inner(self) -> R { self.0.inner }

    pub fn read_raw(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let mut from = &self.0.buf[self.0.pos..self.0.cap];
        match try!(Read::read(&mut from, buf)) {
            0 => {}
            n => { self.0.pos += n; return Ok(n) }
        }
        self.0.inner.read(buf)
    }
}

impl<R: Read> Read for DecoderReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(|stream, inner, flush| stream.decompress(inner, buf, flush))
    }
}

impl<R: Read, D: Direction> InnerRead<R, D> {
    fn read<F>(&mut self, mut f: F) -> io::Result<usize>
        where F: FnMut(&mut Stream<D>, &[u8], Flush) -> libc::c_int
    {
        loop {
            let mut eof = false;
            if self.pos == self.cap {
                self.cap = try!(self.inner.read(&mut self.buf));
                self.pos = 0;
                eof = self.cap == 0;
            }

            let before_out = self.stream.total_out();
            let before_in = self.stream.total_in();
            let ret = f(&mut self.stream, &self.buf[self.pos..self.cap],
                        if eof {Flush::Finish} else {Flush::None});
            let read = (self.stream.total_out() - before_out) as usize;
            self.pos += (self.stream.total_in() - before_in) as usize;

            return match ret {
                ffi::MZ_OK | ffi::MZ_BUF_ERROR => {
                    // If we haven't ready any data and we haven't hit EOF yet,
                    // then we need to keep asking for more data because if we
                    // return that 0 bytes of data have been read then it will
                    // be interpreted as EOF.
                    if read == 0 && !eof { continue }
                    Ok(read)
                }
                ffi::MZ_STREAM_END => return Ok(read),
                ffi::MZ_DATA_ERROR => {
                    Err(io::Error::new(io::ErrorKind::InvalidInput,
                                       "corrupt deflate stream"))
                }
                n => panic!("unexpected return {}", n),
            }
        }
    }
}
<commit_msg>Fix a TODO, use Box<[T]> instead of Vec<T><commit_after>//! Raw un-exported bindings to miniz for encoding/decoding

use std::io::prelude::*;
use std::io;
use libc;

use Compression;
use ffi;
use stream::{Stream, Compress, Decompress, Direction, Flush};

pub struct EncoderWriter<W: Write>(InnerWrite<W, Compress>);
pub struct DecoderWriter<W: Write>(InnerWrite<W, Decompress>);

struct InnerWrite<W, D: Direction> {
    inner: Option<W>,
    stream: Stream<D>,
    buf: Vec<u8>,
}

pub struct EncoderReader<R: Read>(InnerRead<R, Compress>);
pub struct DecoderReader<R: Read>(InnerRead<R, Decompress>);

struct InnerRead<R, D: Direction> {
    inner: R,
    stream: Stream<D>,
    buf: Box<[u8]>,
    pos: usize,
    cap: usize,
}

impl<W: Write> EncoderWriter<W> {
    pub fn new(w: W, level: Compression, raw: bool, buf: Vec<u8>)
               -> EncoderWriter<W> {
        EncoderWriter(InnerWrite {
            inner: Some(w),
            stream: Stream::new_compress(level, raw),
            buf: buf,
        })
    }

    pub fn finish(&mut self) -> io::Result<()> {
        self.0.finish(&mut |stream, inner| {
            stream.compress_vec(&[], inner, Flush::Finish)
        })
    }

    pub fn into_inner(mut self) -> W { self.0.inner.take().unwrap() }

    pub fn take_inner(&mut self) -> W { self.0.inner.take().unwrap() }

    pub fn write_all_raw(&mut self, buf: &[u8]) -> io::Result<()> {
        self.0.inner.as_mut().unwrap().write_all(buf)
    }

    pub fn unwrapped(&self) -> bool {
        self.0.inner.is_none()
    }
}

impl<W: Write> Write for EncoderWriter<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        // miniz isn't guaranteed to actually write any of the buffer provided,
        // it may be in a flushing mode where it's just giving us data before
        // we're actually giving it any data. We don't want to spuriously return
        // `Ok(0)` when possible as it will cause calls to write_all() to fail.
        // As a result we execute this in a loop to ensure that we try our
        // darndest to write the data.
        loop {
            let n = try!(self.0.write(&mut |stream, inner| {
                stream.compress_vec(buf, inner, Flush::None)
            }));
            if buf.len() == 0 || n != 0 {
                return Ok(n)
            }
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        self.0.finish(&mut |stream, inner| {
            stream.compress_vec(&[], inner, Flush::Sync)
        }).and_then(|()| self.0.inner.as_mut().unwrap().flush())
    }
}

impl<W: Write> Drop for EncoderWriter<W> {
    fn drop(&mut self) {
        if self.0.inner.is_some() {
            let _ = self.finish();
        }
    }
}

impl<W: Write> DecoderWriter<W> {
    pub fn new(w: W, raw: bool, buf: Vec<u8>) -> DecoderWriter<W> {
        DecoderWriter(InnerWrite {
            inner: Some(w),
            stream: Stream::new_decompress(raw),
            buf: buf,
        })
    }

    pub fn finish(&mut self) -> io::Result<()> {
        self.0.finish(&mut |stream, inner| {
            stream.decompress_vec(&[], inner, Flush::Finish)
        })
    }

    pub fn into_inner(mut self) -> W { self.0.inner.take().unwrap() }
}

impl<W: Write> Write for DecoderWriter<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        // See EncoderWriter::write for why this is in a loop
        loop {
            let n = try!(self.0.write(&mut |stream, inner| {
                stream.decompress_vec(buf, inner, Flush::None)
            }));
            if buf.len() == 0 || n != 0 {
                return Ok(n)
            }
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        self.0.finish(&mut |stream, inner| {
            stream.decompress_vec(&[], inner, Flush::Sync)
        }).and_then(|()| self.0.inner.as_mut().unwrap().flush())
    }
}

impl<W: Write, D: Direction> InnerWrite<W, D> {
    fn write<F>(&mut self, f: &mut F) -> io::Result<usize>
        where F: FnMut(&mut Stream<D>, &mut Vec<u8>) -> libc::c_int
    {
        let writer = self.inner.as_mut().unwrap();
        if self.buf.len() > 0 {
            try!(writer.write_all(&self.buf));
            self.buf.truncate(0);
        }

        let before_in = self.stream.total_in();
        let ret = f(&mut self.stream, &mut self.buf);
        let written = (self.stream.total_in() - before_in) as usize;
        match ret {
            ffi::MZ_OK | ffi::MZ_BUF_ERROR | ffi::MZ_STREAM_END => Ok(written),
            n => panic!("unexpected return {}", n),
        }
    }

    fn finish<F>(&mut self, f: &mut F) -> io::Result<()>
        where F: FnMut(&mut Stream<D>, &mut Vec<u8>) -> libc::c_int
    {
        // Unfortunately miniz doesn't actually tell us when we're done with
        // pulling out all the data from the internal stream. To remedy this we
        // have to continually ask the stream for more memory until it doesn't
        // give us a chunk of memory the same size as our own internal buffer,
        // at which point we assume it's reached the end.
        let mut cont = true;
        while cont {
            try!(self.write(f));
            let inner = self.inner.as_mut().unwrap();
            if self.buf.len() > 0 {
                try!(inner.write_all(&self.buf));
            }
            cont = self.buf.len() == self.buf.capacity();
            self.buf.truncate(0);
        }
        Ok(())
    }
}

impl<R: Read> EncoderReader<R> {
    pub fn new(w: R, level: Compression, raw: bool, buf: Vec<u8>)
               -> EncoderReader<R> {
        EncoderReader(InnerRead {
            inner: w,
            stream: Stream::new_compress(level, raw),
            buf: buf.into_boxed_slice(),
            cap: 0,
            pos: 0,
        })
    }
    pub fn get_ref(&self) -> &R { &self.0.inner }
    pub fn into_inner(self) -> R { self.0.inner }
}

impl<R: Read> Read for EncoderReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(|stream, inner, flush| stream.compress(inner, buf, flush))
    }
}

impl<R: Read> DecoderReader<R> {
    pub fn new(r: R, raw: bool, buf: Vec<u8>) -> DecoderReader<R> {
        DecoderReader(InnerRead {
            inner: r,
            stream: Stream::new_decompress(raw),
            buf: buf.into_boxed_slice(),
            pos: 0,
            cap: 0,
        })
    }

    pub fn into_inner(self) -> R { self.0.inner }

    pub fn read_raw(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let mut from = &self.0.buf[self.0.pos..self.0.cap];
        match try!(Read::read(&mut from, buf)) {
            0 => {}
            n => { self.0.pos += n; return Ok(n) }
        }
        self.0.inner.read(buf)
    }
}

impl<R: Read> Read for DecoderReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(|stream, inner, flush| stream.decompress(inner, buf, flush))
    }
}

impl<R: Read, D: Direction> InnerRead<R, D> {
    fn read<F>(&mut self, mut f: F) -> io::Result<usize>
        where F: FnMut(&mut Stream<D>, &[u8], Flush) -> libc::c_int
    {
        loop {
            let mut eof = false;
            if self.pos == self.cap {
                self.cap = try!(self.inner.read(&mut self.buf));
                self.pos = 0;
                eof = self.cap == 0;
            }

            let before_out = self.stream.total_out();
            let before_in = self.stream.total_in();
            let ret = f(&mut self.stream, &self.buf[self.pos..self.cap],
                        if eof {Flush::Finish} else {Flush::None});
            let read = (self.stream.total_out() - before_out) as usize;
            self.pos += (self.stream.total_in() - before_in) as usize;

            return match ret {
                ffi::MZ_OK | ffi::MZ_BUF_ERROR => {
                    // If we haven't ready any data and we haven't hit EOF yet,
                    // then we need to keep asking for more data because if we
                    // return that 0 bytes of data have been read then it will
                    // be interpreted as EOF.
                    if read == 0 && !eof { continue }
                    Ok(read)
                }
                ffi::MZ_STREAM_END => return Ok(read),
                ffi::MZ_DATA_ERROR => {
                    Err(io::Error::new(io::ErrorKind::InvalidInput,
                                       "corrupt deflate stream"))
                }
                n => panic!("unexpected return {}", n),
            }
        }
    }
}
<|endoftext|>