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

// To ensure we don't use stdlib allocating types by accident
#[allow(dead_code)]
struct Vec;
#[allow(dead_code)]
struct Box;
#[allow(dead_code)]
struct HashMap;
#[allow(dead_code)]
struct String;

macro_rules! box_database {
    ($($boxenum:ident $boxtype:expr),*,) => {
        #[derive(Clone, Copy, PartialEq)]
        pub enum BoxType {
            $($boxenum),*,
            UnknownBox(u32),
        }

        impl From<u32> for BoxType {
            fn from(t: u32) -> BoxType {
                use self::BoxType::*;
                match t {
                    $($boxtype => $boxenum),*,
                    _ => UnknownBox(t),
                }
            }
        }

        impl Into<u32> for BoxType {
            fn into(self) -> u32 {
                use self::BoxType::*;
                match self {
                    $($boxenum => $boxtype),*,
                    UnknownBox(t) => t,
                }
            }
        }

        impl fmt::Debug for BoxType {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                let fourcc: FourCC = From::from(self.clone());
                fourcc.fmt(f)
            }
        }
    }
}

#[derive(Default, PartialEq, Clone)]
pub struct FourCC {
    pub value: [u8; 4],
}

impl From<u32> for FourCC {
    fn from(number: u32) -> FourCC {
        FourCC {
            value: number.to_be_bytes(),
        }
    }
}

impl From<BoxType> for FourCC {
    fn from(t: BoxType) -> FourCC {
        let box_num: u32 = Into::into(t);
        From::from(box_num)
    }
}

impl From<[u8; 4]> for FourCC {
    fn from(v: [u8; 4]) -> FourCC {
        FourCC { value: v }
    }
}

impl fmt::Debug for FourCC {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match std::str::from_utf8(&self.value) {
            Ok(s) => f.write_str(s),
            Err(_) => self.value.fmt(f),
        }
    }
}

impl fmt::Display for FourCC {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(std::str::from_utf8(&self.value).unwrap_or("null"))
    }
}

impl PartialEq<&[u8; 4]> for FourCC {
    fn eq(&self, other: &&[u8; 4]) -> bool {
        self.value.eq(*other)
    }
}

#[deny(unreachable_patterns)]
box_database!(
    FileTypeBox                       0x6674_7970, // "ftyp"
    MediaDataBox                      0x6d64_6174, // "mdat"
    PrimaryItemBox                    0x7069_746d, // "pitm"
    ItemInfoBox                       0x6969_6e66, // "iinf"
    ItemInfoEntry                     0x696e_6665, // "infe"
    ItemLocationBox                   0x696c_6f63, // "iloc"
    MovieBox                          0x6d6f_6f76, // "moov"
    MovieHeaderBox                    0x6d76_6864, // "mvhd"
    TrackBox                          0x7472_616b, // "trak"
    TrackHeaderBox                    0x746b_6864, // "tkhd"
    EditBox                           0x6564_7473, // "edts"
    MediaBox                          0x6d64_6961, // "mdia"
    EditListBox                       0x656c_7374, // "elst"
    MediaHeaderBox                    0x6d64_6864, // "mdhd"
    HandlerBox                        0x6864_6c72, // "hdlr"
    MediaInformationBox               0x6d69_6e66, // "minf"
    ImageReferenceBox                 0x6972_6566, // "iref"
    ImagePropertiesBox                0x6970_7270, // "iprp"
    ItemPropertyContainerBox          0x6970_636f, // "ipco"
    ItemPropertyAssociationBox        0x6970_6d61, // "ipma"
    ColorInformationBox               0x636f_6c72, // "colr"
    PixelInformationBox               0x7069_7869, // "pixi"
    AuxiliaryTypeProperty             0x6175_7843, // "auxC"
    SampleTableBox                    0x7374_626c, // "stbl"
    SampleDescriptionBox              0x7374_7364, // "stsd"
    TimeToSampleBox                   0x7374_7473, // "stts"
    SampleToChunkBox                  0x7374_7363, // "stsc"
    SampleSizeBox                     0x7374_737a, // "stsz"
    ChunkOffsetBox                    0x7374_636f, // "stco"
    ChunkLargeOffsetBox               0x636f_3634, // "co64"
    SyncSampleBox                     0x7374_7373, // "stss"
    AVCSampleEntry                    0x6176_6331, // "avc1"
    AVC3SampleEntry                   0x6176_6333, // "avc3" - Need to check official name in spec.
    AVCConfigurationBox               0x6176_6343, // "avcC"
    H263SampleEntry                   0x7332_3633, // "s263"
    H263SpecificBox                   0x6432_3633, // "d263"
    MP4AudioSampleEntry               0x6d70_3461, // "mp4a"
    MP4VideoSampleEntry               0x6d70_3476, // "mp4v"
    ESDBox                            0x6573_6473, // "esds"
    VP8SampleEntry                    0x7670_3038, // "vp08"
    VP9SampleEntry                    0x7670_3039, // "vp09"
    VPCodecConfigurationBox           0x7670_6343, // "vpcC"
    AV1SampleEntry                    0x6176_3031, // "av01"
    AV1CodecConfigurationBox          0x6176_3143, // "av1C"
    FLACSampleEntry                   0x664c_6143, // "fLaC"
    FLACSpecificBox                   0x6466_4c61, // "dfLa"
    OpusSampleEntry                   0x4f70_7573, // "Opus"
    OpusSpecificBox                   0x644f_7073, // "dOps"
    ProtectedVisualSampleEntry        0x656e_6376, // "encv" - Need to check official name in spec.
    ProtectedAudioSampleEntry         0x656e_6361, // "enca" - Need to check official name in spec.
    MovieExtendsBox                   0x6d76_6578, // "mvex"
    MovieExtendsHeaderBox             0x6d65_6864, // "mehd"
    QTWaveAtom                        0x7761_7665, // "wave" - quicktime atom
    ProtectionSystemSpecificHeaderBox 0x7073_7368, // "pssh"
    SchemeInformationBox              0x7363_6869, // "schi"
    TrackEncryptionBox                0x7465_6e63, // "tenc"
    ProtectionSchemeInfoBox           0x7369_6e66, // "sinf"
    OriginalFormatBox                 0x6672_6d61, // "frma"
    SchemeTypeBox                     0x7363_686d, // "schm"
    MP3AudioSampleEntry               0x2e6d_7033, // ".mp3" - from F4V.
    CompositionOffsetBox              0x6374_7473, // "ctts"
    LPCMAudioSampleEntry              0x6c70_636d, // "lpcm" - quicktime atom
    ALACSpecificBox                   0x616c_6163, // "alac" - Also used by ALACSampleEntry
    UuidBox                           0x7575_6964, // "uuid"
    MetadataBox                       0x6d65_7461, // "meta"
    MetadataHeaderBox                 0x6d68_6472, // "mhdr"
    MetadataItemKeysBox               0x6b65_7973, // "keys"
    MetadataItemListEntry             0x696c_7374, // "ilst"
    MetadataItemDataEntry             0x6461_7461, // "data"
    MetadataItemNameBox               0x6e61_6d65, // "name"
    UserdataBox                       0x7564_7461, // "udta"
    AlbumEntry                        0xa961_6c62, // "©alb"
    ArtistEntry                       0xa941_5254, // "©ART"
    ArtistLowercaseEntry              0xa961_7274, // "©art"
    AlbumArtistEntry                  0x6141_5254, // "aART"
    CommentEntry                      0xa963_6d74, // "©cmt"
    DateEntry                         0xa964_6179, // "©day"
    TitleEntry                        0xa96e_616d, // "©nam"
    CustomGenreEntry                  0xa967_656e, // "©gen"
    StandardGenreEntry                0x676e_7265, // "gnre"
    TrackNumberEntry                  0x7472_6b6e, // "trkn"
    DiskNumberEntry                   0x6469_736b, // "disk"
    ComposerEntry                     0xa977_7274, // "©wrt"
    EncoderEntry                      0xa974_6f6f, // "©too"
    EncodedByEntry                    0xa965_6e63, // "©enc"
    TempoEntry                        0x746d_706f, // "tmpo"
    CopyrightEntry                    0x6370_7274, // "cprt"
    CompilationEntry                  0x6370_696c, // "cpil"
    CoverArtEntry                     0x636f_7672, // "covr"
    AdvisoryEntry                     0x7274_6e67, // "rtng"
    RatingEntry                       0x7261_7465, // "rate"
    GroupingEntry                     0xa967_7270, // "©grp"
    MediaTypeEntry                    0x7374_696b, // "stik"
    PodcastEntry                      0x7063_7374, // "pcst"
    CategoryEntry                     0x6361_7467, // "catg"
    KeywordEntry                      0x6b65_7977, // "keyw"
    PodcastUrlEntry                   0x7075_726c, // "purl"
    PodcastGuidEntry                  0x6567_6964, // "egid"
    DescriptionEntry                  0x6465_7363, // "desc"
    LongDescriptionEntry              0x6c64_6573, // "ldes"
    LyricsEntry                       0xa96c_7972, // "©lyr"
    TVNetworkNameEntry                0x7476_6e6e, // "tvnn"
    TVShowNameEntry                   0x7476_7368, // "tvsh"
    TVEpisodeNameEntry                0x7476_656e, // "tven"
    TVSeasonNumberEntry               0x7476_736e, // "tvsn"
    TVEpisodeNumberEntry              0x7476_6573, // "tves"
    PurchaseDateEntry                 0x7075_7264, // "purd"
    GaplessPlaybackEntry              0x7067_6170, // "pgap"
    OwnerEntry                        0x6f77_6e72, // "ownr"
    HDVideoEntry                      0x6864_7664, // "hdvd"
    SortNameEntry                     0x736f_6e6d, // "sonm"
    SortAlbumEntry                    0x736f_616c, // "soal"
    SortArtistEntry                   0x736f_6172, // "soar"
    SortAlbumArtistEntry              0x736f_6161, // "soaa"
    SortComposerEntry                 0x736f_636f, // "soco"
);
<commit_msg>Allow optional attributes on entries in the box_database macro<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
use std::fmt;

// To ensure we don't use stdlib allocating types by accident
#[allow(dead_code)]
struct Vec;
#[allow(dead_code)]
struct Box;
#[allow(dead_code)]
struct HashMap;
#[allow(dead_code)]
struct String;

macro_rules! box_database {
    ($($(#[$attr:meta])* $boxenum:ident $boxtype:expr),*,) => {
        #[derive(Clone, Copy, PartialEq)]
        pub enum BoxType {
            $($(#[$attr])* $boxenum),*,
            UnknownBox(u32),
        }

        impl From<u32> for BoxType {
            fn from(t: u32) -> BoxType {
                use self::BoxType::*;
                match t {
                    $($(#[$attr])* $boxtype => $boxenum),*,
                    _ => UnknownBox(t),
                }
            }
        }

        impl Into<u32> for BoxType {
            fn into(self) -> u32 {
                use self::BoxType::*;
                match self {
                    $($(#[$attr])* $boxenum => $boxtype),*,
                    UnknownBox(t) => t,
                }
            }
        }

    }
}

impl fmt::Debug for BoxType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let fourcc: FourCC = From::from(self.clone());
        fourcc.fmt(f)
    }
}

#[derive(Default, PartialEq, Clone)]
pub struct FourCC {
    pub value: [u8; 4],
}

impl From<u32> for FourCC {
    fn from(number: u32) -> FourCC {
        FourCC {
            value: number.to_be_bytes(),
        }
    }
}

impl From<BoxType> for FourCC {
    fn from(t: BoxType) -> FourCC {
        let box_num: u32 = Into::into(t);
        From::from(box_num)
    }
}

impl From<[u8; 4]> for FourCC {
    fn from(v: [u8; 4]) -> FourCC {
        FourCC { value: v }
    }
}

impl fmt::Debug for FourCC {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match std::str::from_utf8(&self.value) {
            Ok(s) => f.write_str(s),
            Err(_) => self.value.fmt(f),
        }
    }
}

impl fmt::Display for FourCC {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(std::str::from_utf8(&self.value).unwrap_or("null"))
    }
}

impl PartialEq<&[u8; 4]> for FourCC {
    fn eq(&self, other: &&[u8; 4]) -> bool {
        self.value.eq(*other)
    }
}

#[deny(unreachable_patterns)]
box_database!(
    FileTypeBox                       0x6674_7970, // "ftyp"
    MediaDataBox                      0x6d64_6174, // "mdat"
    PrimaryItemBox                    0x7069_746d, // "pitm"
    ItemInfoBox                       0x6969_6e66, // "iinf"
    ItemInfoEntry                     0x696e_6665, // "infe"
    ItemLocationBox                   0x696c_6f63, // "iloc"
    MovieBox                          0x6d6f_6f76, // "moov"
    MovieHeaderBox                    0x6d76_6864, // "mvhd"
    TrackBox                          0x7472_616b, // "trak"
    TrackHeaderBox                    0x746b_6864, // "tkhd"
    EditBox                           0x6564_7473, // "edts"
    MediaBox                          0x6d64_6961, // "mdia"
    EditListBox                       0x656c_7374, // "elst"
    MediaHeaderBox                    0x6d64_6864, // "mdhd"
    HandlerBox                        0x6864_6c72, // "hdlr"
    MediaInformationBox               0x6d69_6e66, // "minf"
    ImageReferenceBox                 0x6972_6566, // "iref"
    ImagePropertiesBox                0x6970_7270, // "iprp"
    ItemPropertyContainerBox          0x6970_636f, // "ipco"
    ItemPropertyAssociationBox        0x6970_6d61, // "ipma"
    ColorInformationBox               0x636f_6c72, // "colr"
    PixelInformationBox               0x7069_7869, // "pixi"
    AuxiliaryTypeProperty             0x6175_7843, // "auxC"
    SampleTableBox                    0x7374_626c, // "stbl"
    SampleDescriptionBox              0x7374_7364, // "stsd"
    TimeToSampleBox                   0x7374_7473, // "stts"
    SampleToChunkBox                  0x7374_7363, // "stsc"
    SampleSizeBox                     0x7374_737a, // "stsz"
    ChunkOffsetBox                    0x7374_636f, // "stco"
    ChunkLargeOffsetBox               0x636f_3634, // "co64"
    SyncSampleBox                     0x7374_7373, // "stss"
    AVCSampleEntry                    0x6176_6331, // "avc1"
    AVC3SampleEntry                   0x6176_6333, // "avc3" - Need to check official name in spec.
    AVCConfigurationBox               0x6176_6343, // "avcC"
    H263SampleEntry                   0x7332_3633, // "s263"
    H263SpecificBox                   0x6432_3633, // "d263"
    MP4AudioSampleEntry               0x6d70_3461, // "mp4a"
    MP4VideoSampleEntry               0x6d70_3476, // "mp4v"
    ESDBox                            0x6573_6473, // "esds"
    VP8SampleEntry                    0x7670_3038, // "vp08"
    VP9SampleEntry                    0x7670_3039, // "vp09"
    VPCodecConfigurationBox           0x7670_6343, // "vpcC"
    AV1SampleEntry                    0x6176_3031, // "av01"
    AV1CodecConfigurationBox          0x6176_3143, // "av1C"
    FLACSampleEntry                   0x664c_6143, // "fLaC"
    FLACSpecificBox                   0x6466_4c61, // "dfLa"
    OpusSampleEntry                   0x4f70_7573, // "Opus"
    OpusSpecificBox                   0x644f_7073, // "dOps"
    ProtectedVisualSampleEntry        0x656e_6376, // "encv" - Need to check official name in spec.
    ProtectedAudioSampleEntry         0x656e_6361, // "enca" - Need to check official name in spec.
    MovieExtendsBox                   0x6d76_6578, // "mvex"
    MovieExtendsHeaderBox             0x6d65_6864, // "mehd"
    QTWaveAtom                        0x7761_7665, // "wave" - quicktime atom
    ProtectionSystemSpecificHeaderBox 0x7073_7368, // "pssh"
    SchemeInformationBox              0x7363_6869, // "schi"
    TrackEncryptionBox                0x7465_6e63, // "tenc"
    ProtectionSchemeInfoBox           0x7369_6e66, // "sinf"
    OriginalFormatBox                 0x6672_6d61, // "frma"
    SchemeTypeBox                     0x7363_686d, // "schm"
    MP3AudioSampleEntry               0x2e6d_7033, // ".mp3" - from F4V.
    CompositionOffsetBox              0x6374_7473, // "ctts"
    LPCMAudioSampleEntry              0x6c70_636d, // "lpcm" - quicktime atom
    ALACSpecificBox                   0x616c_6163, // "alac" - Also used by ALACSampleEntry
    UuidBox                           0x7575_6964, // "uuid"
    MetadataBox                       0x6d65_7461, // "meta"
    MetadataHeaderBox                 0x6d68_6472, // "mhdr"
    MetadataItemKeysBox               0x6b65_7973, // "keys"
    MetadataItemListEntry             0x696c_7374, // "ilst"
    MetadataItemDataEntry             0x6461_7461, // "data"
    MetadataItemNameBox               0x6e61_6d65, // "name"
    UserdataBox                       0x7564_7461, // "udta"
    AlbumEntry                        0xa961_6c62, // "©alb"
    ArtistEntry                       0xa941_5254, // "©ART"
    ArtistLowercaseEntry              0xa961_7274, // "©art"
    AlbumArtistEntry                  0x6141_5254, // "aART"
    CommentEntry                      0xa963_6d74, // "©cmt"
    DateEntry                         0xa964_6179, // "©day"
    TitleEntry                        0xa96e_616d, // "©nam"
    CustomGenreEntry                  0xa967_656e, // "©gen"
    StandardGenreEntry                0x676e_7265, // "gnre"
    TrackNumberEntry                  0x7472_6b6e, // "trkn"
    DiskNumberEntry                   0x6469_736b, // "disk"
    ComposerEntry                     0xa977_7274, // "©wrt"
    EncoderEntry                      0xa974_6f6f, // "©too"
    EncodedByEntry                    0xa965_6e63, // "©enc"
    TempoEntry                        0x746d_706f, // "tmpo"
    CopyrightEntry                    0x6370_7274, // "cprt"
    CompilationEntry                  0x6370_696c, // "cpil"
    CoverArtEntry                     0x636f_7672, // "covr"
    AdvisoryEntry                     0x7274_6e67, // "rtng"
    RatingEntry                       0x7261_7465, // "rate"
    GroupingEntry                     0xa967_7270, // "©grp"
    MediaTypeEntry                    0x7374_696b, // "stik"
    PodcastEntry                      0x7063_7374, // "pcst"
    CategoryEntry                     0x6361_7467, // "catg"
    KeywordEntry                      0x6b65_7977, // "keyw"
    PodcastUrlEntry                   0x7075_726c, // "purl"
    PodcastGuidEntry                  0x6567_6964, // "egid"
    DescriptionEntry                  0x6465_7363, // "desc"
    LongDescriptionEntry              0x6c64_6573, // "ldes"
    LyricsEntry                       0xa96c_7972, // "©lyr"
    TVNetworkNameEntry                0x7476_6e6e, // "tvnn"
    TVShowNameEntry                   0x7476_7368, // "tvsh"
    TVEpisodeNameEntry                0x7476_656e, // "tven"
    TVSeasonNumberEntry               0x7476_736e, // "tvsn"
    TVEpisodeNumberEntry              0x7476_6573, // "tves"
    PurchaseDateEntry                 0x7075_7264, // "purd"
    GaplessPlaybackEntry              0x7067_6170, // "pgap"
    OwnerEntry                        0x6f77_6e72, // "ownr"
    HDVideoEntry                      0x6864_7664, // "hdvd"
    SortNameEntry                     0x736f_6e6d, // "sonm"
    SortAlbumEntry                    0x736f_616c, // "soal"
    SortArtistEntry                   0x736f_6172, // "soar"
    SortAlbumArtistEntry              0x736f_6161, // "soaa"
    SortComposerEntry                 0x736f_636f, // "soco"
);
<|endoftext|>


<commit_before>// Purge all references to a crate from the database.
//
// Please be super sure you want to do this before running this.
//
// Usage:
//      cargo run --bin delete-crate crate-name

#![warn(clippy::all, rust_2018_idioms)]

use cargo_registry::{db, models::Crate, schema::crates};
use std::{
    env,
    io::{self, prelude::*},
};

use diesel::prelude::*;

fn main() {
    let conn = db::connect_now().unwrap();
    conn.transaction::<_, diesel::result::Error, _>(|| {
        delete(&conn);
        Ok(())
    })
    .unwrap()
}

fn delete(conn: &PgConnection) {
    let name = match env::args().nth(1) {
        None => {
            println!("needs a crate-name argument");
            return;
        }
        Some(s) => s,
    };

    let krate: Crate = Crate::by_name(&name).first(conn).unwrap();
    print!(
        "Are you sure you want to delete {} ({}) [y/N]: ",
        name, krate.id
    );
    io::stdout().flush().unwrap();
    let mut line = String::new();
    io::stdin().read_line(&mut line).unwrap();
    if !line.starts_with('y') {
        return;
    }

    println!("deleting the crate");
    let n = diesel::delete(crates::table.find(krate.id))
        .execute(conn)
        .unwrap();
    println!("  {} deleted", n);

    print!("commit? [y/N]: ");
    io::stdout().flush().unwrap();
    let mut line = String::new();
    io::stdin().read_line(&mut line).unwrap();
    if !line.starts_with('y') {
        panic!("aborting transaction");
    }
}
<commit_msg>bin/delete-crate: Use `clap` for CLI argument parsing<commit_after>#![warn(clippy::all, rust_2018_idioms)]

use cargo_registry::{db, models::Crate, schema::crates};
use std::io::{self, prelude::*};

use clap::Clap;
use diesel::prelude::*;

#[derive(Clap, Debug)]
#[clap(
    name = "delete-crate",
    about = "Purge all references to a crate from the database.\n\nPlease be super sure you want to do this before running this."
)]
struct Opts {
    /// Name of the crate
    crate_name: String,
}

fn main() {
    let conn = db::connect_now().unwrap();
    conn.transaction::<_, diesel::result::Error, _>(|| {
        delete(&conn);
        Ok(())
    })
    .unwrap()
}

fn delete(conn: &PgConnection) {
    let opts: Opts = Opts::parse();

    let krate: Crate = Crate::by_name(&opts.crate_name).first(conn).unwrap();
    print!(
        "Are you sure you want to delete {} ({}) [y/N]: ",
        opts.crate_name, krate.id
    );
    io::stdout().flush().unwrap();
    let mut line = String::new();
    io::stdin().read_line(&mut line).unwrap();
    if !line.starts_with('y') {
        return;
    }

    println!("deleting the crate");
    let n = diesel::delete(crates::table.find(krate.id))
        .execute(conn)
        .unwrap();
    println!("  {} deleted", n);

    print!("commit? [y/N]: ");
    io::stdout().flush().unwrap();
    let mut line = String::new();
    io::stdin().read_line(&mut line).unwrap();
    if !line.starts_with('y') {
        panic!("aborting transaction");
    }
}
<|endoftext|>


<commit_before>// vim: tw=80
use super::*;

use quote::ToTokens;

use crate::{
    mock_function::MockFunction,
    mock_trait::MockTrait
};

fn phantom_default_inits(generics: &Generics) -> Vec<TokenStream> {
    generics.params
    .iter()
    .enumerate()
    .map(|(count, _param)| {
        let phident = format_ident!("_t{}", count);
        quote!(#phident: ::std::marker::PhantomData)
    }).collect()
}

/// Generate any PhantomData field definitions
fn phantom_fields(generics: &Generics) -> Vec<TokenStream> {
    generics.params
    .iter()
    .enumerate()
    .filter_map(|(count, param)| {
        let phident = format_ident!("_t{}", count);
        match param {
            syn::GenericParam::Lifetime(l) => {
                if !l.bounds.is_empty() {
                    compile_error(l.bounds.span(),
                        "#automock does not yet support lifetime bounds on structs");
                }
                let lifetime = &l.lifetime;
                Some(
                quote!(#phident: ::std::marker::PhantomData<&#lifetime ()>)
                )
            },
            syn::GenericParam::Type(tp) => {
                let ty = &tp.ident;
                Some(
                quote!(#phident: ::std::marker::PhantomData<#ty>)
                )
            },
            syn::GenericParam::Const(_) => {
                compile_error(param.span(),
                    "#automock does not yet support generic constants");
                None
            }
        }
    }).collect()
}

/// A collection of methods defined in one spot
struct Methods(Vec<MockFunction>);

impl Methods {
    fn calls(&self, modname: Option<&Ident>) -> Vec<impl ToTokens> {
        self.0.iter()
            .map(|meth| meth.call(modname))
            .collect::<Vec<_>>()
    }

    fn checkpoints(&self) -> Vec<impl ToTokens> {
        self.0.iter()
            .filter(|meth| !meth.is_static())
            .map(|meth| meth.checkpoint())
            .collect::<Vec<_>>()
    }

    fn contexts(&self, modname: Option<&Ident>) -> Vec<impl ToTokens> {
        self.0.iter()
            .map(|meth| if !meth.is_static() {
                // Only static methods have context methods, but we need
                // something here so contexts will have the same length as
                // calls.
                // TODO: after merging the 2020_refactor branch, eliminate
                // this hack by de-interleaving the calls, contexts, and
                // expects methods.
                Box::new(TokenStream::new()) as Box<dyn ToTokens>
            } else {
                Box::new(meth.context_fn(modname)) as Box<dyn ToTokens>
            }).collect::<Vec<_>>()
    }

    /// Return a fragment of code to initialize struct fields during default()
    fn default_inits(&self) -> Vec<TokenStream> {
        self.0.iter()
            .filter(|meth| !meth.is_static())
            .map(|meth| {
                let name = meth.name();
                let attrs = meth.format_attrs(false);
                quote!(#attrs #name: Default::default())
            }).collect::<Vec<_>>()
    }

    fn field_definitions(&self, modname: &Ident) -> Vec<TokenStream> {
        self.0.iter()
            .filter(|meth| !meth.is_static())
            .map(|meth| meth.field_definition(Some(modname)))
            .collect::<Vec<_>>()
    }

    fn expects(&self, modname: &Ident) -> Vec<impl ToTokens> {
        self.0.iter()
            .map(|meth| if meth.is_static() {
                // static methods' expect methods are generated by the
                // Context objects, but we still need something here so
                // expects will have the same length as calls.
                // TODO: after merging the 2020_refactor branch, eliminate
                // this hack by de-interleaving the calls and expects
                // methods.
                Box::new(TokenStream::new()) as Box<dyn ToTokens>
            } else {
                Box::new(meth.expect(&modname)) as Box<dyn ToTokens>
            }).collect::<Vec<_>>()
    }

    fn priv_mods(&self) -> Vec<impl ToTokens> {
        self.0.iter()
            .map(|meth| meth.priv_module())
            .collect::<Vec<_>>()
    }
}

pub(crate) struct MockItemStruct {
    attrs: Vec<Attribute>,
    generics: Generics,
    /// Does the original struct have a `new` method?
    has_new: bool,
    /// Inherent methods of the mock struct
    methods: Methods,
    /// Name of the overall module that holds all of the mock stuff
    // TODO: base this on name so we can get rid of MockableStruct.original_name
    modname: Ident,
    name: Ident,
    /// Is this a whole MockStruct or just a substructure for a trait impl?
    traits: Vec<MockTrait>,
    vis: Visibility,
}

impl MockItemStruct {
    fn new_method(&self) -> impl ToTokens {
        if self.has_new {
            TokenStream::new()
        } else {
            quote!(
                /// Create a new mock object with no expectations.
                ///
                /// This method will not be generated if the real struct
                /// already has a `new` method.  However, it *will* be
                /// generated if the struct implements a trait with a `new`
                /// method.  The trait's `new` method can still be called
                /// like `<MockX as TraitY>::new`
                pub fn new() -> Self {
                    Self::default()
                }
            )
        }
    }

    fn phantom_default_inits(&self) -> Vec<TokenStream> {
        phantom_default_inits(&self.generics)
    }

    fn phantom_fields(&self) -> Vec<TokenStream> {
        phantom_fields(&self.generics)
    }
}

impl From<MockableStruct> for MockItemStruct {
    fn from(mockable: MockableStruct) -> MockItemStruct {
        let mock_ident = gen_mod_ident(&mockable.name, None);
        let modname = gen_mod_ident(&mockable.original_name, None);
        let generics = mockable.generics.clone();
        let struct_name = &mockable.name;
        let vis = mockable.vis;
        let has_new = mockable.methods.iter()
            .any(|meth| meth.sig.ident == "new") ||
            mockable.traits.iter()
            .any(|trait_|
                trait_.items.iter()
                    .any(|ti| if let TraitItem::Method(tim) = ti {
                            tim.sig.ident == "new"
                        } else {
                            false
                        }
                    )
            );
        let methods = Methods(mockable.methods.into_iter()
            .map(|meth|
                mock_function::Builder::new(&meth.sig, &meth.vis)
                    .attrs(&meth.attrs)
                    .parent(&mock_ident)
                    .struct_(&struct_name)
                    .struct_generics(&generics)
                    .levels(2)
                    .call_levels(0)
                    .build()
            ).collect::<Vec<_>>());
        let structname = &mockable.name;
        let traits = mockable.traits.into_iter()
            .map(|t| MockTrait::new(structname, &generics, t, &vis))
            .collect();

        MockItemStruct {
            attrs: mockable.attrs,
            generics,
            has_new,
            methods,
            modname,
            name: mockable.name,
            traits,
            vis
        }
    }
}

impl ToTokens for MockItemStruct {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let attrs = &self.attrs;
        let struct_name = &self.name;
        let (ig, tg, wc) = self.generics.split_for_impl();
        let modname = &self.modname;
        let calls = self.methods.calls(Some(modname));
        let method_checkpoints = self.methods.checkpoints();
        let contexts = self.methods.contexts(Some(&modname));
        let expects = self.methods.expects(&modname);
        let new_method = self.new_method();
        let priv_mods = self.methods.priv_mods();
        let substructs = self.traits.iter()
            .map(|trait_| {
                MockItemTraitImpl {
                    attrs: trait_.attrs.clone(),
                    generics: self.generics.clone(),
                    fieldname: format_ident!("{}_expectations", trait_.name()),
                    methods: Methods(trait_.methods.clone()),
                    modname: format_ident!("{}_{}", &self.modname, trait_.name()),
                    name: format_ident!("{}_{}", &self.name, trait_.name()),
                }
            }).collect::<Vec<_>>();
        let substruct_expectations = self.traits.iter()
            .map(|trait_| format_ident!("{}_expectations", trait_.name()))
            .collect::<Vec<_>>();
        let mut field_definitions = substructs.iter()
            .map(|ss| {
                let fieldname = &ss.fieldname;
                let tyname = &ss.name;
                quote!(#fieldname: #tyname #tg)
            }).collect::<Vec<_>>();
        field_definitions.extend(self.methods.field_definitions(&modname));
        field_definitions.extend(self.phantom_fields());
        let mut default_inits = substructs.iter()
            .map(|ss| {
                let fieldname = &ss.fieldname;
                quote!(#fieldname: Default::default())
            }).collect::<Vec<_>>();
        default_inits.extend(self.methods.default_inits());
        default_inits.extend(self.phantom_default_inits());
        let trait_impls = self.traits.iter()
            .map(|ss| {
                let modname = format_ident!("{}_{}", &self.modname, ss.name());
                ss.trait_impl(&modname)
            }).collect::<Vec<_>>();
        let vis = &self.vis;
        quote!(
            #[allow(non_snake_case)]
            #[allow(missing_docs)]
            pub mod #modname {
                use super::*;
                #(#priv_mods)*
            }
            #[allow(non_camel_case_types)]
            #[allow(non_snake_case)]
            #[allow(missing_docs)]
            #(#attrs)*
            #vis struct #struct_name #ig #wc
            {
                #(#field_definitions),*
            }
            impl #ig ::std::default::Default for #struct_name #tg #wc {
                fn default() -> Self {
                    Self {
                        #(#default_inits),*
                    }
                }
            }
            #(#substructs)*
            impl #ig #struct_name #tg #wc {
                #(#calls #contexts #expects)*
                /// Validate that all current expectations for all methods have
                /// been satisfied, and discard them.
                pub fn checkpoint(&mut self) {
                    #(self.#substruct_expectations.checkpoint();)*
                    #(#method_checkpoints)*
                }
                #new_method
            }
            #(#trait_impls)*
        ).to_tokens(tokens);
    }
}

pub(crate) struct MockItemTraitImpl {
    attrs: Vec<Attribute>,
    generics: Generics,
    /// Inherent methods of the mock struct
    methods: Methods,
    /// Name of the overall module that holds all of the mock stuff
    // TODO: base this on name so we can get rid of MockableStruct.original_name
    modname: Ident,
    name: Ident,
    /// Name of the field of this type in the parent's structure
    fieldname: Ident,
}

impl MockItemTraitImpl {
    fn phantom_default_inits(&self) -> Vec<TokenStream> {
        phantom_default_inits(&self.generics)
    }

    fn phantom_fields(&self) -> Vec<TokenStream> {
        phantom_fields(&self.generics)
    }
}

impl ToTokens for MockItemTraitImpl {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let attrs_nodocs = format_attrs(&self.attrs, false);
        let struct_name = &self.name;
        let (ig, tg, wc) = self.generics.split_for_impl(); //TODO
        let modname = &self.modname;
        let method_checkpoints = self.methods.checkpoints();
        let mut default_inits = self.methods.default_inits();
        default_inits.extend(self.phantom_default_inits());
        let mut field_definitions = self.methods.field_definitions(&modname);
        field_definitions.extend(self.phantom_fields());
        let priv_mods = self.methods.priv_mods();
        quote!(
            #[allow(non_snake_case)]
            #[allow(missing_docs)]
            pub mod #modname {
                use super::*;
                #(#priv_mods)*
            }
            #[allow(non_camel_case_types)]
            #[allow(non_snake_case)]
            #[allow(missing_docs)]
            #attrs_nodocs
            struct #struct_name #ig #wc
            {
                #(#field_definitions),*
            }
            impl #ig ::std::default::Default for #struct_name #tg #wc {
                fn default() -> Self {
                    Self {
                        #(#default_inits),*
                    }
                }
            }
            impl #ig #struct_name #tg #wc {
                /// Validate that all current expectations for all methods have
                /// been satisfied, and discard them.
                pub fn checkpoint(&mut self) {
                    #(#method_checkpoints)*
                }
            }
        ).to_tokens(tokens);
    }
}
<commit_msg>Delete obsolete comment<commit_after>// vim: tw=80
use super::*;

use quote::ToTokens;

use crate::{
    mock_function::MockFunction,
    mock_trait::MockTrait
};

fn phantom_default_inits(generics: &Generics) -> Vec<TokenStream> {
    generics.params
    .iter()
    .enumerate()
    .map(|(count, _param)| {
        let phident = format_ident!("_t{}", count);
        quote!(#phident: ::std::marker::PhantomData)
    }).collect()
}

/// Generate any PhantomData field definitions
fn phantom_fields(generics: &Generics) -> Vec<TokenStream> {
    generics.params
    .iter()
    .enumerate()
    .filter_map(|(count, param)| {
        let phident = format_ident!("_t{}", count);
        match param {
            syn::GenericParam::Lifetime(l) => {
                if !l.bounds.is_empty() {
                    compile_error(l.bounds.span(),
                        "#automock does not yet support lifetime bounds on structs");
                }
                let lifetime = &l.lifetime;
                Some(
                quote!(#phident: ::std::marker::PhantomData<&#lifetime ()>)
                )
            },
            syn::GenericParam::Type(tp) => {
                let ty = &tp.ident;
                Some(
                quote!(#phident: ::std::marker::PhantomData<#ty>)
                )
            },
            syn::GenericParam::Const(_) => {
                compile_error(param.span(),
                    "#automock does not yet support generic constants");
                None
            }
        }
    }).collect()
}

/// A collection of methods defined in one spot
struct Methods(Vec<MockFunction>);

impl Methods {
    fn calls(&self, modname: Option<&Ident>) -> Vec<impl ToTokens> {
        self.0.iter()
            .map(|meth| meth.call(modname))
            .collect::<Vec<_>>()
    }

    fn checkpoints(&self) -> Vec<impl ToTokens> {
        self.0.iter()
            .filter(|meth| !meth.is_static())
            .map(|meth| meth.checkpoint())
            .collect::<Vec<_>>()
    }

    fn contexts(&self, modname: Option<&Ident>) -> Vec<impl ToTokens> {
        self.0.iter()
            .map(|meth| if !meth.is_static() {
                // Only static methods have context methods, but we need
                // something here so contexts will have the same length as
                // calls.
                // TODO: after merging the 2020_refactor branch, eliminate
                // this hack by de-interleaving the calls, contexts, and
                // expects methods.
                Box::new(TokenStream::new()) as Box<dyn ToTokens>
            } else {
                Box::new(meth.context_fn(modname)) as Box<dyn ToTokens>
            }).collect::<Vec<_>>()
    }

    /// Return a fragment of code to initialize struct fields during default()
    fn default_inits(&self) -> Vec<TokenStream> {
        self.0.iter()
            .filter(|meth| !meth.is_static())
            .map(|meth| {
                let name = meth.name();
                let attrs = meth.format_attrs(false);
                quote!(#attrs #name: Default::default())
            }).collect::<Vec<_>>()
    }

    fn field_definitions(&self, modname: &Ident) -> Vec<TokenStream> {
        self.0.iter()
            .filter(|meth| !meth.is_static())
            .map(|meth| meth.field_definition(Some(modname)))
            .collect::<Vec<_>>()
    }

    fn expects(&self, modname: &Ident) -> Vec<impl ToTokens> {
        self.0.iter()
            .map(|meth| if meth.is_static() {
                // static methods' expect methods are generated by the
                // Context objects, but we still need something here so
                // expects will have the same length as calls.
                // TODO: after merging the 2020_refactor branch, eliminate
                // this hack by de-interleaving the calls and expects
                // methods.
                Box::new(TokenStream::new()) as Box<dyn ToTokens>
            } else {
                Box::new(meth.expect(&modname)) as Box<dyn ToTokens>
            }).collect::<Vec<_>>()
    }

    fn priv_mods(&self) -> Vec<impl ToTokens> {
        self.0.iter()
            .map(|meth| meth.priv_module())
            .collect::<Vec<_>>()
    }
}

pub(crate) struct MockItemStruct {
    attrs: Vec<Attribute>,
    generics: Generics,
    /// Does the original struct have a `new` method?
    has_new: bool,
    /// Inherent methods of the mock struct
    methods: Methods,
    /// Name of the overall module that holds all of the mock stuff
    // TODO: base this on name so we can get rid of MockableStruct.original_name
    modname: Ident,
    name: Ident,
    /// Is this a whole MockStruct or just a substructure for a trait impl?
    traits: Vec<MockTrait>,
    vis: Visibility,
}

impl MockItemStruct {
    fn new_method(&self) -> impl ToTokens {
        if self.has_new {
            TokenStream::new()
        } else {
            quote!(
                /// Create a new mock object with no expectations.
                ///
                /// This method will not be generated if the real struct
                /// already has a `new` method.  However, it *will* be
                /// generated if the struct implements a trait with a `new`
                /// method.  The trait's `new` method can still be called
                /// like `<MockX as TraitY>::new`
                pub fn new() -> Self {
                    Self::default()
                }
            )
        }
    }

    fn phantom_default_inits(&self) -> Vec<TokenStream> {
        phantom_default_inits(&self.generics)
    }

    fn phantom_fields(&self) -> Vec<TokenStream> {
        phantom_fields(&self.generics)
    }
}

impl From<MockableStruct> for MockItemStruct {
    fn from(mockable: MockableStruct) -> MockItemStruct {
        let mock_ident = gen_mod_ident(&mockable.name, None);
        let modname = gen_mod_ident(&mockable.original_name, None);
        let generics = mockable.generics.clone();
        let struct_name = &mockable.name;
        let vis = mockable.vis;
        let has_new = mockable.methods.iter()
            .any(|meth| meth.sig.ident == "new") ||
            mockable.traits.iter()
            .any(|trait_|
                trait_.items.iter()
                    .any(|ti| if let TraitItem::Method(tim) = ti {
                            tim.sig.ident == "new"
                        } else {
                            false
                        }
                    )
            );
        let methods = Methods(mockable.methods.into_iter()
            .map(|meth|
                mock_function::Builder::new(&meth.sig, &meth.vis)
                    .attrs(&meth.attrs)
                    .parent(&mock_ident)
                    .struct_(&struct_name)
                    .struct_generics(&generics)
                    .levels(2)
                    .call_levels(0)
                    .build()
            ).collect::<Vec<_>>());
        let structname = &mockable.name;
        let traits = mockable.traits.into_iter()
            .map(|t| MockTrait::new(structname, &generics, t, &vis))
            .collect();

        MockItemStruct {
            attrs: mockable.attrs,
            generics,
            has_new,
            methods,
            modname,
            name: mockable.name,
            traits,
            vis
        }
    }
}

impl ToTokens for MockItemStruct {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let attrs = &self.attrs;
        let struct_name = &self.name;
        let (ig, tg, wc) = self.generics.split_for_impl();
        let modname = &self.modname;
        let calls = self.methods.calls(Some(modname));
        let method_checkpoints = self.methods.checkpoints();
        let contexts = self.methods.contexts(Some(&modname));
        let expects = self.methods.expects(&modname);
        let new_method = self.new_method();
        let priv_mods = self.methods.priv_mods();
        let substructs = self.traits.iter()
            .map(|trait_| {
                MockItemTraitImpl {
                    attrs: trait_.attrs.clone(),
                    generics: self.generics.clone(),
                    fieldname: format_ident!("{}_expectations", trait_.name()),
                    methods: Methods(trait_.methods.clone()),
                    modname: format_ident!("{}_{}", &self.modname, trait_.name()),
                    name: format_ident!("{}_{}", &self.name, trait_.name()),
                }
            }).collect::<Vec<_>>();
        let substruct_expectations = self.traits.iter()
            .map(|trait_| format_ident!("{}_expectations", trait_.name()))
            .collect::<Vec<_>>();
        let mut field_definitions = substructs.iter()
            .map(|ss| {
                let fieldname = &ss.fieldname;
                let tyname = &ss.name;
                quote!(#fieldname: #tyname #tg)
            }).collect::<Vec<_>>();
        field_definitions.extend(self.methods.field_definitions(&modname));
        field_definitions.extend(self.phantom_fields());
        let mut default_inits = substructs.iter()
            .map(|ss| {
                let fieldname = &ss.fieldname;
                quote!(#fieldname: Default::default())
            }).collect::<Vec<_>>();
        default_inits.extend(self.methods.default_inits());
        default_inits.extend(self.phantom_default_inits());
        let trait_impls = self.traits.iter()
            .map(|ss| {
                let modname = format_ident!("{}_{}", &self.modname, ss.name());
                ss.trait_impl(&modname)
            }).collect::<Vec<_>>();
        let vis = &self.vis;
        quote!(
            #[allow(non_snake_case)]
            #[allow(missing_docs)]
            pub mod #modname {
                use super::*;
                #(#priv_mods)*
            }
            #[allow(non_camel_case_types)]
            #[allow(non_snake_case)]
            #[allow(missing_docs)]
            #(#attrs)*
            #vis struct #struct_name #ig #wc
            {
                #(#field_definitions),*
            }
            impl #ig ::std::default::Default for #struct_name #tg #wc {
                fn default() -> Self {
                    Self {
                        #(#default_inits),*
                    }
                }
            }
            #(#substructs)*
            impl #ig #struct_name #tg #wc {
                #(#calls #contexts #expects)*
                /// Validate that all current expectations for all methods have
                /// been satisfied, and discard them.
                pub fn checkpoint(&mut self) {
                    #(self.#substruct_expectations.checkpoint();)*
                    #(#method_checkpoints)*
                }
                #new_method
            }
            #(#trait_impls)*
        ).to_tokens(tokens);
    }
}

pub(crate) struct MockItemTraitImpl {
    attrs: Vec<Attribute>,
    generics: Generics,
    /// Inherent methods of the mock struct
    methods: Methods,
    /// Name of the overall module that holds all of the mock stuff
    // TODO: base this on name so we can get rid of MockableStruct.original_name
    modname: Ident,
    name: Ident,
    /// Name of the field of this type in the parent's structure
    fieldname: Ident,
}

impl MockItemTraitImpl {
    fn phantom_default_inits(&self) -> Vec<TokenStream> {
        phantom_default_inits(&self.generics)
    }

    fn phantom_fields(&self) -> Vec<TokenStream> {
        phantom_fields(&self.generics)
    }
}

impl ToTokens for MockItemTraitImpl {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let attrs_nodocs = format_attrs(&self.attrs, false);
        let struct_name = &self.name;
        let (ig, tg, wc) = self.generics.split_for_impl();
        let modname = &self.modname;
        let method_checkpoints = self.methods.checkpoints();
        let mut default_inits = self.methods.default_inits();
        default_inits.extend(self.phantom_default_inits());
        let mut field_definitions = self.methods.field_definitions(&modname);
        field_definitions.extend(self.phantom_fields());
        let priv_mods = self.methods.priv_mods();
        quote!(
            #[allow(non_snake_case)]
            #[allow(missing_docs)]
            pub mod #modname {
                use super::*;
                #(#priv_mods)*
            }
            #[allow(non_camel_case_types)]
            #[allow(non_snake_case)]
            #[allow(missing_docs)]
            #attrs_nodocs
            struct #struct_name #ig #wc
            {
                #(#field_definitions),*
            }
            impl #ig ::std::default::Default for #struct_name #tg #wc {
                fn default() -> Self {
                    Self {
                        #(#default_inits),*
                    }
                }
            }
            impl #ig #struct_name #tg #wc {
                /// Validate that all current expectations for all methods have
                /// been satisfied, and discard them.
                pub fn checkpoint(&mut self) {
                    #(#method_checkpoints)*
                }
            }
        ).to_tokens(tokens);
    }
}
<|endoftext|>


<commit_before>use crate::config::SslMode;
use crate::tls::TlsConnect;
use crate::{connect_tls, Error};
use futures::future;
use postgres_protocol::message::frontend;
use std::pin::Pin;
use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt};

pub async fn cancel_query_raw<S, T>(
    stream: S,
    mode: SslMode,
    tls: T,
    process_id: i32,
    secret_key: i32,
) -> Result<(), Error>
where
    S: AsyncRead + AsyncWrite + Unpin,
    T: TlsConnect<S>,
{
    let (mut stream, _) = connect_tls::connect_tls(stream, mode, tls).await?;

    let mut buf = vec![];
    frontend::cancel_request(process_id, secret_key, &mut buf);

    stream.write_all(&buf).await.map_err(Error::io)?;
    stream.flush().await.map_err(Error::io)?;
    future::poll_fn(|cx| Pin::new(&mut stream).poll_shutdown(cx))
        .await
        .map_err(Error::io)?;

    Ok(())
}
<commit_msg>Cleanup shutdown call<commit_after>use crate::config::SslMode;
use crate::tls::TlsConnect;
use crate::{connect_tls, Error};
use postgres_protocol::message::frontend;
use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt};

pub async fn cancel_query_raw<S, T>(
    stream: S,
    mode: SslMode,
    tls: T,
    process_id: i32,
    secret_key: i32,
) -> Result<(), Error>
where
    S: AsyncRead + AsyncWrite + Unpin,
    T: TlsConnect<S>,
{
    let (mut stream, _) = connect_tls::connect_tls(stream, mode, tls).await?;

    let mut buf = vec![];
    frontend::cancel_request(process_id, secret_key, &mut buf);

    stream.write_all(&buf).await.map_err(Error::io)?;
    stream.flush().await.map_err(Error::io)?;
    stream.shutdown().await.map_err(Error::io)?;

    Ok(())
}
<|endoftext|>


<commit_before>use bluetooth_utils;
use dbus::MessageItem;
use hex::FromHex;
use std::collections::HashMap;
use std::error::Error;

static DEVICE_INTERFACE: &'static str = "org.bluez.Device1";

#[derive(Clone, Debug)]
pub struct BluetoothDevice {
    object_path: String,
}

impl BluetoothDevice {
    pub fn new(object_path: String)
           -> BluetoothDevice {
        BluetoothDevice {
            object_path: object_path
        }
    }

    pub fn get_id(&self) -> String {
        self.object_path.clone()
    }

    fn get_property(&self, prop: &str) -> Result<MessageItem, Box<Error>> {
        bluetooth_utils::get_property(DEVICE_INTERFACE, &self.object_path, prop)
    }

    fn set_property<T>(&self, prop: &str, value: T) -> Result<(), Box<Error>>
    where T: Into<MessageItem> {
        bluetooth_utils::set_property(DEVICE_INTERFACE, &self.object_path, prop, value)
    }

    fn call_method(&self, method: &str, param: Option<&[MessageItem]>) -> Result<(), Box<Error>> {
        bluetooth_utils::call_method(DEVICE_INTERFACE, &self.object_path, method, param)
    }

/*
 * Properties
 */
    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n105
    pub fn get_address(&self) -> Result<String, Box<Error>> {
        let address = try!(self.get_property("Address"));
        Ok(String::from(address.inner::<&str>().unwrap()))
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n109
    pub fn get_name(&self) -> Result<String, Box<Error>> {
        let name = try!(self.get_property("Name"));
        Ok(String::from(name.inner::<&str>().unwrap()))
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n121
    pub fn get_icon(&self) -> Result<String, Box<Error>> {
        let icon = try!(self.get_property("Icon"));
        Ok(String::from(icon.inner::<&str>().unwrap()))
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n126
    pub fn get_class(&self) -> Result<u32, Box<Error>> {
        let class = try!(self.get_property("Class"));
        Ok(class.inner::<u32>().unwrap())
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n126
    pub fn get_appearance(&self) -> Result<u16, Box<Error>> {
        let appearance = try!(self.get_property("Appearance"));
        Ok(appearance.inner::<u16>().unwrap())
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n134
    pub fn get_uuids(&self) -> Result<Vec<String>, Box<Error>> {
        let uuids = try!(self.get_property("UUIDs"));
        let z: &[MessageItem] = uuids.inner().unwrap();
        let mut v: Vec<String> = Vec::new();
        for y in z {
            v.push(String::from(y.inner::<&str>().unwrap()));
        }
        Ok(v)
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n139
    pub fn is_paired(&self) -> Result<bool, Box<Error>> {
         let paired = try!(self.get_property("Paired"));
         Ok(paired.inner::<bool>().unwrap())
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n143
    pub fn is_connected(&self) -> Result<bool, Box<Error>> {
         let connected = try!(self.get_property("Connected"));
         Ok(connected.inner::<bool>().unwrap())
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n149
    pub fn is_trusted(&self) -> Result<bool, Box<Error>> {
        let trusted = try!(self.get_property("Trusted"));
        Ok(trusted.inner::<bool>().unwrap())
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n154
    pub fn is_blocked(&self) -> Result<bool, Box<Error>> {
        let blocked = try!(self.get_property("Blocked"));
        Ok(blocked.inner::<bool>().unwrap())
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n161
    pub fn get_alias(&self) -> Result<String, Box<Error>> {
        let alias = try!(self.get_property("Alias"));
        Ok(String::from(alias.inner::<&str>().unwrap()))
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n161
    pub fn set_alias(&self, value: String) -> Result<(),Box<Error>> {
        self.set_property("Alias", value)
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n174
    pub fn get_adapter(&self) -> Result<String, Box<Error>> {
        let adapter = try!(self.get_property("Adapter"));
        Ok(String::from(adapter.inner::<&str>().unwrap()))
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n178
    pub fn is_legacy_pairing(&self) -> Result<bool, Box<Error>> {
        let legacy_pairing = try!(self.get_property("LegacyPairing"));
        Ok(legacy_pairing.inner::<bool>().unwrap())
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n189
    pub fn get_modalias(&self) ->  Result<(String, u32, u32, u32), Box<Error>> {
        let modalias = try!(self.get_property("Modalias"));
        let m = modalias.inner::<&str>().unwrap();
        let ids: Vec<&str> = m.split(":").collect();

        let source = String::from(ids[0]);
        let vendor = Vec::from_hex(ids[1][1..5].to_string()).unwrap();
        let product = Vec::from_hex(ids[1][6..10].to_string()).unwrap();
        let device = Vec::from_hex(ids[1][11..15].to_string()).unwrap();

        Ok((source,
        (vendor[0] as u32) * 16 * 16 + (vendor[1] as u32),
        (product[0] as u32) * 16 * 16 + (product[1] as u32),
        (device[0] as u32) * 16 * 16 + (device[1] as u32)))
    }

    pub fn get_vendor_id_source(&self) -> Result<String, Box<Error>> {
        let (vendor_id_source,_,_,_) = try!(self.get_modalias());
        Ok(vendor_id_source)
    }

    pub fn get_vendor_id(&self) -> Result<u32, Box<Error>> {
        let (_,vendor_id,_,_) = try!(self.get_modalias());
        Ok(vendor_id)
    }

    pub fn get_product_id(&self) -> Result<u32, Box<Error>> {
        let (_,_,product_id,_) = try!(self.get_modalias());
        Ok(product_id)
    }

    pub fn get_device_id(&self) -> Result<u32, Box<Error>> {
        let (_,_,_,device_id) = try!(self.get_modalias());
        Ok(device_id)
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n194
    pub fn get_rssi(&self) -> Result<i16, Box<Error>> {
        let rssi = try!(self.get_property("RSSI"));
        Ok(rssi.inner::<i16>().unwrap())
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n199
    pub fn get_tx_power(&self) -> Result<i16, Box<Error>> {
        let tx_power = try!(self.get_property("TxPower"));
        Ok(tx_power.inner::<i16>().unwrap())
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n204
    pub fn get_manufacturer_data(&self) -> Result<HashMap<u16, Vec<u8>>, Box<Error>> {
        let manufacturer_data_array = try!(self.get_property("ManufacturerData"));
        let mut m = HashMap::new();
        let dict_vec = manufacturer_data_array.inner::<&Vec<MessageItem>>().unwrap();
        for dict in dict_vec {
            let (key, value) = dict.inner::<(&MessageItem, &MessageItem)>().unwrap();
            let v = value.inner::<&MessageItem>().unwrap()
                         .inner::<&Vec<MessageItem>>().unwrap()
                         .into_iter()
                         .map(|b| b.inner::<u8>().unwrap_or(0))
                         .collect();
            m.insert(key.inner::<u16>().unwrap(), v);
        }
        Ok(m)
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n210
    pub fn get_service_data(&self) -> Result<HashMap<String, Vec<u8>>, Box<Error>> {
        let service_data_array = try!(self.get_property("ServiceData"));
        let mut m = HashMap::new();
        let dict_vec = service_data_array.inner::<&Vec<MessageItem>>().unwrap();
        for dict in dict_vec {
            let (key, value) = dict.inner::<(&MessageItem, &MessageItem)>().unwrap();
            let v = value.inner::<&MessageItem>().unwrap()
                         .inner::<&Vec<MessageItem>>().unwrap()
                         .into_iter()
                         .map(|b| b.inner::<u8>().unwrap_or(0))
                         .collect();
            m.insert(key.inner::<&str>().unwrap().to_string(), v);
        }
        Ok(m)
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n215
    pub fn get_gatt_services(&self) -> Result<Vec<String>, Box<Error>> {
        bluetooth_utils::list_services(&self.object_path)
    }

/*
 * Methods
 */

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n12
    pub fn connect(&self) -> Result<(), Box<Error>> {
        self.call_method("Connect", None)
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n29
    pub fn disconnect(&self) -> Result<(), Box<Error>>{
        self.call_method("Disconnect", None)
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n43
    pub fn connect_profile(&self, uuid: String) -> Result<(), Box<Error>>{
        self.call_method("ConnectProfile", Some(&[uuid.into()]))
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n55
    pub fn disconnect_profile(&self, uuid: String) -> Result<(), Box<Error>>{
        self.call_method("DisconnectProfile", Some(&[uuid.into()]))
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n70
    pub fn pair(&self) -> Result<(), Box<Error>>{
        self.call_method("Pair", None)
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n97
    pub fn cancel_pairing(&self) -> Result<(), Box<Error>>{
        self.call_method("CancelPairing", None)
    }
}
<commit_msg>added set_trusted method to BluetoothDevice<commit_after>use bluetooth_utils;
use dbus::MessageItem;
use hex::FromHex;
use std::collections::HashMap;
use std::error::Error;

static DEVICE_INTERFACE: &'static str = "org.bluez.Device1";

#[derive(Clone, Debug)]
pub struct BluetoothDevice {
    object_path: String,
}

impl BluetoothDevice {
    pub fn new(object_path: String)
           -> BluetoothDevice {
        BluetoothDevice {
            object_path: object_path
        }
    }

    pub fn get_id(&self) -> String {
        self.object_path.clone()
    }

    fn get_property(&self, prop: &str) -> Result<MessageItem, Box<Error>> {
        bluetooth_utils::get_property(DEVICE_INTERFACE, &self.object_path, prop)
    }

    fn set_property<T>(&self, prop: &str, value: T) -> Result<(), Box<Error>>
    where T: Into<MessageItem> {
        bluetooth_utils::set_property(DEVICE_INTERFACE, &self.object_path, prop, value)
    }

    fn call_method(&self, method: &str, param: Option<&[MessageItem]>) -> Result<(), Box<Error>> {
        bluetooth_utils::call_method(DEVICE_INTERFACE, &self.object_path, method, param)
    }

/*
 * Properties
 */
    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n105
    pub fn get_address(&self) -> Result<String, Box<Error>> {
        let address = try!(self.get_property("Address"));
        Ok(String::from(address.inner::<&str>().unwrap()))
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n109
    pub fn get_name(&self) -> Result<String, Box<Error>> {
        let name = try!(self.get_property("Name"));
        Ok(String::from(name.inner::<&str>().unwrap()))
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n121
    pub fn get_icon(&self) -> Result<String, Box<Error>> {
        let icon = try!(self.get_property("Icon"));
        Ok(String::from(icon.inner::<&str>().unwrap()))
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n126
    pub fn get_class(&self) -> Result<u32, Box<Error>> {
        let class = try!(self.get_property("Class"));
        Ok(class.inner::<u32>().unwrap())
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n126
    pub fn get_appearance(&self) -> Result<u16, Box<Error>> {
        let appearance = try!(self.get_property("Appearance"));
        Ok(appearance.inner::<u16>().unwrap())
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n134
    pub fn get_uuids(&self) -> Result<Vec<String>, Box<Error>> {
        let uuids = try!(self.get_property("UUIDs"));
        let z: &[MessageItem] = uuids.inner().unwrap();
        let mut v: Vec<String> = Vec::new();
        for y in z {
            v.push(String::from(y.inner::<&str>().unwrap()));
        }
        Ok(v)
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n139
    pub fn is_paired(&self) -> Result<bool, Box<Error>> {
         let paired = try!(self.get_property("Paired"));
         Ok(paired.inner::<bool>().unwrap())
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n143
    pub fn is_connected(&self) -> Result<bool, Box<Error>> {
         let connected = try!(self.get_property("Connected"));
         Ok(connected.inner::<bool>().unwrap())
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n149
    pub fn set_trusted(&self, value: bool) -> Result<(), Box<Error>> {
        self.set_property("Trusted", value)
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n149
    pub fn is_trusted(&self) -> Result<bool, Box<Error>> {
        let trusted = try!(self.get_property("Trusted"));
        Ok(trusted.inner::<bool>().unwrap())
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n154
    pub fn is_blocked(&self) -> Result<bool, Box<Error>> {
        let blocked = try!(self.get_property("Blocked"));
        Ok(blocked.inner::<bool>().unwrap())
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n161
    pub fn get_alias(&self) -> Result<String, Box<Error>> {
        let alias = try!(self.get_property("Alias"));
        Ok(String::from(alias.inner::<&str>().unwrap()))
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n161
    pub fn set_alias(&self, value: String) -> Result<(),Box<Error>> {
        self.set_property("Alias", value)
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n174
    pub fn get_adapter(&self) -> Result<String, Box<Error>> {
        let adapter = try!(self.get_property("Adapter"));
        Ok(String::from(adapter.inner::<&str>().unwrap()))
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n178
    pub fn is_legacy_pairing(&self) -> Result<bool, Box<Error>> {
        let legacy_pairing = try!(self.get_property("LegacyPairing"));
        Ok(legacy_pairing.inner::<bool>().unwrap())
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n189
    pub fn get_modalias(&self) ->  Result<(String, u32, u32, u32), Box<Error>> {
        let modalias = try!(self.get_property("Modalias"));
        let m = modalias.inner::<&str>().unwrap();
        let ids: Vec<&str> = m.split(":").collect();

        let source = String::from(ids[0]);
        let vendor = Vec::from_hex(ids[1][1..5].to_string()).unwrap();
        let product = Vec::from_hex(ids[1][6..10].to_string()).unwrap();
        let device = Vec::from_hex(ids[1][11..15].to_string()).unwrap();

        Ok((source,
        (vendor[0] as u32) * 16 * 16 + (vendor[1] as u32),
        (product[0] as u32) * 16 * 16 + (product[1] as u32),
        (device[0] as u32) * 16 * 16 + (device[1] as u32)))
    }

    pub fn get_vendor_id_source(&self) -> Result<String, Box<Error>> {
        let (vendor_id_source,_,_,_) = try!(self.get_modalias());
        Ok(vendor_id_source)
    }

    pub fn get_vendor_id(&self) -> Result<u32, Box<Error>> {
        let (_,vendor_id,_,_) = try!(self.get_modalias());
        Ok(vendor_id)
    }

    pub fn get_product_id(&self) -> Result<u32, Box<Error>> {
        let (_,_,product_id,_) = try!(self.get_modalias());
        Ok(product_id)
    }

    pub fn get_device_id(&self) -> Result<u32, Box<Error>> {
        let (_,_,_,device_id) = try!(self.get_modalias());
        Ok(device_id)
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n194
    pub fn get_rssi(&self) -> Result<i16, Box<Error>> {
        let rssi = try!(self.get_property("RSSI"));
        Ok(rssi.inner::<i16>().unwrap())
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n199
    pub fn get_tx_power(&self) -> Result<i16, Box<Error>> {
        let tx_power = try!(self.get_property("TxPower"));
        Ok(tx_power.inner::<i16>().unwrap())
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n204
    pub fn get_manufacturer_data(&self) -> Result<HashMap<u16, Vec<u8>>, Box<Error>> {
        let manufacturer_data_array = try!(self.get_property("ManufacturerData"));
        let mut m = HashMap::new();
        let dict_vec = manufacturer_data_array.inner::<&Vec<MessageItem>>().unwrap();
        for dict in dict_vec {
            let (key, value) = dict.inner::<(&MessageItem, &MessageItem)>().unwrap();
            let v = value.inner::<&MessageItem>().unwrap()
                         .inner::<&Vec<MessageItem>>().unwrap()
                         .into_iter()
                         .map(|b| b.inner::<u8>().unwrap_or(0))
                         .collect();
            m.insert(key.inner::<u16>().unwrap(), v);
        }
        Ok(m)
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n210
    pub fn get_service_data(&self) -> Result<HashMap<String, Vec<u8>>, Box<Error>> {
        let service_data_array = try!(self.get_property("ServiceData"));
        let mut m = HashMap::new();
        let dict_vec = service_data_array.inner::<&Vec<MessageItem>>().unwrap();
        for dict in dict_vec {
            let (key, value) = dict.inner::<(&MessageItem, &MessageItem)>().unwrap();
            let v = value.inner::<&MessageItem>().unwrap()
                         .inner::<&Vec<MessageItem>>().unwrap()
                         .into_iter()
                         .map(|b| b.inner::<u8>().unwrap_or(0))
                         .collect();
            m.insert(key.inner::<&str>().unwrap().to_string(), v);
        }
        Ok(m)
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n215
    pub fn get_gatt_services(&self) -> Result<Vec<String>, Box<Error>> {
        bluetooth_utils::list_services(&self.object_path)
    }

/*
 * Methods
 */

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n12
    pub fn connect(&self) -> Result<(), Box<Error>> {
        self.call_method("Connect", None)
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n29
    pub fn disconnect(&self) -> Result<(), Box<Error>>{
        self.call_method("Disconnect", None)
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n43
    pub fn connect_profile(&self, uuid: String) -> Result<(), Box<Error>>{
        self.call_method("ConnectProfile", Some(&[uuid.into()]))
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n55
    pub fn disconnect_profile(&self, uuid: String) -> Result<(), Box<Error>>{
        self.call_method("DisconnectProfile", Some(&[uuid.into()]))
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n70
    pub fn pair(&self) -> Result<(), Box<Error>>{
        self.call_method("Pair", None)
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n97
    pub fn cancel_pairing(&self) -> Result<(), Box<Error>>{
        self.call_method("CancelPairing", None)
    }
}
<|endoftext|>


<commit_before>use std::vec::Vec;
use std::io::IoError;
use serialize::Encodable;
use serialize::Decodable;
use std::io::{Acceptor, Listener, TcpListener, TcpStream, IoResult, BufferedReader};
use std::io::net::tcp::TcpAcceptor;
use std::io::net::ip::SocketAddr;
use std::comm::Select;
use collections::HashMap;
use sync::{RWLock, Arc};
use serialize::json::{Encoder,Error};

pub use self::peer::NetPeer;
use super::events::*;
use self::types::*;
pub mod peer;

// Private stuff, shouldn't be used elsewhere.
pub mod parsers;
mod types;

static CONNECT_TIMEOUT: u64 = 3000;

macro_rules! may_shutdown(
    ($p: ident) => {
        match $p.try_recv() {
            Ok(exitcode) => {
                break;
            }
            Err(_) => {},
        }
    }
)

// TODO: put entry functions in here, like:
// - start_peer_helper (which returns a Peer struct, including fields
// with channels to message with)
// TODO: Peer will contain identity info and channels for
// communicating with this peer task

/*
 * Contains all the information on what peers we have, and manages Schooner's interactions
 * with them.
 */
pub struct NetListener {
    // Maps peer IDs to their associated TCP streams.
    // Since these streams might fail, we need to reestablish them sometimes.
    peer_id_map: HashMap<uint, TcpStream>,
    // Peer configurations, stored in a concurrency construct.
    peer_configs: Vec<NetPeerConfig>,
}

impl NetListener {
    pub fn new() -> NetListener {
        NetListener {
            peer_id_map: HashMap::new(),
            peer_configs: Vec::new(),
        }
    }

    /*
     * Start the listener for this server. This needs to open a TCP listening port
     * at whatever its configured listening address is, and it needs to have a way
     * to send commands that it has received from peers back out to the main loop.
     *
     * conf: the config for this server
     * peer_configs: vector of configs for peers
     * from_peers_send: sends messages from peers back to the main loop.
     *
     */
    pub fn startup_peers(mut self, conf: NetPeerConfig, peer_configs: ~Vec<NetPeerConfig>, from_peers_send: Sender<RaftMsg>) {
        for conf in peer_configs.iter() {
            self.peer_configs.push(conf.clone());
        }
        let (peer_connect_send, peer_connect_recv) = channel();
        let (peer_shutdown_send, peer_shutdown_recv) = channel();
        NetListener::listen_peers(conf.address, peer_connect_send, peer_shutdown_recv);
        /*
        let selector = Select::new();
        for conf in peer_configs.iter() {
            let (send, recv) = channel();
            let netpeer = NetPeer::new(~conf.clone(), ~send);
            let mut peer_handle = selector.handle(&recv);
            unsafe { peer_handle.add(); }
            self.peer_select_map.insert(peer_handle.id(), netpeer.conf.id);
            self.peer_id_map.insert(conf.id, netpeer);
        }
        let listener = TcpListener::new();
        a.set_timeout(Some(100));
        match a.accept() {
            Ok(..) => println!("accepted a socket"),
            Err(ref e) if e.kind == TimedOut => { println!("timed out!"); }
            Err(e) => println!("err: {}", e),
        }
        */
    }

    fn listen_peers(addr: SocketAddr, peer_send: Sender<(uint, TcpStream)>, shutdown: Receiver<uint>) {
        spawn(proc() {
            let listener: TcpListener = TcpListener::bind(addr).unwrap();
            let mut acceptor: TcpAcceptor = listener.listen().unwrap();
            debug!("Started listening on {}", addr);
            loop {
                acceptor.set_timeout(Some(5000));
                for maybe_stream in acceptor.incoming() {
                    match maybe_stream {
                        Ok(stream) => {
                            let mut reader = ~BufferedReader::new(stream);
                            let line = reader.read_line();
                            let id: Option<uint> = line.ok().and_then(|l| from_str(l));
                            if id.is_some() {
                                debug!("Handshake with peer {} completed.", id.unwrap());
                                peer_send.send((id.unwrap(), reader.unwrap()));
                            }
                            else {
                                let mut stream = reader.unwrap();
                                debug!("Dropping peer at {} never got an id.", stream.peer_name());
                                drop(stream);
                            }
                        }
                        Err(e) => {
                            break;
                        }
                    }
                }
                may_shutdown!(shutdown);
            }
        });
    }

    fn try_connect(&mut self, peer_id: uint) -> Option<TcpStream> {
        let ref peer_configs = self.peer_configs;
        let mut peer: Option<&NetPeerConfig> = None;
        for conf in peer_configs.iter() {
            if conf.id == peer_id {
                peer = Some(conf);
            }
        }
        if peer.is_none() {
            return None;
        }
        match TcpStream::connect_timeout(peer.unwrap().address, CONNECT_TIMEOUT) {
            Ok(mut stream) => {
                stream.write_uint(peer.unwrap().id);
                stream.write_line("");
                Some(stream.clone())
            }
            err => {
                None
            }
        }
    }

    /*
     * Start the client listener.
     *
     * conf: the config for this server, containing *client* listen address.
     * from_clients_send: sends messages from peers back to the main loop.
     *
     */
    fn spawn_client_listener(& mut self, conf: NetPeerConfig, from_client_send: Sender<(ClientCmdReq, Sender<ClientCmdRes>)>) {
        // unwrapping because our server is dead in the water if it can't listen on its assigned port
        let listener: TcpListener = TcpListener::bind(conf.address).unwrap();
        let mut acceptor: TcpAcceptor = listener.listen().unwrap();
        for maybe_stream in acceptor.incoming() {
            match maybe_stream {
                Ok(stream) => {
                    // TODO
                }
                Err(e) => {
                    debug!("{}", e);
                    continue;
                }
            }
        }
    }

    /*
     * Get the configurations of the known peers for this network listener. Maybe
     * only used by the leader to get the potential peers that it can send messages
     * to. Probably should send even peers that NetListener thinks are down, since
     * in case they come back up the leader might like to send requests to them.
     */
    fn get_peer_ids(& self) -> Vec<uint> {
        /*
        let mut confs = Vec::new();
        for conf in self.peer_id_map.keys() {
            confs.push(conf.clone());
        }
        confs
         */
        Vec::new()
    }

    /*
     * Leader only
     */
    fn send_append_req(& mut self, peer: uint, cmd: AppendEntriesReq) -> Option<Receiver<AppendEntriesRes>> {
        // if we were able to send the data over the TCP connection, then we will send it
        // back out on the returned Receiver.
        /*
        let netpeer = self.peer_id_map.get(&peer);
        match netpeer.send(RpcARQ(cmd)) {
            Some(reschan) => {
                // TODO
                None
            }
            None => {
                None
            }
        }
         */
        None
    }

    fn send_vote_req(peer: NetPeerConfig, cmd: VoteReq) -> Option<Receiver<VoteRes>> {
        None
    }

}

#[cfg(test)]
mod test {
    use std::vec::Vec;
    use std::io::net::ip::{SocketAddr, Ipv4Addr};
    use std::io::net::tcp::TcpStream;
    use std::io::timer::sleep;
    use std::io::BufferedWriter;
    use std::container::MutableSet;
    use super::types::*;
    use super::NetListener;

    #[test]
    fn test_warmup() {
        let pc = NetPeerConfig {
            id: 1,
            address: SocketAddr {
                ip: Ipv4Addr(127, 0, 0, 1),
                port: 8844,
            },
            client_addr: SocketAddr {
                ip: Ipv4Addr(127, 0, 0, 1),
                port: 8840,
            },
        };
        let mut pc_vec = ~Vec::new();
        pc_vec.push(NetPeerConfig {
            id: 1,
            address: SocketAddr {
                ip: Ipv4Addr(127, 0, 0, 1),
                port: 8888,
            },
            client_addr: SocketAddr {
                ip: Ipv4Addr(127, 0, 0, 1),
                port: 8840,
            },
        });
        /*
        let mut nl = NetListener::new();
        let (from_peers_send, from_peers) = channel();
        nl.spawn_peer_listener(pc, pc_vec, from_peers_send);
        */
    }

    fn connect_handshake(id: uint, addr: SocketAddr) {
        match TcpStream::connect(addr) {
            Ok(mut stream) => {
                let mut writer = BufferedWriter::new(stream);
                writer.write_uint(id);
                drop(writer.unwrap());
            }
            Err(e) => {
                fail!("{}", e);
            }
        }
    }

    #[test]
    fn test_listen_peers() {
        let (peer_connect_send, peer_connect_recv) = channel();
        let (shutdown_send, shutdown_recv) = channel();
        let listen_addr = SocketAddr {
            ip: Ipv4Addr(127, 0, 0, 1),
            port: 9999,
        };
        NetListener::listen_peers(listen_addr, peer_connect_send, shutdown_recv);
        sleep(1000);
        connect_handshake(14, listen_addr);
        let (res_id, _) = peer_connect_recv.recv();
        assert_eq!(res_id, 14);
        connect_handshake(10, listen_addr);
        let (res_id, _) = peer_connect_recv.recv();
        assert_eq!(res_id, 10);
        connect_handshake(1, listen_addr);
        let (res_id, _) = peer_connect_recv.recv();
        assert_eq!(res_id, 1);
        shutdown_send.send(0);
    }
}
<commit_msg>consolidate startup logic<commit_after>use std::vec::Vec;
use std::io::IoError;
use serialize::Encodable;
use serialize::Decodable;
use std::io::{Acceptor, Listener, TcpListener, TcpStream, IoResult, BufferedReader};
use std::io::net::tcp::TcpAcceptor;
use std::io::net::ip::SocketAddr;
use std::comm::Select;
use collections::HashMap;
use sync::{RWLock, Arc};
use serialize::json::{Encoder,Error};

pub use self::peer::NetPeer;
use super::events::*;
use self::types::*;
pub mod peer;

// Private stuff, shouldn't be used elsewhere.
pub mod parsers;
mod types;

static CONNECT_TIMEOUT: u64 = 3000;

macro_rules! may_shutdown(
    ($p: ident) => {
        match $p.try_recv() {
            Ok(exitcode) => {
                debug!("Received shutdown signal {} on subsystem.", exitcode);
                break;
            }
            Err(_) => {},
        }
    };
    ($s: ident, $p: ident) => {
        match $s.$p.try_recv() {
            Ok(exitcode) => {
                debug!("Received shutdown signal {} on NetListener.", exitcode);
                for sender in $s.shutdown_senders.iter() {
                    sender.send(exitcode);
                }
                break;
            }
            Err(_) => {},
        }
    };
)

macro_rules! try_update (
    ($s: ident, $p: ident, $m: ident) => {
        match $s.$p.try_recv() {
            Ok((incoming_id, incoming_stream)) => {
                let has_stream: bool = $s.$m.get(&incoming_id).is_some();
                if !has_stream {
                    $s.$m.insert(incoming_id, Some(incoming_stream));
                }
            }
            Err(_) => {}
        }
    }
)

// TODO: put entry functions in here, like:
// - start_peer_helper (which returns a Peer struct, including fields
// with channels to message with)
// TODO: Peer will contain identity info and channels for
// communicating with this peer task

/*
 * Contains all the information on what peers we have, and manages Schooner's interactions
 * with them.
 */
pub struct NetListener {
    // config info for this peer
    conf: NetPeerConfig,
    // Maps peer IDs to their associated TCP streams.
    peer_id_map: HashMap<uint, Option<TcpStream>>,
    // Peer configurations, stored in a concurrency construct.
    peer_configs: ~Vec<NetPeerConfig>,
    // Sender we use to talk back up to Raft
    from_peers_send: Sender<RaftMsg>,
    // Receives peer connections as (id, stream) from listen_peers()
    peer_connect_recv: Receiver<(uint, TcpStream)>,
    // Signal from main raft process to do a shutdown.
    shutdown_signal: Receiver<uint>,
    // channels we send the shutdown signal to if we receive one
    shutdown_senders: Vec<Sender<uint>>,
}

impl NetListener {
    pub fn new(conf: NetPeerConfig,
               peer_configs: ~Vec<NetPeerConfig>,
               from_peers_send: Sender<RaftMsg>,
               from_client_send: Sender<(ClientCmdReq, Sender<ClientCmdRes>)>,
               shutdown_signal: Receiver<uint>
        ) -> NetListener {
        let (peer_connect_send, peer_connect_recv) = channel();
        let (peer_shutdown_send, peer_shutdown_recv) = channel();
        NetListener::listen_peers(conf.address, peer_connect_send, peer_shutdown_recv);
        let (peer_connect_send, peer_connect_recv) = channel();
        let (client_shutdown_send, client_shutdown_recv) = channel();
        NetListener::listen_clients(conf.client_addr, from_client_send, client_shutdown_recv);
        let mut this = NetListener {
            conf: conf,
            peer_id_map: HashMap::new(),
            peer_configs: peer_configs.clone(),
            from_peers_send: from_peers_send,
            peer_connect_recv: peer_connect_recv,
            shutdown_signal: shutdown_signal,
            shutdown_senders: Vec::new(),
        };
        this.shutdown_senders.push(peer_shutdown_send);
        this.shutdown_senders.push(client_shutdown_send);
        for conf in peer_configs.iter() {
            this.peer_id_map.insert(conf.id, None);
            try_update!(this, peer_connect_recv, peer_id_map);
        }
        this.connect_peers();
        this
    }

    /*
     * Get the configurations of the known peers for this network listener. Maybe
     * only used by the leader to get the potential peers that it can send messages
     * to. Probably should send even peers that NetListener thinks are down, since
     * in case they come back up the leader might like to send requests to them.
     */
    fn get_peer_ids(& self) -> Vec<uint> {
        /*
        let mut confs = Vec::new();
        for conf in self.peer_id_map.keys() {
            confs.push(conf.clone());
        }
        confs
         */
        Vec::new()
    }

    /*
     * Leader only
     */
    fn send_append_req(& mut self, peer: uint, cmd: AppendEntriesReq) -> Option<Receiver<AppendEntriesRes>> {
        // if we were able to send the data over the TCP connection, then we will send it
        // back out on the returned Receiver.
        /*
        let netpeer = self.peer_id_map.get(&peer);
        match netpeer.send(RpcARQ(cmd)) {
            Some(reschan) => {
                // TODO
                None
            }
            None => {
                None
            }
        }
         */
        None
    }

    fn send_vote_req(peer: NetPeerConfig, cmd: VoteReq) -> Option<Receiver<VoteRes>> {
        None
    }

    /*
     */
    fn connect_peers(&mut self) {
        let configs = self.peer_configs.clone();
        for conf in configs.iter() {
            let id = conf.id;
            may_shutdown!(self, shutdown_signal);
            try_update!(self, peer_connect_recv, peer_id_map);
            if self.peer_id_map.get(&id).is_none() {
                let mstream = self.try_connect(id);
                may_shutdown!(self, shutdown_signal);
                try_update!(self, peer_connect_recv, peer_id_map);
                match mstream {
                    Some(stream) => {
                        may_shutdown!(self, shutdown_signal);
                        try_update!(self, peer_connect_recv, peer_id_map);
                        if self.peer_id_map.get(&id).is_none() {
                            self.peer_id_map.insert(id, Some(stream));
                        }
                        else {
                            drop(stream);
                        }
                    }
                    None => {
                        debug!("Couldn't get a connection to id: {}", id);
                    }
                }
            }
        }
    }

    fn lookup_peer_config<'a>(&'a mut self, id: uint) -> Option<&'a NetPeerConfig> {
        let mut peer_config: Option<&NetPeerConfig> = None;
        for conf in self.peer_configs.iter() {
            if conf.id == id {
                peer_config = Some(conf);
            }
        }
        peer_config
    }

    fn listen_peers(addr: SocketAddr, peer_send: Sender<(uint, TcpStream)>, shutdown: Receiver<uint>) {
        spawn(proc() {
            let listener: TcpListener = TcpListener::bind(addr).unwrap();
            let mut acceptor: TcpAcceptor = listener.listen().unwrap();
            debug!("Started listening on {}", addr);
            loop {
                acceptor.set_timeout(Some(CONNECT_TIMEOUT));
                for maybe_stream in acceptor.incoming() {
                    match maybe_stream {
                        Ok(stream) => {
                            let mut reader = ~BufferedReader::new(stream);
                            let line = reader.read_line();
                            let id: Option<uint> = line.ok().and_then(|l| from_str(l));
                            if id.is_some() {
                                debug!("Handshake with peer {} completed.", id.unwrap());
                                peer_send.send((id.unwrap(), reader.unwrap()));
                            }
                            else {
                                let mut stream = reader.unwrap();
                                debug!("Dropping peer at {} never got an id.", stream.peer_name());
                                drop(stream);
                            }
                        }
                        Err(e) => {
                            break;
                        }
                    }
                }
                may_shutdown!(shutdown);
            }
        });
    }

    /*
     * Start the client listener.
     *
     * conf: the config for this server, containing *client* listen address.
     * from_clients_send: sends messages from peers back to the main loop.
     *
     */
    fn listen_clients(addr: SocketAddr, from_client_send: Sender<(ClientCmdReq, Sender<ClientCmdRes>)>, shutdown_signal: Receiver<uint>) {
        // unwrapping because our server is dead in the water if it can't listen on its assigned port
        spawn(proc() {
            let listener: TcpListener = TcpListener::bind(addr).unwrap();
            let mut acceptor: TcpAcceptor = listener.listen().unwrap();
            debug!("Started listening on {}", addr);
            loop {
                acceptor.set_timeout(Some(CONNECT_TIMEOUT));
                for maybe_stream in acceptor.incoming() {
                    match maybe_stream {
                        Ok(stream) => {
                            // TODO!
                        }
                        Err(e) => {
                            break;
                        }
                    }
                }
                may_shutdown!(shutdown_signal);
            }
        });
    }

    fn try_connect(&mut self, peer_id: uint) -> Option<TcpStream> {
        let peer = self.lookup_peer_config(peer_id);
        if peer.is_none() {
            return None;
        }
        match TcpStream::connect_timeout(peer.unwrap().address, CONNECT_TIMEOUT) {
            Ok(mut stream) => {
                stream.write_uint(peer.unwrap().id);
                stream.write_line("");
                Some(stream.clone())
            }
            err => {
                None
            }
        }
    }
}

#[cfg(test)]
mod test {
    use std::vec::Vec;
    use std::io::net::ip::{SocketAddr, Ipv4Addr};
    use std::io::net::tcp::TcpStream;
    use std::io::timer::sleep;
    use std::io::BufferedWriter;
    use std::container::MutableSet;
    use super::types::*;
    use super::NetListener;

    #[test]
    fn test_warmup() {
        let pc1 = NetPeerConfig {
            id: 1,
            address: SocketAddr {
                ip: Ipv4Addr(127, 0, 0, 1),
                port: 9090,
            },
            client_addr: SocketAddr {
                ip: Ipv4Addr(127, 0, 0, 1),
                port: 9091,
            },
        };
        let pc2 = NetPeerConfig {
            id: 2,
            address: SocketAddr {
                ip: Ipv4Addr(127, 0, 0, 1),
                port: 9092,
            },
            client_addr: SocketAddr {
                ip: Ipv4Addr(127, 0, 0, 1),
                port: 9093,
            },
        };
        let mut pc_vec1 = ~Vec::new();
        let mut pc_vec2 = ~Vec::new();
        pc_vec1.push(pc2);
        pc_vec2.push(pc1);
        let (from_peers_send1, from_peers_recv1) = channel();
        let (from_client_send1, from_client_recv1) = channel();
        let (shutdown_send1, shutdown_recv1) = channel();
        let (from_peers_send2, from_peers_recv2) = channel();
        let (from_client_send2, from_client_recv2) = channel();
        let (shutdown_send2, shutdown_recv2) = channel();
        let mut nl1 = NetListener::new(pc1, pc_vec1, from_peers_send1, from_client_send1, shutdown_recv1);
        let mut nl2 = NetListener::new(pc2, pc_vec2, from_peers_send2, from_client_send2, shutdown_recv2);
        sleep(2000);
        debug!("Sending shutdown");
        shutdown_send1.send(0);
        shutdown_send2.send(0);
        nl1.connect_peers();
        nl2.connect_peers();
    }

    fn connect_handshake(id: uint, addr: SocketAddr) {
        match TcpStream::connect(addr) {
            Ok(mut stream) => {
                let mut writer = BufferedWriter::new(stream);
                writer.write_uint(id);
                drop(writer.unwrap());
            }
            Err(e) => {
                fail!("{}", e);
            }
        }
    }

    #[test]
    fn test_listen_peers() {
        let (peer_connect_send, peer_connect_recv) = channel();
        let (shutdown_send, shutdown_recv) = channel();
        let listen_addr = SocketAddr {
            ip: Ipv4Addr(127, 0, 0, 1),
            port: 9999,
        };
        NetListener::listen_peers(listen_addr, peer_connect_send, shutdown_recv);
        sleep(1000);
        connect_handshake(14, listen_addr);
        let (res_id, _) = peer_connect_recv.recv();
        assert_eq!(res_id, 14);
        connect_handshake(10, listen_addr);
        let (res_id, _) = peer_connect_recv.recv();
        assert_eq!(res_id, 10);
        connect_handshake(1, listen_addr);
        let (res_id, _) = peer_connect_recv.recv();
        assert_eq!(res_id, 1);
        shutdown_send.send(0);
    }
}
<|endoftext|>