<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"
    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>Consistently use lowercase hex values in box_database<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 {
    ($($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"
    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>use crate::sync::atomic::Ordering;

#[cfg(test)]
use stdarch_test::assert_instr;

/// Compares and exchange 16 bytes (128 bits) of data atomically.
///
/// This intrinsic corresponds to the `cmpxchg16b` instruction on `x86_64`
/// processors. It performs an atomic compare-and-swap, updating the `ptr`
/// memory location to `val` if the current value in memory equals `old`.
///
/// # Return value
///
/// This function returns the previous value at the memory location. If it is
/// equal to `old` then the memory was updated to `new`.
///
/// # Memory Orderings
///
/// This atomic operations has the same semantics of memory orderings as
/// `AtomicUsize::compare_exchange` does, only operating on 16 bytes of memory
/// instead of just a pointer.
///
/// For more information on memory orderings here see the `compare_exchange`
/// documentation for other `Atomic*` types in the standard library.
///
/// # Unsafety
///
/// This method is unsafe because it takes a raw pointer and will attempt to
/// read and possibly write the memory at the pointer. The pointer must also be
/// aligned on a 16-byte boundary.
///
/// This method also requires the `cmpxchg16b` CPU feature to be available at
/// runtime to work correctly. If the CPU running the binary does not actually
/// support `cmpxchg16b` and the program enters an execution path that
/// eventually would reach this function the behavior is undefined.
///
/// The failure ordering must be [`SeqCst`], [`Acquire`] or [`Relaxed`], or this
/// function call is undefined. See the `Atomic*` documentation's
/// `compare_exchange` function for more information. When `compare_exchange`
/// panics, this is undefined behavior. Currently this function aborts the
/// process with an undefined instruction.
#[inline]
#[cfg_attr(test, assert_instr(cmpxchg16b, success = Ordering::SeqCst, failure = Ordering::SeqCst))]
#[target_feature(enable = "cmpxchg16b")]
pub unsafe fn cmpxchg16b(
    dst: *mut u128,
    old: u128,
    new: u128,
    success: Ordering,
    failure: Ordering,
) -> u128 {
    use crate::{intrinsics, sync::atomic::Ordering::*};

    debug_assert!(dst as usize % 16 == 0);

    let (val, _ok) = match (success, failure) {
        (Relaxed, Relaxed) => intrinsics::atomic_cxchg_relaxed_relaxed(dst, old, new),
        (Relaxed, Acquire) => intrinsics::atomic_cxchg_relaxed_acquire(dst, old, new),
        (Relaxed, SeqCst) => intrinsics::atomic_cxchg_relaxed_seqcst(dst, old, new),
        (Acquire, Relaxed) => intrinsics::atomic_cxchg_acquire_relaxed(dst, old, new),
        (Acquire, Acquire) => intrinsics::atomic_cxchg_acquire_acquire(dst, old, new),
        (Acquire, SeqCst) => intrinsics::atomic_cxchg_acquire_seqcst(dst, old, new),
        (Release, Relaxed) => intrinsics::atomic_cxchg_release_relaxed(dst, old, new),
        (Release, Acquire) => intrinsics::atomic_cxchg_release_acquire(dst, old, new),
        (Release, SeqCst) => intrinsics::atomic_cxchg_release_seqcst(dst, old, new),
        (AcqRel, Relaxed) => intrinsics::atomic_cxchg_acqrel_relaxed(dst, old, new),
        (AcqRel, Acquire) => intrinsics::atomic_cxchg_acqrel_acquire(dst, old, new),
        (AcqRel, SeqCst) => intrinsics::atomic_cxchg_acqrel_seqcst(dst, old, new),
        (SeqCst, Relaxed) => intrinsics::atomic_cxchg_seqcst_relaxed(dst, old, new),
        (SeqCst, Acquire) => intrinsics::atomic_cxchg_seqcst_acquire(dst, old, new),
        (SeqCst, SeqCst) => intrinsics::atomic_cxchg_seqcst_seqcst(dst, old, new),

        // The above block is all copied from libcore, and this statement is
        // also copied from libcore except that it's a panic in libcore and we
        // have a little bit more of a lightweight panic here.
        _ => crate::core_arch::x86::ud2(),
    };
    val
}
<commit_msg>Fix links in documentation of cmpxchg16b<commit_after>use crate::sync::atomic::Ordering;

#[cfg(test)]
use stdarch_test::assert_instr;

/// Compares and exchange 16 bytes (128 bits) of data atomically.
///
/// This intrinsic corresponds to the `cmpxchg16b` instruction on `x86_64`
/// processors. It performs an atomic compare-and-swap, updating the `ptr`
/// memory location to `val` if the current value in memory equals `old`.
///
/// # Return value
///
/// This function returns the previous value at the memory location. If it is
/// equal to `old` then the memory was updated to `new`.
///
/// # Memory Orderings
///
/// This atomic operations has the same semantics of memory orderings as
/// `AtomicUsize::compare_exchange` does, only operating on 16 bytes of memory
/// instead of just a pointer.
///
/// For more information on memory orderings here see the `compare_exchange`
/// documentation for other `Atomic*` types in the standard library.
///
/// # Unsafety
///
/// This method is unsafe because it takes a raw pointer and will attempt to
/// read and possibly write the memory at the pointer. The pointer must also be
/// aligned on a 16-byte boundary.
///
/// This method also requires the `cmpxchg16b` CPU feature to be available at
/// runtime to work correctly. If the CPU running the binary does not actually
/// support `cmpxchg16b` and the program enters an execution path that
/// eventually would reach this function the behavior is undefined.
///
/// The failure ordering must be [`Ordering::SeqCst`], [`Ordering::Acquire`] or
/// [`Ordering::Relaxed`], or this function call is undefined. See the `Atomic*`
/// documentation's `compare_exchange` function for more information. When
/// `compare_exchange` panics, this is undefined behavior. Currently this
/// function aborts the process with an undefined instruction.
#[inline]
#[cfg_attr(test, assert_instr(cmpxchg16b, success = Ordering::SeqCst, failure = Ordering::SeqCst))]
#[target_feature(enable = "cmpxchg16b")]
pub unsafe fn cmpxchg16b(
    dst: *mut u128,
    old: u128,
    new: u128,
    success: Ordering,
    failure: Ordering,
) -> u128 {
    use crate::{intrinsics, sync::atomic::Ordering::*};

    debug_assert!(dst as usize % 16 == 0);

    let (val, _ok) = match (success, failure) {
        (Relaxed, Relaxed) => intrinsics::atomic_cxchg_relaxed_relaxed(dst, old, new),
        (Relaxed, Acquire) => intrinsics::atomic_cxchg_relaxed_acquire(dst, old, new),
        (Relaxed, SeqCst) => intrinsics::atomic_cxchg_relaxed_seqcst(dst, old, new),
        (Acquire, Relaxed) => intrinsics::atomic_cxchg_acquire_relaxed(dst, old, new),
        (Acquire, Acquire) => intrinsics::atomic_cxchg_acquire_acquire(dst, old, new),
        (Acquire, SeqCst) => intrinsics::atomic_cxchg_acquire_seqcst(dst, old, new),
        (Release, Relaxed) => intrinsics::atomic_cxchg_release_relaxed(dst, old, new),
        (Release, Acquire) => intrinsics::atomic_cxchg_release_acquire(dst, old, new),
        (Release, SeqCst) => intrinsics::atomic_cxchg_release_seqcst(dst, old, new),
        (AcqRel, Relaxed) => intrinsics::atomic_cxchg_acqrel_relaxed(dst, old, new),
        (AcqRel, Acquire) => intrinsics::atomic_cxchg_acqrel_acquire(dst, old, new),
        (AcqRel, SeqCst) => intrinsics::atomic_cxchg_acqrel_seqcst(dst, old, new),
        (SeqCst, Relaxed) => intrinsics::atomic_cxchg_seqcst_relaxed(dst, old, new),
        (SeqCst, Acquire) => intrinsics::atomic_cxchg_seqcst_acquire(dst, old, new),
        (SeqCst, SeqCst) => intrinsics::atomic_cxchg_seqcst_seqcst(dst, old, new),

        // The above block is all copied from libcore, and this statement is
        // also copied from libcore except that it's a panic in libcore and we
        // have a little bit more of a lightweight panic here.
        _ => crate::core_arch::x86::ud2(),
    };
    val
}
<|endoftext|>


<commit_before>//! Access Control List (ACL) for shadowsocks
//!
//! This is for advance controlling server behaviors in both local and proxy servers.

use std::{
    collections::HashSet,
    fmt,
    fs::File,
    io::{self, BufRead, BufReader, Error, ErrorKind},
    net::{IpAddr, SocketAddr},
    path::Path,
};

use ipnet::{IpNet, Ipv4Net, Ipv6Net};
use iprange::IpRange;
use regex::bytes::{RegexSet, RegexSetBuilder};

use shadowsocks::{context::Context, relay::socks5::Address};

use self::sub_domains_tree::SubDomainsTree;

mod sub_domains_tree;

/// Strategy mode that ACL is running
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Mode {
    /// BlackList mode, rejects or bypasses all requests by default
    BlackList,
    /// WhiteList mode, accepts or proxies all requests by default
    WhiteList,
}

#[derive(Clone)]
struct Rules {
    ipv4: IpRange<Ipv4Net>,
    ipv6: IpRange<Ipv6Net>,
    rule_regex: RegexSet,
    rule_set: HashSet<String>,
    rule_tree: SubDomainsTree,
}

impl fmt::Debug for Rules {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Rules {{ ipv4: {:?}, ipv6: {:?}, rule_regex: [", self.ipv4, self.ipv6)?;

        let max_len = 2;
        let has_more = self.rule_regex.len() > max_len;

        for (idx, r) in self.rule_regex.patterns().iter().take(max_len).enumerate() {
            if idx > 0 {
                f.write_str(", ")?;
            }
            f.write_str(r)?;
        }

        if has_more {
            f.write_str(", ...")?;
        }

        write!(f, "], rule_set: {:?}, rule_tree: {:?} }}", self.rule_set, self.rule_tree)
    }
}

impl Rules {
    /// Create a new rule
    fn new(
        mut ipv4: IpRange<Ipv4Net>,
        mut ipv6: IpRange<Ipv6Net>,
        rule_regex: RegexSet,
        rule_set: HashSet<String>,
        rule_tree: SubDomainsTree,
    ) -> Rules {
        // Optimization, merging networks
        ipv4.simplify();
        ipv6.simplify();

        Rules {
            ipv4,
            ipv6,
            rule_regex,
            rule_set,
            rule_tree,
        }
    }

    /// Check if the specified address matches these rules
    #[allow(dead_code)]
    fn check_address_matched(&self, addr: &Address) -> bool {
        match *addr {
            Address::SocketAddress(ref saddr) => self.check_ip_matched(&saddr.ip()),
            Address::DomainNameAddress(ref domain, ..) => self.check_host_matched(domain),
        }
    }

    /// Check if the specified address matches any rules
    fn check_ip_matched(&self, addr: &IpAddr) -> bool {
        match addr {
            IpAddr::V4(v4) => self.ipv4.contains(v4),
            IpAddr::V6(v6) => self.ipv6.contains(v6),
        }
    }

    /// Check if the specified host matches any rules
    fn check_host_matched(&self, host: &str) -> bool {
        self.rule_set.contains(host) || self.rule_tree.contains(host) || self.rule_regex.is_match(host.as_bytes())
    }

    /// Check if there are no rules for IP addresses
    fn is_ip_empty(&self) -> bool {
        self.ipv4.is_empty() && self.ipv6.is_empty()
    }

    /// Check if there are no rules for domain names
    fn is_host_empty(&self) -> bool {
        self.rule_set.is_empty() && self.rule_tree.is_empty() && self.rule_regex.is_empty()
    }
}

/// ACL rules
///
/// ## Sections
///
/// ACL File is formatted in sections, each section has a name with surrounded by brackets `[` and `]`
/// followed by Rules line by line.
///
/// ```plain
/// [SECTION-1]
/// RULE-1
/// RULE-2
/// RULE-3
///
/// [SECTION-2]
/// RULE-1
/// RULE-2
/// RULE-3
/// ```
///
/// Available sections are
///
/// - For local servers (`sslocal`, `ssredir`, ...)
///     * `[bypass_all]` - ACL runs in `BlackList` mode.
///     * `[proxy_all]` - ACL runs in `WhiteList` mode.
///     * `[bypass_list]` - Rules for connecting directly
///     * `[proxy_list]` - Rules for connecting through proxies
/// - For remote servers (`ssserver`)
///     * `[reject_all]` - ACL runs in `BlackList` mode.
///     * `[accept_all]` - ACL runs in `WhiteList` mode.
///     * `[black_list]` - Rules for rejecting
///     * `[white_list]` - Rules for allowing
///     * `[outbound_block_list]` - Rules for blocking outbound addresses.
///
/// ## Mode
///
/// Mode is the default ACL strategy for those addresses that are not in configuration file.
///
/// - `BlackList` - Bypasses / Rejects all addresses except those in `[proxy_list]` or `[white_list]`
/// - `WhiltList` - Proxies / Accepts all addresses except those in `[bypass_list]` or `[black_list]`
///
/// ## Rules
///
/// Rules can be either
///
/// - CIDR form network addresses, like `10.9.0.32/16`
/// - IP addresses, like `127.0.0.1` or `::1`
/// - Regular Expression for matching hosts, like `(^|\.)gmail\.com$`
#[derive(Debug, Clone)]
pub struct AccessControl {
    outbound_block: Rules,
    black_list: Rules,
    white_list: Rules,
    mode: Mode,
}

impl AccessControl {
    /// Load ACL rules from a file
    pub fn load_from_file<P: AsRef<Path>>(p: P) -> io::Result<AccessControl> {
        let fp = File::open(p)?;
        let r = BufReader::new(fp);

        let mut mode = Mode::BlackList;

        let mut outbound_block_ipv4 = IpRange::new();
        let mut outbound_block_ipv6 = IpRange::new();
        let mut outbound_block_rules_regex = Vec::new();
        let mut outbound_block_rules_set = HashSet::new();
        let mut outbound_block_rules_tree = SubDomainsTree::new();
        let mut bypass_ipv4 = IpRange::new();
        let mut bypass_ipv6 = IpRange::new();
        let mut bypass_rules_regex = Vec::new();
        let mut bypass_rules_set = HashSet::new();
        let mut bypass_rules_tree = SubDomainsTree::new();
        let mut proxy_ipv4 = IpRange::new();
        let mut proxy_ipv6 = IpRange::new();
        let mut proxy_rules_regex = Vec::new();
        let mut proxy_rules_set = HashSet::new();
        let mut proxy_rules_tree = SubDomainsTree::new();

        let mut curr_ipv4 = &mut bypass_ipv4;
        let mut curr_ipv6 = &mut bypass_ipv6;
        let mut curr_rules_regex = &mut bypass_rules_regex;
        let mut curr_rules_set = &mut bypass_rules_set;
        let mut curr_rules_tree = &mut bypass_rules_tree;

        for line in r.lines() {
            let line = line?;
            if line.is_empty() {
                continue;
            }

            // Comments
            if line.starts_with('#') {
                continue;
            }

            if line.starts_with("||") {
                curr_rules_tree.insert(&line[2..]);
                continue;
            }

            if line.starts_with('|') {
                curr_rules_set.insert(line[1..].to_string());
                continue;
            }

            match line.as_str() {
                "[reject_all]" | "[bypass_all]" => {
                    mode = Mode::WhiteList;
                }
                "[accept_all]" | "[proxy_all]" => {
                    mode = Mode::BlackList;
                }
                "[outbound_block_list]" => {
                    curr_ipv4 = &mut outbound_block_ipv4;
                    curr_ipv6 = &mut outbound_block_ipv6;
                    curr_rules_regex = &mut outbound_block_rules_regex;
                    curr_rules_set = &mut outbound_block_rules_set;
                    curr_rules_tree = &mut outbound_block_rules_tree;
                }
                "[black_list]" | "[bypass_list]" => {
                    curr_ipv4 = &mut bypass_ipv4;
                    curr_ipv6 = &mut bypass_ipv6;
                    curr_rules_regex = &mut bypass_rules_regex;
                    curr_rules_set = &mut bypass_rules_set;
                    curr_rules_tree = &mut bypass_rules_tree;
                }
                "[white_list]" | "[proxy_list]" => {
                    curr_ipv4 = &mut proxy_ipv4;
                    curr_ipv6 = &mut proxy_ipv6;
                    curr_rules_regex = &mut proxy_rules_regex;
                    curr_rules_set = &mut proxy_rules_set;
                    curr_rules_tree = &mut proxy_rules_tree;
                }
                _ => {
                    match line.parse::<IpNet>() {
                        Ok(IpNet::V4(v4)) => {
                            curr_ipv4.add(v4);
                        }
                        Ok(IpNet::V6(v6)) => {
                            curr_ipv6.add(v6);
                        }
                        Err(..) => {
                            // Maybe it is a pure IpAddr
                            match line.parse::<IpAddr>() {
                                Ok(IpAddr::V4(v4)) => {
                                    curr_ipv4.add(Ipv4Net::from(v4));
                                }
                                Ok(IpAddr::V6(v6)) => {
                                    curr_ipv6.add(Ipv6Net::from(v6));
                                }
                                Err(..) => {
                                    // FIXME: If this line is not a valid regex, how can we know without actually compile it?
                                    curr_rules_regex.push(line);
                                }
                            }
                        }
                    }
                }
            }
        }

        const REGEX_SIZE_LIMIT: usize = usize::max_value();

        let outbound_block_regex = match RegexSetBuilder::new(outbound_block_rules_regex)
            .size_limit(REGEX_SIZE_LIMIT)
            .unicode(false)
            .build()
        {
            Ok(r) => r,
            Err(err) => {
                let err = Error::new(ErrorKind::Other, format!("[outbound_block_list] regex error: {}", err));
                return Err(err);
            }
        };

        let bypass_regex = match RegexSetBuilder::new(bypass_rules_regex)
            .case_insensitive(true)
            .size_limit(REGEX_SIZE_LIMIT)
            .unicode(false)
            .build()
        {
            Ok(r) => r,
            Err(err) => {
                let err = Error::new(
                    ErrorKind::Other,
                    format!("[black_list] or [bypass_list] regex error: {}", err),
                );
                return Err(err);
            }
        };

        let proxy_regex = match RegexSetBuilder::new(proxy_rules_regex)
            .case_insensitive(true)
            .size_limit(REGEX_SIZE_LIMIT)
            .unicode(false)
            .build()
        {
            Ok(r) => r,
            Err(err) => {
                let err = Error::new(
                    ErrorKind::Other,
                    format!("[white_list] or [proxy_list] regex error: {}", err),
                );
                return Err(err);
            }
        };

        Ok(AccessControl {
            outbound_block: Rules::new(
                outbound_block_ipv4,
                outbound_block_ipv6,
                outbound_block_regex,
                outbound_block_rules_set,
                outbound_block_rules_tree,
            ),
            black_list: Rules::new(
                bypass_ipv4,
                bypass_ipv6,
                bypass_regex,
                bypass_rules_set,
                bypass_rules_tree,
            ),
            white_list: Rules::new(proxy_ipv4, proxy_ipv6, proxy_regex, proxy_rules_set, proxy_rules_tree),
            mode,
        })
    }

    /// Check if domain name is in proxy_list.
    /// If so, it should be resolved from remote (for Android's DNS relay)
    ///
    /// Return
    /// - `Some(true)` if `host` is in `white_list` (should be proxied)
    /// - `Some(false)` if `host` is in `black_list` (should be bypassed)
    /// - `None` if `host` doesn't match any rules
    pub fn check_host_in_proxy_list(&self, host: &str) -> Option<bool> {
        // Addresses in proxy_list will be proxied
        if self.white_list.check_host_matched(host) {
            return Some(true);
        }
        // Addresses in bypass_list will be bypassed
        if self.black_list.check_host_matched(host) {
            return Some(false);
        }
        None
    }

    /// If there are no IP rules
    pub fn is_ip_empty(&self) -> bool {
        match self.mode {
            Mode::BlackList => self.black_list.is_ip_empty(),
            Mode::WhiteList => self.white_list.is_ip_empty(),
        }
    }

    /// If there are no domain name rules
    pub fn is_host_empty(&self) -> bool {
        self.black_list.is_host_empty() && self.white_list.is_host_empty()
    }

    /// Check if `IpAddr` should be proxied
    pub fn check_ip_in_proxy_list(&self, ip: &IpAddr) -> bool {
        match self.mode {
            Mode::BlackList => !self.black_list.check_ip_matched(ip),
            Mode::WhiteList => self.white_list.check_ip_matched(ip),
        }
    }

    /// Default mode
    ///
    /// Default behavor for hosts that are not configured
    /// - `true` - Proxied
    /// - `false` - Bypassed
    pub fn is_default_in_proxy_list(&self) -> bool {
        match self.mode {
            Mode::BlackList => true,
            Mode::WhiteList => false,
        }
    }

    /// Check if target address should be bypassed (for client)
    ///
    /// This function may perform a DNS resolution
    pub async fn check_target_bypassed(&self, context: &Context, addr: &Address) -> bool {
        match *addr {
            Address::SocketAddress(ref addr) => !self.check_ip_in_proxy_list(&addr.ip()),
            // Resolve hostname and check the list
            Address::DomainNameAddress(ref host, port) => {
                if let Some(value) = self.check_host_in_proxy_list(host) {
                    return !value;
                }
                if self.is_ip_empty() {
                    return !self.is_default_in_proxy_list();
                }
                if let Ok(vaddr) = context.dns_resolve(host, port).await {
                    for addr in vaddr {
                        if !self.check_ip_in_proxy_list(&addr.ip()) {
                            return true;
                        }
                    }
                }
                false
            }
        }
    }

    /// Check if client address should be blocked (for server)
    pub fn check_client_blocked(&self, addr: &SocketAddr) -> bool {
        match self.mode {
            Mode::BlackList => {
                // Only clients in black_list will be blocked
                self.black_list.check_ip_matched(&addr.ip())
            }
            Mode::WhiteList => {
                // Only clients in white_list will be proxied
                !self.white_list.check_ip_matched(&addr.ip())
            }
        }
    }

    /// Check if outbound address is blocked (for server)
    ///
    /// NOTE: `Address::DomainName` is only validated by regex rules,
    ///       resolved addresses are checked in the `lookup_outbound_then!` macro
    pub async fn check_outbound_blocked(&self, context: &Context, outbound: &Address) -> bool {
        match outbound {
            Address::SocketAddress(saddr) => self.outbound_block.check_ip_matched(&saddr.ip()),
            Address::DomainNameAddress(host, port) => {
                if self.outbound_block.check_host_matched(host) {
                    return true;
                }

                if let Ok(vaddr) = context.dns_resolve(host, *port).await {
                    for addr in vaddr {
                        if self.outbound_block.check_ip_matched(&addr.ip()) {
                            return true;
                        }
                    }
                }

                false
            }
        }
    }
}
<commit_msg>Refactor AccessControl::load_from_file and add ascii check for all matchers<commit_after>//! Access Control List (ACL) for shadowsocks
//!
//! This is for advance controlling server behaviors in both local and proxy servers.

use std::{
    collections::HashSet,
    fmt,
    fs::File,
    io::{self, BufRead, BufReader, Error, ErrorKind},
    net::{IpAddr, SocketAddr},
    path::Path,
};

use ipnet::{IpNet, Ipv4Net, Ipv6Net};
use iprange::IpRange;
use regex::bytes::{RegexSet, RegexSetBuilder};

use shadowsocks::{context::Context, relay::socks5::Address};

use self::sub_domains_tree::SubDomainsTree;

mod sub_domains_tree;

/// Strategy mode that ACL is running
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Mode {
    /// BlackList mode, rejects or bypasses all requests by default
    BlackList,
    /// WhiteList mode, accepts or proxies all requests by default
    WhiteList,
}

#[derive(Clone)]
struct Rules {
    ipv4: IpRange<Ipv4Net>,
    ipv6: IpRange<Ipv6Net>,
    rule_regex: RegexSet,
    rule_set: HashSet<String>,
    rule_tree: SubDomainsTree,
}

impl fmt::Debug for Rules {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Rules {{ ipv4: {:?}, ipv6: {:?}, rule_regex: [", self.ipv4, self.ipv6)?;

        let max_len = 2;
        let has_more = self.rule_regex.len() > max_len;

        for (idx, r) in self.rule_regex.patterns().iter().take(max_len).enumerate() {
            if idx > 0 {
                f.write_str(", ")?;
            }
            f.write_str(r)?;
        }

        if has_more {
            f.write_str(", ...")?;
        }

        write!(f, "], rule_set: {:?}, rule_tree: {:?} }}", self.rule_set, self.rule_tree)
    }
}

impl Rules {
    /// Create a new rule
    fn new(
        mut ipv4: IpRange<Ipv4Net>,
        mut ipv6: IpRange<Ipv6Net>,
        rule_regex: RegexSet,
        rule_set: HashSet<String>,
        rule_tree: SubDomainsTree,
    ) -> Rules {
        // Optimization, merging networks
        ipv4.simplify();
        ipv6.simplify();

        Rules {
            ipv4,
            ipv6,
            rule_regex,
            rule_set,
            rule_tree,
        }
    }

    /// Check if the specified address matches these rules
    #[allow(dead_code)]
    fn check_address_matched(&self, addr: &Address) -> bool {
        match *addr {
            Address::SocketAddress(ref saddr) => self.check_ip_matched(&saddr.ip()),
            Address::DomainNameAddress(ref domain, ..) => self.check_host_matched(domain),
        }
    }

    /// Check if the specified address matches any rules
    fn check_ip_matched(&self, addr: &IpAddr) -> bool {
        match addr {
            IpAddr::V4(v4) => self.ipv4.contains(v4),
            IpAddr::V6(v6) => self.ipv6.contains(v6),
        }
    }

    /// Check if the specified host matches any rules
    fn check_host_matched(&self, host: &str) -> bool {
        self.rule_set.contains(host) || self.rule_tree.contains(host) || self.rule_regex.is_match(host.as_bytes())
    }

    /// Check if there are no rules for IP addresses
    fn is_ip_empty(&self) -> bool {
        self.ipv4.is_empty() && self.ipv6.is_empty()
    }

    /// Check if there are no rules for domain names
    fn is_host_empty(&self) -> bool {
        self.rule_set.is_empty() && self.rule_tree.is_empty() && self.rule_regex.is_empty()
    }
}

struct ParsingRules {
    name: &'static str,
    ipv4: IpRange<Ipv4Net>,
    ipv6: IpRange<Ipv6Net>,
    rules_regex: Vec<String>,
    rules_set: HashSet<String>,
    rules_tree: SubDomainsTree,
}

impl ParsingRules {
    fn new(name: &'static str) -> Self {
        ParsingRules {
            name,
            ipv4: IpRange::new(),
            ipv6: IpRange::new(),
            rules_regex: Vec::new(),
            rules_set: HashSet::new(),
            rules_tree: SubDomainsTree::new(),
        }
    }

    fn add_ipv4_rule(&mut self, rule: impl Into<Ipv4Net>) {
        self.ipv4.add(rule.into());
    }

    fn add_ipv6_rule(&mut self, rule: impl Into<Ipv6Net>) {
        self.ipv6.add(rule.into());
    }

    fn add_regex_rule(&mut self, rule: String) {
        // FIXME: If this line is not a valid regex, how can we know without actually compile it?
        self.rules_regex.push(rule);
    }

    fn add_set_rule(&mut self, rule: &str) -> io::Result<()> {
        self.rules_set.insert(self.check_is_ascii(rule)?.to_string());
        Ok(())
    }

    fn add_tree_rule(&mut self, rule: &str) -> io::Result<()> {
        self.rules_tree.insert(self.check_is_ascii(rule)?);
        Ok(())
    }

    fn check_is_ascii<'a>(&self, str: &'a str) -> io::Result<&'a str> {
        if str.is_ascii() {
            Ok(str)
        } else {
            Err(Error::new(
                ErrorKind::Other,
                format!("{} parsing error: Unicode not allowed here `{}`", self.name, str)
            ))
        }
    }

    fn compile_regex(name: &'static str, regex_rules: Vec<String>) -> io::Result<RegexSet> {
        const REGEX_SIZE_LIMIT: usize = usize::max_value();
        RegexSetBuilder::new(regex_rules)
            .case_insensitive(true)
            .size_limit(REGEX_SIZE_LIMIT)
            .unicode(false)
            .build()
            .map_err(|err| Error::new(
                ErrorKind::Other,
                format!("{} regex error: {}", name, err),
            ))
    }

    fn into_rules(self) -> io::Result<Rules> {
        Ok(Rules::new(
            self.ipv4,
            self.ipv6,
            Self::compile_regex(self.name, self.rules_regex)?,
            self.rules_set,
            self.rules_tree,
        ))
    }
}

/// ACL rules
///
/// ## Sections
///
/// ACL File is formatted in sections, each section has a name with surrounded by brackets `[` and `]`
/// followed by Rules line by line.
///
/// ```plain
/// [SECTION-1]
/// RULE-1
/// RULE-2
/// RULE-3
///
/// [SECTION-2]
/// RULE-1
/// RULE-2
/// RULE-3
/// ```
///
/// Available sections are
///
/// - For local servers (`sslocal`, `ssredir`, ...)
///     * `[bypass_all]` - ACL runs in `BlackList` mode.
///     * `[proxy_all]` - ACL runs in `WhiteList` mode.
///     * `[bypass_list]` - Rules for connecting directly
///     * `[proxy_list]` - Rules for connecting through proxies
/// - For remote servers (`ssserver`)
///     * `[reject_all]` - ACL runs in `BlackList` mode.
///     * `[accept_all]` - ACL runs in `WhiteList` mode.
///     * `[black_list]` - Rules for rejecting
///     * `[white_list]` - Rules for allowing
///     * `[outbound_block_list]` - Rules for blocking outbound addresses.
///
/// ## Mode
///
/// Mode is the default ACL strategy for those addresses that are not in configuration file.
///
/// - `BlackList` - Bypasses / Rejects all addresses except those in `[proxy_list]` or `[white_list]`
/// - `WhiltList` - Proxies / Accepts all addresses except those in `[bypass_list]` or `[black_list]`
///
/// ## Rules
///
/// Rules can be either
///
/// - CIDR form network addresses, like `10.9.0.32/16`
/// - IP addresses, like `127.0.0.1` or `::1`
/// - Regular Expression for matching hosts, like `(^|\.)gmail\.com$`
/// - Domain with preceding `|` for exact matching, like `|google.com`
/// - Domain with preceding `||` for matching with subdomains, like `||google.com`
#[derive(Debug, Clone)]
pub struct AccessControl {
    outbound_block: Rules,
    black_list: Rules,
    white_list: Rules,
    mode: Mode,
}

impl AccessControl {
    /// Load ACL rules from a file
    pub fn load_from_file<P: AsRef<Path>>(p: P) -> io::Result<AccessControl> {
        let fp = File::open(p)?;
        let r = BufReader::new(fp);

        let mut mode = Mode::BlackList;

        let mut outbound_block = ParsingRules::new("[outbound_block_list]");
        let mut bypass = ParsingRules::new("[black_list] or [bypass_list]");
        let mut proxy = ParsingRules::new("[white_list] or [proxy_list]");
        let mut curr = &mut bypass;

        for line in r.lines() {
            let line = line?;
            if line.is_empty() {
                continue;
            }

            // Comments
            if line.starts_with('#') {
                continue;
            }

            if line.starts_with("||") {
                curr.add_tree_rule(&line[2..])?;
                continue;
            }

            if line.starts_with('|') {
                curr.add_set_rule(&line[1..])?;
                continue;
            }

            match line.as_str() {
                "[reject_all]" | "[bypass_all]" => {
                    mode = Mode::WhiteList;
                }
                "[accept_all]" | "[proxy_all]" => {
                    mode = Mode::BlackList;
                }
                "[outbound_block_list]" => {
                    curr = &mut outbound_block;
                }
                "[black_list]" | "[bypass_list]" => {
                    curr = &mut bypass;
                }
                "[white_list]" | "[proxy_list]" => {
                    curr = &mut proxy;
                }
                _ => {
                    match line.parse::<IpNet>() {
                        Ok(IpNet::V4(v4)) => {
                            curr.add_ipv4_rule(v4);
                        }
                        Ok(IpNet::V6(v6)) => {
                            curr.add_ipv6_rule(v6);
                        }
                        Err(..) => {
                            // Maybe it is a pure IpAddr
                            match line.parse::<IpAddr>() {
                                Ok(IpAddr::V4(v4)) => {
                                    curr.add_ipv4_rule(v4);
                                }
                                Ok(IpAddr::V6(v6)) => {
                                    curr.add_ipv6_rule(v6);
                                }
                                Err(..) => {
                                    curr.add_regex_rule(line);
                                }
                            }
                        }
                    }
                }
            }
        }

        Ok(AccessControl {
            outbound_block: outbound_block.into_rules()?,
            black_list: bypass.into_rules()?,
            white_list: proxy.into_rules()?,
            mode,
        })
    }

    /// Check if domain name is in proxy_list.
    /// If so, it should be resolved from remote (for Android's DNS relay)
    ///
    /// Return
    /// - `Some(true)` if `host` is in `white_list` (should be proxied)
    /// - `Some(false)` if `host` is in `black_list` (should be bypassed)
    /// - `None` if `host` doesn't match any rules
    pub fn check_host_in_proxy_list(&self, host: &str) -> Option<bool> {
        // Addresses in proxy_list will be proxied
        if self.white_list.check_host_matched(host) {
            return Some(true);
        }
        // Addresses in bypass_list will be bypassed
        if self.black_list.check_host_matched(host) {
            return Some(false);
        }
        None
    }

    /// If there are no IP rules
    pub fn is_ip_empty(&self) -> bool {
        match self.mode {
            Mode::BlackList => self.black_list.is_ip_empty(),
            Mode::WhiteList => self.white_list.is_ip_empty(),
        }
    }

    /// If there are no domain name rules
    pub fn is_host_empty(&self) -> bool {
        self.black_list.is_host_empty() && self.white_list.is_host_empty()
    }

    /// Check if `IpAddr` should be proxied
    pub fn check_ip_in_proxy_list(&self, ip: &IpAddr) -> bool {
        match self.mode {
            Mode::BlackList => !self.black_list.check_ip_matched(ip),
            Mode::WhiteList => self.white_list.check_ip_matched(ip),
        }
    }

    /// Default mode
    ///
    /// Default behavor for hosts that are not configured
    /// - `true` - Proxied
    /// - `false` - Bypassed
    pub fn is_default_in_proxy_list(&self) -> bool {
        match self.mode {
            Mode::BlackList => true,
            Mode::WhiteList => false,
        }
    }

    /// Check if target address should be bypassed (for client)
    ///
    /// This function may perform a DNS resolution
    pub async fn check_target_bypassed(&self, context: &Context, addr: &Address) -> bool {
        match *addr {
            Address::SocketAddress(ref addr) => !self.check_ip_in_proxy_list(&addr.ip()),
            // Resolve hostname and check the list
            Address::DomainNameAddress(ref host, port) => {
                if let Some(value) = self.check_host_in_proxy_list(host) {
                    return !value;
                }
                if self.is_ip_empty() {
                    return !self.is_default_in_proxy_list();
                }
                if let Ok(vaddr) = context.dns_resolve(host, port).await {
                    for addr in vaddr {
                        if !self.check_ip_in_proxy_list(&addr.ip()) {
                            return true;
                        }
                    }
                }
                false
            }
        }
    }

    /// Check if client address should be blocked (for server)
    pub fn check_client_blocked(&self, addr: &SocketAddr) -> bool {
        match self.mode {
            Mode::BlackList => {
                // Only clients in black_list will be blocked
                self.black_list.check_ip_matched(&addr.ip())
            }
            Mode::WhiteList => {
                // Only clients in white_list will be proxied
                !self.white_list.check_ip_matched(&addr.ip())
            }
        }
    }

    /// Check if outbound address is blocked (for server)
    ///
    /// NOTE: `Address::DomainName` is only validated by regex rules,
    ///       resolved addresses are checked in the `lookup_outbound_then!` macro
    pub async fn check_outbound_blocked(&self, context: &Context, outbound: &Address) -> bool {
        match outbound {
            Address::SocketAddress(saddr) => self.outbound_block.check_ip_matched(&saddr.ip()),
            Address::DomainNameAddress(host, port) => {
                if self.outbound_block.check_host_matched(host) {
                    return true;
                }

                if let Ok(vaddr) = context.dns_resolve(host, *port).await {
                    for addr in vaddr {
                        if self.outbound_block.check_ip_matched(&addr.ip()) {
                            return true;
                        }
                    }
                }

                false
            }
        }
    }
}
<|endoftext|>


<commit_before>use rustc_serialize::{Encodable, Decodable, Decoder};
use std::collections::HashMap;
use toml::encode_str;

use yxorp::messages::Command;

#[derive(Debug,Clone,PartialEq,Eq,Hash, RustcDecodable, RustcEncodable)]
pub struct HttpProxyInstance {
  ip_address: String,
  port:       u16,
}

#[derive(Debug,Clone,PartialEq,Eq,Hash, RustcDecodable, RustcEncodable)]
pub struct HttpProxyFront {
  app_id:     String,
  hostname:   String,
  path_begin: String,
  port:       u16,
  instances:  Vec<HttpProxyInstance>
}

#[derive(Debug,Clone,PartialEq,Eq,RustcDecodable, RustcEncodable)]
pub struct HttpProxy {
  ip_address: String,
  port:       u16,
  fronts:     HashMap<String, HttpProxyFront>
}

#[derive(Debug,Clone,PartialEq,Eq,Hash, RustcDecodable, RustcEncodable)]
pub struct TlsProxyFront {
  app_id:     String,
  hostname:   String,
  path_begin: String,
  port:       u16,
  cert_path:  String,
  key_path:   String,
  instances:  Vec<HttpProxyInstance>
}

#[derive(Debug,Clone,PartialEq,Eq,RustcDecodable, RustcEncodable)]
pub struct TlsProxy {
  ip_address: String,
  port:       u16,
  fronts:     HashMap<String, TlsProxyFront>
}

impl HttpProxy {
  fn new(ip: String, port: u16) -> HttpProxy {
    HttpProxy {
      ip_address: ip,
      port:       port,
      fronts:     HashMap::new(),
    }
  }

  fn handle_command(&mut self, command: &Command) {
    match command {
      &Command::AddHttpFront(ref front) => {
        let f = HttpProxyFront {
          app_id:     front.app_id.clone(),
          hostname:   front.hostname.clone(),
          path_begin: front.path_begin.clone(),
          port:       front.port,
          instances:  Vec::new()
        };
        self.fronts.insert(front.app_id.clone(), f);
      },
      &Command::RemoveHttpFront(ref front) => {
        self.fronts.remove(&front.app_id);
      },
      &Command::AddInstance(ref instance)  => {
        if let Some(front) = self.fronts.get_mut(&instance.app_id) {
          let inst = HttpProxyInstance {
            ip_address: instance.ip_address.clone(),
            port:       instance.port,
          };
          front.instances.push(inst);
        }
      },
      &Command::RemoveInstance(ref instance) => {
        if let Some(front) = self.fronts.get_mut(&instance.app_id) {
          let mut v = Vec::new();
          for el in front.instances.drain(..) {
            if el.ip_address != instance.ip_address || el.port != instance.port {
              v.push(el);
            }
          }
          front.instances = v;
        }
      }
      _ => {}
    }
  }

  fn encode(&self) -> String {
    encode_str(self)
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use yxorp::messages::{Command,HttpFront,Instance};
  use toml::decode_str;

  #[test]
  fn serialize() {
    let mut state = HttpProxy::new(String::from("127.0.0.1"), 80);
    state.handle_command(&Command::AddHttpFront(HttpFront { app_id: String::from("app_1"), hostname: String::from("lolcatho.st:8080"), path_begin: String::from("/"), port: 8080 }));
    state.handle_command(&Command::AddHttpFront(HttpFront { app_id: String::from("app_2"), hostname: String::from("test.local"), path_begin: String::from("/abc"), port: 80 }));
    state.handle_command(&Command::AddInstance(Instance { app_id: String::from("app_1"), ip_address: String::from("127.0.0.1"), port: 1026 }));
    state.handle_command(&Command::AddInstance(Instance { app_id: String::from("app_1"), ip_address: String::from("127.0.0.2"), port: 1027 }));
    state.handle_command(&Command::AddInstance(Instance { app_id: String::from("app_2"), ip_address: String::from("192.167.1.2"), port: 1026 }));
    state.handle_command(&Command::AddInstance(Instance { app_id: String::from("app_1"), ip_address: String::from("192.168.1.3"), port: 1027 }));
    state.handle_command(&Command::RemoveInstance(Instance { app_id: String::from("app_1"), ip_address: String::from("192.168.1.3"), port: 1027 }));

    let encoded = state.encode();
    println!("serialized:\n{}", encoded);

    let new_state: Option<HttpProxy> = decode_str(&encoded);
    println!("deserialized:\n{:?}", new_state);
    assert!(false);
  }
}
/*
pub struct ConfigState {
  listeners
}
*/
<commit_msg>pass the tests<commit_after>use rustc_serialize::{Encodable, Decodable, Decoder};
use std::collections::HashMap;
use toml::encode_str;

use yxorp::messages::Command;

#[derive(Debug,Clone,PartialEq,Eq,Hash, RustcDecodable, RustcEncodable)]
pub struct HttpProxyInstance {
  ip_address: String,
  port:       u16,
}

#[derive(Debug,Clone,PartialEq,Eq,Hash, RustcDecodable, RustcEncodable)]
pub struct HttpProxyFront {
  app_id:     String,
  hostname:   String,
  path_begin: String,
  port:       u16,
  instances:  Vec<HttpProxyInstance>
}

#[derive(Debug,Clone,PartialEq,Eq,RustcDecodable, RustcEncodable)]
pub struct HttpProxy {
  ip_address: String,
  port:       u16,
  fronts:     HashMap<String, HttpProxyFront>
}

#[derive(Debug,Clone,PartialEq,Eq,Hash, RustcDecodable, RustcEncodable)]
pub struct TlsProxyFront {
  app_id:     String,
  hostname:   String,
  path_begin: String,
  port:       u16,
  cert_path:  String,
  key_path:   String,
  instances:  Vec<HttpProxyInstance>
}

#[derive(Debug,Clone,PartialEq,Eq,RustcDecodable, RustcEncodable)]
pub struct TlsProxy {
  ip_address: String,
  port:       u16,
  fronts:     HashMap<String, TlsProxyFront>
}

impl HttpProxy {
  fn new(ip: String, port: u16) -> HttpProxy {
    HttpProxy {
      ip_address: ip,
      port:       port,
      fronts:     HashMap::new(),
    }
  }

  fn handle_command(&mut self, command: &Command) {
    match command {
      &Command::AddHttpFront(ref front) => {
        let f = HttpProxyFront {
          app_id:     front.app_id.clone(),
          hostname:   front.hostname.clone(),
          path_begin: front.path_begin.clone(),
          port:       front.port,
          instances:  Vec::new()
        };
        self.fronts.insert(front.app_id.clone(), f);
      },
      &Command::RemoveHttpFront(ref front) => {
        self.fronts.remove(&front.app_id);
      },
      &Command::AddInstance(ref instance)  => {
        if let Some(front) = self.fronts.get_mut(&instance.app_id) {
          let inst = HttpProxyInstance {
            ip_address: instance.ip_address.clone(),
            port:       instance.port,
          };
          front.instances.push(inst);
        }
      },
      &Command::RemoveInstance(ref instance) => {
        if let Some(front) = self.fronts.get_mut(&instance.app_id) {
          let mut v = Vec::new();
          for el in front.instances.drain(..) {
            if el.ip_address != instance.ip_address || el.port != instance.port {
              v.push(el);
            }
          }
          front.instances = v;
        }
      }
      _ => {}
    }
  }

  fn encode(&self) -> String {
    encode_str(self)
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use yxorp::messages::{Command,HttpFront,Instance};
  use toml::decode_str;

  #[test]
  fn serialize() {
    let mut state = HttpProxy::new(String::from("127.0.0.1"), 80);
    state.handle_command(&Command::AddHttpFront(HttpFront { app_id: String::from("app_1"), hostname: String::from("lolcatho.st:8080"), path_begin: String::from("/"), port: 8080 }));
    state.handle_command(&Command::AddHttpFront(HttpFront { app_id: String::from("app_2"), hostname: String::from("test.local"), path_begin: String::from("/abc"), port: 80 }));
    state.handle_command(&Command::AddInstance(Instance { app_id: String::from("app_1"), ip_address: String::from("127.0.0.1"), port: 1026 }));
    state.handle_command(&Command::AddInstance(Instance { app_id: String::from("app_1"), ip_address: String::from("127.0.0.2"), port: 1027 }));
    state.handle_command(&Command::AddInstance(Instance { app_id: String::from("app_2"), ip_address: String::from("192.167.1.2"), port: 1026 }));
    state.handle_command(&Command::AddInstance(Instance { app_id: String::from("app_1"), ip_address: String::from("192.168.1.3"), port: 1027 }));
    state.handle_command(&Command::RemoveInstance(Instance { app_id: String::from("app_1"), ip_address: String::from("192.168.1.3"), port: 1027 }));

    let encoded = state.encode();
    println!("serialized:\n{}", encoded);

    let new_state: Option<HttpProxy> = decode_str(&encoded);
    println!("deserialized:\n{:?}", new_state);
    assert_eq!(new_state, Some(state));
    //assert!(false);
  }
}
<|endoftext|>


<commit_before>// xfail-stage0
// xfail-stage1
// xfail-stage2
// -*- rust -*-

// error-pattern: Unsatisfied .* lt(a, c)

fn f(int a, int b) : lt(a,b) {
}

fn lt(int a, int b) -> bool {
  ret a < b;
}

fn main() {
  let int a = 10;
  let int b = 23;
  let int c = 77;
  check lt(a,b);
  check lt(b,c);
  f(a,b);
  f(a,c);
}
<commit_msg>change fn to pred in pred-on-wrong-slots (but it's still xfailed<commit_after>// xfail-stage0
// xfail-stage1
// xfail-stage2
// -*- rust -*-

// error-pattern: Unsatisfied .* lt(a, c)

fn f(int a, int b) : lt(a,b) {
}

pred lt(int a, int b) -> bool {
  ret a < b;
}

fn main() {
  let int a = 10;
  let int b = 23;
  let int c = 77;
  check lt(a,b);
  check lt(b,c);
  f(a,b);
  f(a,c);
}
<|endoftext|>


<commit_before>use super::from_clause::AsQuerySource;
use crate::backend::Backend;
use crate::expression::{Expression, SelectableExpression};
use crate::query_builder::*;
use crate::query_source::QuerySource;

#[doc(hidden)]
pub struct DefaultSelectClause<QS: AsQuerySource> {
    default_seletion: <QS::QuerySource as QuerySource>::DefaultSelection,
}

impl<QS> std::fmt::Debug for DefaultSelectClause<QS>
where
    QS: AsQuerySource,
    <QS::QuerySource as QuerySource>::DefaultSelection: std::fmt::Debug,
{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("DefaultSelectClause")
            .field("default_seletion", &self.default_seletion)
            .finish()
    }
}

impl<QS> Clone for DefaultSelectClause<QS>
where
    QS: AsQuerySource,
    <QS::QuerySource as QuerySource>::DefaultSelection: Clone,
{
    fn clone(&self) -> Self {
        Self {
            default_seletion: self.default_seletion.clone(),
        }
    }
}

impl<QS> Copy for DefaultSelectClause<QS>
where
    QS: AsQuerySource,
    <QS::QuerySource as QuerySource>::DefaultSelection: Copy,
{
}

impl<QS: AsQuerySource> DefaultSelectClause<QS> {
    pub(crate) fn new(qs: &QS) -> Self {
        Self {
            default_seletion: qs.as_query_source().default_selection(),
        }
    }
}

impl<QS> QueryId for DefaultSelectClause<QS>
where
    QS: AsQuerySource,
    <QS::QuerySource as QuerySource>::DefaultSelection: QueryId,
{
    type QueryId = <<QS::QuerySource as QuerySource>::DefaultSelection as QueryId>::QueryId;

    const HAS_STATIC_QUERY_ID: bool =
        <<QS::QuerySource as QuerySource>::DefaultSelection as QueryId>::HAS_STATIC_QUERY_ID;
}

#[derive(Debug, Clone, Copy, QueryId)]
pub struct SelectClause<T>(pub T);

/// Specialised variant of `Expression` for select clause types
///
/// The difference to the normal `Expression` trait is the query source (`QS`)
/// generic type parameter. This allows to access the query source in generic code.
#[cfg_attr(
    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
    cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")
)]
pub trait SelectClauseExpression<QS> {
    /// The expression represented by the given select clause
    type Selection;
    /// SQL type of the select clause
    type SelectClauseSqlType;
}

impl<T, QS> SelectClauseExpression<FromClause<QS>> for SelectClause<T>
where
    QS: QuerySource,
    T: SelectableExpression<QS>,
{
    type Selection = T;
    type SelectClauseSqlType = T::SqlType;
}

impl<T> SelectClauseExpression<NoFromClause> for SelectClause<T>
where
    T: SelectableExpression<NoFromClause>,
{
    type Selection = T;
    type SelectClauseSqlType = T::SqlType;
}

impl<QS> SelectClauseExpression<FromClause<QS>> for DefaultSelectClause<FromClause<QS>>
where
    QS: QuerySource,
{
    type Selection = QS::DefaultSelection;
    type SelectClauseSqlType = <Self::Selection as Expression>::SqlType;
}

impl<T, DB> QueryFragment<DB> for SelectClause<T>
where
    DB: Backend,
    T: QueryFragment<DB>,
{
    fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
        self.0.walk_ast(pass)
    }
}

impl<QS, DB> QueryFragment<DB> for DefaultSelectClause<QS>
where
    DB: Backend,
    QS: AsQuerySource,
    <QS::QuerySource as QuerySource>::DefaultSelection: QueryFragment<DB>,
{
    fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
        self.default_seletion.walk_ast(pass)
    }
}
<commit_msg>fix typo<commit_after>use super::from_clause::AsQuerySource;
use crate::backend::Backend;
use crate::expression::{Expression, SelectableExpression};
use crate::query_builder::*;
use crate::query_source::QuerySource;

#[doc(hidden)]
pub struct DefaultSelectClause<QS: AsQuerySource> {
    default_selection: <QS::QuerySource as QuerySource>::DefaultSelection,
}

impl<QS> std::fmt::Debug for DefaultSelectClause<QS>
where
    QS: AsQuerySource,
    <QS::QuerySource as QuerySource>::DefaultSelection: std::fmt::Debug,
{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("DefaultSelectClause")
            .field("default_selection", &self.default_selection)
            .finish()
    }
}

impl<QS> Clone for DefaultSelectClause<QS>
where
    QS: AsQuerySource,
    <QS::QuerySource as QuerySource>::DefaultSelection: Clone,
{
    fn clone(&self) -> Self {
        Self {
            default_selection: self.default_selection.clone(),
        }
    }
}

impl<QS> Copy for DefaultSelectClause<QS>
where
    QS: AsQuerySource,
    <QS::QuerySource as QuerySource>::DefaultSelection: Copy,
{
}

impl<QS: AsQuerySource> DefaultSelectClause<QS> {
    pub(crate) fn new(qs: &QS) -> Self {
        Self {
            default_selection: qs.as_query_source().default_selection(),
        }
    }
}

impl<QS> QueryId for DefaultSelectClause<QS>
where
    QS: AsQuerySource,
    <QS::QuerySource as QuerySource>::DefaultSelection: QueryId,
{
    type QueryId = <<QS::QuerySource as QuerySource>::DefaultSelection as QueryId>::QueryId;

    const HAS_STATIC_QUERY_ID: bool =
        <<QS::QuerySource as QuerySource>::DefaultSelection as QueryId>::HAS_STATIC_QUERY_ID;
}

#[derive(Debug, Clone, Copy, QueryId)]
pub struct SelectClause<T>(pub T);

/// Specialised variant of `Expression` for select clause types
///
/// The difference to the normal `Expression` trait is the query source (`QS`)
/// generic type parameter. This allows to access the query source in generic code.
#[cfg_attr(
    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
    cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")
)]
pub trait SelectClauseExpression<QS> {
    /// The expression represented by the given select clause
    type Selection;
    /// SQL type of the select clause
    type SelectClauseSqlType;
}

impl<T, QS> SelectClauseExpression<FromClause<QS>> for SelectClause<T>
where
    QS: QuerySource,
    T: SelectableExpression<QS>,
{
    type Selection = T;
    type SelectClauseSqlType = T::SqlType;
}

impl<T> SelectClauseExpression<NoFromClause> for SelectClause<T>
where
    T: SelectableExpression<NoFromClause>,
{
    type Selection = T;
    type SelectClauseSqlType = T::SqlType;
}

impl<QS> SelectClauseExpression<FromClause<QS>> for DefaultSelectClause<FromClause<QS>>
where
    QS: QuerySource,
{
    type Selection = QS::DefaultSelection;
    type SelectClauseSqlType = <Self::Selection as Expression>::SqlType;
}

impl<T, DB> QueryFragment<DB> for SelectClause<T>
where
    DB: Backend,
    T: QueryFragment<DB>,
{
    fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
        self.0.walk_ast(pass)
    }
}

impl<QS, DB> QueryFragment<DB> for DefaultSelectClause<QS>
where
    DB: Backend,
    QS: AsQuerySource,
    <QS::QuerySource as QuerySource>::DefaultSelection: QueryFragment<DB>,
{
    fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
        self.default_selection.walk_ast(pass)
    }
}
<|endoftext|>


<commit_before>/// Internal namespace.
mod internal
{
  use crate::exposed::*;

  // xxx : module type_constructors
  // xxx : samples
  // xxx : redo implements

  // xxx : implement clone_as_tuple()
  // xxx : implement clone_as_array()
  // xxx : implement as_tuple()
  // xxx : implement as_array()
  // xxx : implement as_slice()

  // xxx : from type for homopair
  // xxx : from array for homopair
  // xxx : from slice for homopair

  ///
  /// Type constructor to define tuple wrapping a given type.
  ///
  /// Quite often you need to wrap a given type into new one.
  /// For example if orphan rule became and obstacle one should introduce a new type wrapping foreing one.
  /// Type constructr `types!` does exaclty that and auto-implement traits From, Into and Deref for the constructed type.
  ///
  /// ### Sample :: single line single.
  ///
  /// To define your own single use macro `types!`. Single-line definition looks like that.
  ///
  /// ```rust
  /// use fundamental_data_type::prelude::*;
  /// types!( single MySingle : i32 );
  /// let x = MySingle( 13 );
  /// println!( "x : {}", x.0 );
  /// ```
  ///
  /// It gererates code:
  ///
  /// ```rust
  /// use fundamental_data_type::prelude::*;
  ///
  /// pub struct MySingle( pub i32 );
  ///
  /// impl core::ops::Deref for MySingle
  /// {
  ///   type Target = i32;
  ///   fn deref( &self ) -> &Self::Target
  ///   {
  ///     &self.0
  ///   }
  /// }
  /// impl From< i32 > for MySingle
  /// {
  ///   fn from( src : i32 ) -> Self
  ///   {
  ///     Self( src )
  ///   }
  /// }
  /// impl From< MySingle > for i32
  /// {
  ///   fn from( src : MySingle ) -> Self
  ///   {
  ///     src.0
  ///   }
  /// }
  ///
  /// let x = MySingle( 13 );
  /// println!( "x : {}", x.0 );
  /// ```
  ///
  /// ### Sample :: single with derives and attributes.
  ///
  /// It's possible to define attributes as well as derives.
  ///
  /// ```rust
  /// use fundamental_data_type::prelude::*;
  /// types!
  /// {
  ///   /// This is also attribute and macro understands it.
  ///   #[ derive( Debug ) ]
  ///   single MySingle : i32;
  /// }
  /// let x = MySingle( 13 );
  /// dbg!( x );
  /// ```
  ///
  /// It gererates code:
  ///
  /// ```rust
  /// use fundamental_data_type::prelude::*;
  ///
  /// /// This is also attribute and macro understands it.
  /// #[ derive( Debug ) ]
  /// pub struct MySingle( pub i32 );
  ///
  /// impl core::ops::Deref for MySingle
  /// {
  ///   type Target = i32;
  ///   fn deref( &self ) -> &Self::Target
  ///   {
  ///     &self.0
  ///   }
  /// }
  /// impl From< i32 > for MySingle
  /// {
  ///   fn from( src : i32 ) -> Self
  ///   {
  ///     Self( src )
  ///   }
  /// }
  /// impl From< MySingle > for i32
  /// {
  ///   fn from( src : MySingle ) -> Self
  ///   {
  ///     src.0
  ///   }
  /// }
  ///
  /// let x = MySingle( 13 );
  /// dbg!( x );
  /// ```
  ///
  /// ### Sample :: single with struct instead of macro.
  ///
  /// Sometimes it's sufficient to use common type instead of defining a brand new.
  /// You may use paramtetrized struct `Single< T >` instead of macro `types!` if that is the case.
  ///
  /// ```rust
  /// use fundamental_data_type::prelude::*;
  /// let x = Single::< i32 >( 13 );
  /// dbg!( x );
  /// ```
  ///
  /// ### Sample :: single with parametrized element.
  ///
  /// Element of tuple could be parametrized.
  ///
  /// ```rust
  /// use fundamental_data_type::prelude::*;
  /// types!
  /// {
  ///   #[ derive( Debug ) ]
  ///   single MySingle : std::sync::Arc< T : Copy >;
  /// }
  /// let x = MySingle( std::sync::Arc::new( 13 ) );
  /// dbg!( x );
  /// ```
  ///
  /// It gererates code:
  ///
  /// ```rust
  /// use fundamental_data_type::*;
  ///
  /// #[ derive( Debug ) ]
  /// pub struct MySingle< T : Copy >( pub std::sync::Arc< T > );
  ///
  /// impl<T: Copy> core::ops::Deref for MySingle< T >
  /// {
  ///   type Target = std::sync::Arc< T >;
  ///   fn deref( &self ) -> &Self::Target
  ///   {
  ///     &self.0
  ///   }
  /// }
  /// impl< T : Copy > From< std::sync::Arc< T > > for MySingle< T >
  /// {
  ///   fn from( src : std::sync::Arc<T>) -> Self {
  ///     Self( src )
  ///   }
  /// }
  /// impl< T : Copy > From< MySingle< T > > for std::sync::Arc< T >
  /// {
  ///   fn from(src: MySingle<T>) -> Self
  ///   {
  ///     src.0
  ///   }
  /// }
  ///
  /// let x = MySingle( std::sync::Arc::new( 13 ) );
  /// ```
  ///
  /// ### Sample :: single with parametrized tuple.
  ///
  /// Instead of parametrizing the element it's possible to define a parametrized tuple.
  ///
  ///
  /// ```rust
  /// use fundamental_data_type::prelude::*;
  /// types!
  /// {
  ///   #[ derive( Debug ) ]
  ///   single MySingle : < T : Copy >;
  /// }
  /// let x = MySingle( 13 );
  /// dbg!( x );
  /// ```
  ///
  /// It gererates code:
  ///
  /// ```rust
  /// #[ derive( Debug ) ]
  /// pub struct MySingle< T : Copy >( pub T );
  ///
  /// impl< T : Copy > core::ops::Deref
  /// for MySingle< T >
  /// {
  ///   type Target = T;
  ///   fn deref( &self ) -> &Self::Target
  ///   {
  ///     &self.0
  ///   }
  /// }
  ///
  /// impl< T : Copy > From< T >
  /// for MySingle< T >
  /// {
  ///   fn from( src : T ) -> Self
  ///   {
  ///     Self( src )
  ///   }
  /// }
  ///
  /// let x = MySingle( 13 );
  /// dbg!( 13 );
  /// ```
  ///

  // #[ doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/Readme.md" ) ) ]

  #[ macro_export ]
  macro_rules! types
  {

    // No more.

    (
    )
    =>
    {
    };

    // No more.

    (
      ;
    )
    =>
    {
    };

    // single

    (
      $( #[ $Meta : meta ] )*
      single
      $( $Rest : tt )*
    )
    =>
    {
      $crate::_single!
      {
        $( #[ $Meta ] )*
        single
        $( $Rest )*
      }
    };

    // pair

    (
      $( #[ $Meta : meta ] )*
      pair
      $( $Rest : tt )*
    )
    =>
    {
      $crate::_pair!
      {
        $( #[ $Meta ] )*
        pair
        $( $Rest )*
      }
    };

    // bad syntax

    (
      $( $Rest : tt )*
    )
    =>
    {
      compile_error!
      (
        concat!
        (
          "Bad syntax.\n",
          "Expects : {kind} {name} : {type}.\n",
          "For example : `single MySingle : std::sync::Arc< T : Copy >`.\n",
          "But got:\n",
          stringify!
          (
            $( $Rest )*
          ),
        )
      );
    };

  }

  pub use types;
}

/// Protected namespace of the module.
pub mod protected
{
  pub use super::orphan::*;
}

pub use protected::*;

/// Orphan namespace of the module.
pub mod orphan
{
  pub use super::exposed::*;
}

/// Exposed namespace of the module.
pub mod exposed
{
  pub use super::prelude::*;
}

pub use exposed::*;

/// Prelude to use: `use wtools::prelude::*`.
pub mod prelude
{
  #[ doc( inline ) ]
  pub use super::internal::
  {
    types,
  };
}
<commit_msg>!build<commit_after>/// Internal namespace.
mod internal
{
  use crate::exposed::*;

  // xxx : implement type constructor many
  // xxx : module type_constructors
  // xxx : samples
  // xxx : redo implements

  ///
  /// Type constructor to define tuple wrapping a given type.
  ///
  /// Quite often you need to wrap a given type into new one.
  /// For example if orphan rule became and obstacle one should introduce a new type wrapping foreing one.
  /// Type constructr `types!` does exaclty that and auto-implement traits From, Into and Deref for the constructed type.
  ///
  /// ### Sample :: single line single.
  ///
  /// To define your own single use macro `types!`. Single-line definition looks like that.
  ///
  /// ```rust
  /// use fundamental_data_type::prelude::*;
  /// types!( single MySingle : i32 );
  /// let x = MySingle( 13 );
  /// println!( "x : {}", x.0 );
  /// ```
  ///
  /// It gererates code:
  ///
  /// ```rust
  /// use fundamental_data_type::prelude::*;
  ///
  /// pub struct MySingle( pub i32 );
  ///
  /// impl core::ops::Deref for MySingle
  /// {
  ///   type Target = i32;
  ///   fn deref( &self ) -> &Self::Target
  ///   {
  ///     &self.0
  ///   }
  /// }
  /// impl From< i32 > for MySingle
  /// {
  ///   fn from( src : i32 ) -> Self
  ///   {
  ///     Self( src )
  ///   }
  /// }
  /// impl From< MySingle > for i32
  /// {
  ///   fn from( src : MySingle ) -> Self
  ///   {
  ///     src.0
  ///   }
  /// }
  ///
  /// let x = MySingle( 13 );
  /// println!( "x : {}", x.0 );
  /// ```
  ///
  /// ### Sample :: single with derives and attributes.
  ///
  /// It's possible to define attributes as well as derives.
  ///
  /// ```rust
  /// use fundamental_data_type::prelude::*;
  /// types!
  /// {
  ///   /// This is also attribute and macro understands it.
  ///   #[ derive( Debug ) ]
  ///   single MySingle : i32;
  /// }
  /// let x = MySingle( 13 );
  /// dbg!( x );
  /// ```
  ///
  /// It gererates code:
  ///
  /// ```rust
  /// use fundamental_data_type::prelude::*;
  ///
  /// /// This is also attribute and macro understands it.
  /// #[ derive( Debug ) ]
  /// pub struct MySingle( pub i32 );
  ///
  /// impl core::ops::Deref for MySingle
  /// {
  ///   type Target = i32;
  ///   fn deref( &self ) -> &Self::Target
  ///   {
  ///     &self.0
  ///   }
  /// }
  /// impl From< i32 > for MySingle
  /// {
  ///   fn from( src : i32 ) -> Self
  ///   {
  ///     Self( src )
  ///   }
  /// }
  /// impl From< MySingle > for i32
  /// {
  ///   fn from( src : MySingle ) -> Self
  ///   {
  ///     src.0
  ///   }
  /// }
  ///
  /// let x = MySingle( 13 );
  /// dbg!( x );
  /// ```
  ///
  /// ### Sample :: single with struct instead of macro.
  ///
  /// Sometimes it's sufficient to use common type instead of defining a brand new.
  /// You may use paramtetrized struct `Single< T >` instead of macro `types!` if that is the case.
  ///
  /// ```rust
  /// use fundamental_data_type::prelude::*;
  /// let x = Single::< i32 >( 13 );
  /// dbg!( x );
  /// ```
  ///
  /// ### Sample :: single with parametrized element.
  ///
  /// Element of tuple could be parametrized.
  ///
  /// ```rust
  /// use fundamental_data_type::prelude::*;
  /// types!
  /// {
  ///   #[ derive( Debug ) ]
  ///   single MySingle : std::sync::Arc< T : Copy >;
  /// }
  /// let x = MySingle( std::sync::Arc::new( 13 ) );
  /// dbg!( x );
  /// ```
  ///
  /// It gererates code:
  ///
  /// ```rust
  /// use fundamental_data_type::*;
  ///
  /// #[ derive( Debug ) ]
  /// pub struct MySingle< T : Copy >( pub std::sync::Arc< T > );
  ///
  /// impl<T: Copy> core::ops::Deref for MySingle< T >
  /// {
  ///   type Target = std::sync::Arc< T >;
  ///   fn deref( &self ) -> &Self::Target
  ///   {
  ///     &self.0
  ///   }
  /// }
  /// impl< T : Copy > From< std::sync::Arc< T > > for MySingle< T >
  /// {
  ///   fn from( src : std::sync::Arc<T>) -> Self {
  ///     Self( src )
  ///   }
  /// }
  /// impl< T : Copy > From< MySingle< T > > for std::sync::Arc< T >
  /// {
  ///   fn from(src: MySingle<T>) -> Self
  ///   {
  ///     src.0
  ///   }
  /// }
  ///
  /// let x = MySingle( std::sync::Arc::new( 13 ) );
  /// ```
  ///
  /// ### Sample :: single with parametrized tuple.
  ///
  /// Instead of parametrizing the element it's possible to define a parametrized tuple.
  ///
  ///
  /// ```rust
  /// use fundamental_data_type::prelude::*;
  /// types!
  /// {
  ///   #[ derive( Debug ) ]
  ///   single MySingle : < T : Copy >;
  /// }
  /// let x = MySingle( 13 );
  /// dbg!( x );
  /// ```
  ///
  /// It gererates code:
  ///
  /// ```rust
  /// #[ derive( Debug ) ]
  /// pub struct MySingle< T : Copy >( pub T );
  ///
  /// impl< T : Copy > core::ops::Deref
  /// for MySingle< T >
  /// {
  ///   type Target = T;
  ///   fn deref( &self ) -> &Self::Target
  ///   {
  ///     &self.0
  ///   }
  /// }
  ///
  /// impl< T : Copy > From< T >
  /// for MySingle< T >
  /// {
  ///   fn from( src : T ) -> Self
  ///   {
  ///     Self( src )
  ///   }
  /// }
  ///
  /// let x = MySingle( 13 );
  /// dbg!( 13 );
  /// ```
  ///

  // #[ doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/Readme.md" ) ) ]

  #[ macro_export ]
  macro_rules! types
  {

    // No more.

    (
    )
    =>
    {
    };

    // No more.

    (
      ;
    )
    =>
    {
    };

    // single

    (
      $( #[ $Meta : meta ] )*
      single
      $( $Rest : tt )*
    )
    =>
    {
      $crate::_single!
      {
        $( #[ $Meta ] )*
        single
        $( $Rest )*
      }
    };

    // pair

    (
      $( #[ $Meta : meta ] )*
      pair
      $( $Rest : tt )*
    )
    =>
    {
      $crate::_pair!
      {
        $( #[ $Meta ] )*
        pair
        $( $Rest )*
      }
    };

    // bad syntax

    (
      $( $Rest : tt )*
    )
    =>
    {
      compile_error!
      (
        concat!
        (
          "Bad syntax.\n",
          "Expects : {kind} {name} : {type}.\n",
          "For example : `single MySingle : std::sync::Arc< T : Copy >`.\n",
          "But got:\n",
          stringify!
          (
            $( $Rest )*
          ),
        )
      );
    };

  }

  pub use types;
}

/// Protected namespace of the module.
pub mod protected
{
  pub use super::orphan::*;
}

pub use protected::*;

/// Orphan namespace of the module.
pub mod orphan
{
  pub use super::exposed::*;
}

/// Exposed namespace of the module.
pub mod exposed
{
  pub use super::prelude::*;
}

pub use exposed::*;

/// Prelude to use: `use wtools::prelude::*`.
pub mod prelude
{
  #[ doc( inline ) ]
  pub use super::internal::
  {
    types,
  };
}
<|endoftext|>


<commit_before>//! Compile time optimized maps and sets.
//!
//! Keys can be string literals, byte string literals, byte literals, char
//! literals, or any of the fixed-size integral types.
#![doc(html_root_url="https://sfackler.github.io/doc")]
#![warn(missing_docs)]
#![feature(macro_rules, tuple_indexing, phase, globs)]
#![no_std]

#[phase(plugin, link)]
extern crate core;
extern crate collections;

pub use shared::PhfHash;
#[doc(inline)]
pub use map::Map;
#[doc(inline)]
pub use set::Set;
#[doc(inline)]
pub use ordered_map::OrderedMap;
#[doc(inline)]
pub use ordered_set::OrderedSet;

#[deprecated = "renamed to Map"]
#[doc(hidden)]
pub use Map as PhfMap;
#[deprecated = "renamed to Set"]
#[doc(hidden)]
pub use Set as PhfSet;
#[deprecated = "renamed to OrderedMap"]
#[doc(hidden)]
pub use OrderedMap as PhfOrderedMap;
#[deprecated = "renamed to OrderedSet"]
#[doc(hidden)]
pub use OrderedSet as PhfOrderedSet;

#[path="../../shared/mod.rs"]
mod shared;
pub mod map;
pub mod set;
pub mod ordered_map;
pub mod ordered_set;

mod std {
    pub use core::fmt;
}

<commit_msg>Remove deprecated reexports<commit_after>//! Compile time optimized maps and sets.
//!
//! Keys can be string literals, byte string literals, byte literals, char
//! literals, or any of the fixed-size integral types.
#![doc(html_root_url="https://sfackler.github.io/doc")]
#![warn(missing_docs)]
#![feature(macro_rules, tuple_indexing, phase, globs)]
#![no_std]

#[phase(plugin, link)]
extern crate core;
extern crate collections;

pub use shared::PhfHash;
#[doc(inline)]
pub use map::Map;
#[doc(inline)]
pub use set::Set;
#[doc(inline)]
pub use ordered_map::OrderedMap;
#[doc(inline)]
pub use ordered_set::OrderedSet;

#[path="../../shared/mod.rs"]
mod shared;
pub mod map;
pub mod set;
pub mod ordered_map;
pub mod ordered_set;

mod std {
    pub use core::fmt;
}

<|endoftext|>


<commit_before>use extra::treemap::TreeMap;
//use headers::Headers;
use std::rt;
use std::rt::io::Writer;

use std::rt::io::net::tcp::TcpStream;

use super::status;
use super::headers;

/**
 * The HTTP version tag which will be used for the response.
 *
 * At present, responses will always respond with `HTTP/1.1`, as there doesn't
 * seem much value in responding HTTP/1.0 when we don't really support it.
 * Others do this too, so there's my justification.
 */
static RESPONSE_HTTP_VERSION: &'static str = "HTTP/1.1";
// Maybe we could provide a response interface

fn to_owned_bytes(s: ~str) -> ~[u8] {
    // XXX: Rust compiler bug(?) prevents me from doing `s.as_bytes().to_owned()` in one step
    let b = s.as_bytes();
    b.to_owned()
}

macro_rules! bfmt (
        ($($expr:expr),*) => (to_owned_bytes(fmt!($($expr),*)))
        )

/*
/**
 * A HTTP Response.
 *
 * - `headers`: A hashmap with the headers to send (Content-type and -length are done seperatley).
 * - `status` - A status code for the response. For now only used for the first lne of the response.
 * /
pub struct Response {
    headers: ~TreeMap<~str, ~str>,
    status: status::Status,
}

impl Response {

    fn init(@mut self) {
        // Default to text/html
        //self.headers = ~TreeMap<~str, ~str>::new();
        self.set_header(~"Content-Type", ~"text/html");
    }

    fn write_status(&self, socket: &TcpSocket) {
        socket.write(to_owned_bytes(fmt!("%s %?\r\n", RESPONSE_HTTP_VERSION, self.status)));
    }

    fn write_headers(&self, socket: &TcpSocket) {
        for self.headers.iter().advance |(key, value)| {
            socket.write(to_owned_bytes(fmt!("%s: %s\r\n", *key, *value)));
        }
        socket.write(to_owned_bytes(~"\r\n"));
    }

    fn set_header<V: ToStr>(@mut self, name: ~str, value: V) {
        // TODO: apply some normalisation to the headers
        self.headers.insert(name, value.to_str());
    }

    fn auto_content_length(@mut self) {
        // Returns true if the key did not already exist in the map, but we don't care
        self.set_header(~"Content-Length", self.content.len());
    }

    /// Write the response to a socket using the HTTP version specified by version_number.
    // TODO: is this different for different versions?
    pub fn write(&self, version_number: (int, int), socket: &TcpSocket) {
        self.write_status(socket);
        self.write_headers(socket);
        socket.write(to_owned_bytes(copy self.content));
    }
}*/

pub struct ResponseWriter {
    // The place to write to (typically a TCP stream, rt::io::net::tcp::TcpStream)
    priv writer: TcpStream,
    priv headers_written: bool,
    headers: ~headers::Headers,
    status: status::Status,
}

impl ResponseWriter {
    /// Create a `ResponseWriter` writing to the specified location
    pub fn new(writer: TcpStream) -> ResponseWriter {
        ResponseWriter {
            writer: writer,
            headers_written: false,
            //headers: headers::Headers::new(),
            headers: ~TreeMap::new(),
            status: status::Ok,
        }
    }

    /// Write a response with the specified Content-Type and content; the Content-Length header is
    /// set based upon the contents
    pub fn write_content_auto(&mut self, content_type: ~str, content: ~str) {
        self.headers.insert(~"Content-Type", content_type);
        let cbytes = content.as_bytes();
        self.headers.insert(~"Content-Length", cbytes.len().to_str());
        self.write_headers();
        self.write(cbytes);
    }

    /// Write the Status-Line and headers of the response, in preparation for writing the body.
    ///
    /// If the headers have already been written, this will fail.
    pub fn write_headers(&mut self) {
        // This marks the beginning of the response (RFC2616 §6)
        if self.headers_written {
            fail!("ResponseWriter.write_headers() called, but headers already written");
        }

        // TODO: compare performance of bfmt!("foo %s", ...) and write(bytes!("foo ")) write(...)
        // (Titchy case, but could be good to get an idea of the perf characteristics; there's an
        // extremely remote possibility it might affect things later.)

        // Write the Status-Line (RFC2616 §6.1)
        // XXX: might be better not to hardcode HTTP/1.1.
        self.writer.write(bfmt!("HTTP/1.1 %s\r\n", self.status.to_str()));

        // Write the miscellaneous varieties of headers
        // XXX: this is not in the slightest bit sufficient; much more filtration is required.
        for self.headers.iter().advance |(name, value)| {
            self.writer.write(bfmt!("%s: %s\r\n", *name, *value));
        }
        self.writer.write(bytes!("\r\n"));
        self.headers_written = true;
    }
}

impl rt::io::Writer for ResponseWriter {

    pub fn write(&mut self, buf: &[u8]) {
        if (!self.headers_written) {
            self.write_headers();
        }
        self.writer.write(buf);
    }

    pub fn flush(&mut self) {
        self.writer.flush();
    }

}
<commit_msg>Remove a little bit of memory allocation and some dead code.<commit_after>use extra::treemap::TreeMap;
//use headers::Headers;
use std::rt;
use std::rt::io::Writer;

use std::rt::io::net::tcp::TcpStream;

use super::status;
use super::headers;

/**
 * The HTTP version tag which will be used for the response.
 *
 * At present, responses will always respond with `HTTP/1.1`, as there doesn't
 * seem much value in responding HTTP/1.0 when we don't really support it.
 * Others do this too, so there's my justification.
 */
static RESPONSE_HTTP_VERSION: &'static str = "HTTP/1.1";
// Maybe we could provide a response interface

pub struct ResponseWriter {
    // The place to write to (typically a TCP stream, rt::io::net::tcp::TcpStream)
    priv writer: TcpStream,
    priv headers_written: bool,
    headers: ~headers::Headers,
    status: status::Status,
}

impl ResponseWriter {
    /// Create a `ResponseWriter` writing to the specified location
    pub fn new(writer: TcpStream) -> ResponseWriter {
        ResponseWriter {
            writer: writer,
            headers_written: false,
            //headers: headers::Headers::new(),
            headers: ~TreeMap::new(),
            status: status::Ok,
        }
    }

    /// Write a response with the specified Content-Type and content; the Content-Length header is
    /// set based upon the contents
    pub fn write_content_auto(&mut self, content_type: ~str, content: ~str) {
        self.headers.insert(~"Content-Type", content_type);
        let cbytes = content.as_bytes();
        self.headers.insert(~"Content-Length", cbytes.len().to_str());
        self.write_headers();
        self.write(cbytes);
    }

    /// Write the Status-Line and headers of the response, in preparation for writing the body.
    ///
    /// If the headers have already been written, this will fail.
    pub fn write_headers(&mut self) {
        // This marks the beginning of the response (RFC2616 §6)
        if self.headers_written {
            fail!("ResponseWriter.write_headers() called, but headers already written");
        }

        // Write the Status-Line (RFC2616 §6.1)
        // XXX: might be better not to hardcode HTTP/1.1.
        // XXX: Rust's current lack of statement-duration lifetime handling prevents this from being
        // one statement ("error: borrowed value does not live long enough")
        let s = fmt!("HTTP/1.1 %s\r\n", self.status.to_str());
        self.writer.write(s.as_bytes());

        // Write the miscellaneous varieties of headers
        // XXX: this is not in the slightest bit sufficient; much more filtration is required.
        for self.headers.iter().advance |(name, value)| {
            let s = fmt!("%s: %s\r\n", *name, *value);
            self.writer.write(s.as_bytes());
        }
        self.writer.write(bytes!("\r\n"));
        self.headers_written = true;
    }
}

impl rt::io::Writer for ResponseWriter {

    pub fn write(&mut self, buf: &[u8]) {
        if (!self.headers_written) {
            self.write_headers();
        }
        self.writer.write(buf);
    }

    pub fn flush(&mut self) {
        self.writer.flush();
    }

}
<|endoftext|>