<commit_before>use std::str;
use std::collections::HashMap;

use rocksdb::{Writable, IteratorMode, Direction, WriteBatch};
use byteorder::{ByteOrder, BigEndian, WriteBytesExt};

use RocksDBIndexStore;
use errors::{RocksDBReadError, RocksDBWriteError};
use document_index::DocRef;
use key_builder::KeyBuilder;
use search::doc_id_set::DocIdSet;

#[derive(Debug)]
pub enum SegmentMergeError {
    TooManyDocs,
    RocksDBReadError(RocksDBReadError),
    RocksDBWriteError(RocksDBWriteError),
}

impl From<RocksDBReadError> for SegmentMergeError {
    fn from(e: RocksDBReadError) -> SegmentMergeError {
        SegmentMergeError::RocksDBReadError(e)
    }
}

impl From<RocksDBWriteError> for SegmentMergeError {
    fn from(e: RocksDBWriteError) -> SegmentMergeError {
        SegmentMergeError::RocksDBWriteError(e)
    }
}

impl From<SegmentMergeError> for String {
    fn from(e: SegmentMergeError) -> String {
        format!("{:?}", e).to_string()
    }
}

impl RocksDBIndexStore {
    fn merge_segment_data(&self, source_segments: &Vec<u32>, dest_segment: u32, doc_ref_mapping: &HashMap<DocRef, u16>) -> Result<(), SegmentMergeError> {
        // Merge the term directories
        // The term directory keys are ordered to be most convenient for retrieving all the segments
        // of for a term/field combination in one go (field/term/segment). So we don't end up pulling
        // in a lot of unwanted data, we firstly iterate the keys, it they one of the source segments
        // looking for then we load them and append them to our new segment.

        /// Converts term directory key strings "d1/2/3" into tuples of 3 i32s (1, 2, 3)
        fn parse_term_directory_key(key: &[u8]) -> (u32, u32, u32) {
            let mut nums_iter = key[1..].split(|b| *b == b'/').map(|s| str::from_utf8(s).unwrap().parse::<u32>().unwrap());
            (nums_iter.next().unwrap(), nums_iter.next().unwrap(), nums_iter.next().unwrap())
        }

        let mut current_td_key: Option<(u32, u32)> = None;
        let mut current_td = Vec::new();

        for k in self.db.keys_iterator(IteratorMode::From(b"d", Direction::Forward)) {
            if k[0] != b'd' {
                // No more term directories to merge
                break;
            }

            let (field, term, segment) = parse_term_directory_key(&k);

            if !source_segments.contains(&segment) {
                continue;
            }

            if current_td_key != Some((field, term)) {
                // Finished current term directory. Write it to the DB and start the next one
                if let Some((field, term)) = current_td_key {
                    let kb = KeyBuilder::segment_dir_list(dest_segment, field, term);
                    if let Err(e) = self.db.put(&kb.key(), &current_td) {
                        return Err(RocksDBWriteError::new_put(kb.key().to_vec(), e).into());
                    }
                    current_td.clear();
                }

                current_td_key = Some((field, term));
            }

            // Merge term directory into the new one (and remap the doc ids)
            match self.db.get(&k) {
                Ok(Some(docid_set)) => {
                    for doc_id in DocIdSet::FromRDB(docid_set).iter() {
                        let doc_ref = DocRef::from_segment_ord(segment, doc_id);
                        let new_doc_id = doc_ref_mapping.get(&doc_ref).unwrap();
                        current_td.write_u16::<BigEndian>(*new_doc_id).unwrap();
                    }
                }
                Ok(None) => {},  // FIXME
                Err(e) => return Err(RocksDBReadError::new(k.to_vec(), e).into())
            }
        }

        // All done, write the last term directory
        if let Some((field, term)) = current_td_key {
            let kb = KeyBuilder::segment_dir_list(dest_segment, field, term);
            if let Err(e) = self.db.put(&kb.key(), &current_td) {
                return Err(RocksDBWriteError::new_put(kb.key().to_vec(), e).into());
            }
            current_td.clear();
        }

        // Merge the stored values
        // All stored value keys start with the segment id. So we need to:
        // - Iterate all stored value keys that are prefixed by one of the stored segment ids
        // - Remap their doc ids to the one in the new segment
        // - Write the value back with the new segment/doc ids in the key

        /// Converts stored value key strings "v1/2/3/v" into tuples of 3 i32s and a Vec<u8> (1, 2, 3, vec![b'v', b'a', b'l'])
        fn parse_stored_value_key(key: &[u8]) -> (u32, u32, u32, Vec<u8>) {
            let mut parts_iter = key[1..].split(|b| *b == b'/');
            let segment = str::from_utf8(parts_iter.next().unwrap()).unwrap().parse::<u32>().unwrap();
            let doc_id = str::from_utf8(parts_iter.next().unwrap()).unwrap().parse::<u32>().unwrap();
            let field_ord = str::from_utf8(parts_iter.next().unwrap()).unwrap().parse::<u32>().unwrap();
            let value_type = parts_iter.next().unwrap().to_vec();

            (segment, doc_id, field_ord, value_type)
        }

        for source_segment in source_segments.iter() {
            let kb = KeyBuilder::segment_stored_values_prefix(*source_segment);
            for (k, v) in self.db.iterator(IteratorMode::From(&kb.key(), Direction::Forward)) {
                if k[0] != b'v' {
                    // No more stored values to move
                    break;
                }

                let (segment, doc_id, field, value_type) = parse_stored_value_key(&k);

                if segment != *source_segment {
                    // Segment finished
                    break;
                }

                // Remap doc id
                let doc_ref = DocRef::from_segment_ord(segment, doc_id as u16);
                let new_doc_id = doc_ref_mapping.get(&doc_ref).unwrap();

                // Write value into new segment
                let kb = KeyBuilder::stored_field_value(dest_segment, *new_doc_id, field, &value_type);
                if let Err(e) = self.db.put(&kb.key(), &v) {
                    return Err(RocksDBWriteError::new_put(kb.key().to_vec(), e).into());
                }
            }
        }

        // Merge the statistics
        // Like stored values, these start with segment ids. But instead of just rewriting the
        // key, we need to sum up all the statistics across the segments being merged.

        let mut statistics = HashMap::new();

        /// Converts statistic key strings "s1/total_docs" into tuples of 1 i32 and a Vec<u8> (1, ['t', 'o', 't', ...])
        fn parse_statistic_key(key: &[u8]) -> (u32, Vec<u8>) {
            let mut parts_iter = key[1..].split(|b| *b == b'/');
            let segment = str::from_utf8(parts_iter.next().unwrap()).unwrap().parse::<u32>().unwrap();
            let statistic_name = parts_iter.next().unwrap().to_vec();

            (segment, statistic_name)
        }

        // Fetch and merge statistics
        for source_segment in source_segments.iter() {
            let kb = KeyBuilder::segment_stat_prefix(*source_segment);
            for (k, v) in self.db.iterator(IteratorMode::From(&kb.key(), Direction::Forward)) {
                if k[0] != b's' {
                    // No more statistics to merge
                    break;
                }

                let (segment, statistic_name) = parse_statistic_key(&k);

                if segment != *source_segment {
                    // Segment finished
                    break;
                }

                let mut stat = statistics.entry(statistic_name).or_insert(0);
                *stat += BigEndian::read_i64(&v);
            }
        }

        // Write merged statistics to new segment
        for (stat_name, stat_value) in statistics {
            let kb = KeyBuilder::segment_stat(dest_segment, &stat_name);
            let mut val_bytes = [0; 8];
            BigEndian::write_i64(&mut val_bytes, stat_value);
            if let Err(e) = self.db.put(&kb.key(), &val_bytes) {
                return Err(RocksDBWriteError::new_put(kb.key().to_vec(), e).into());
            }
        }

        // Note: Don't merge the deletion lists
        // Deletion lists can change at any time so we must lock the "document index"
        // before merging them so they can't be altered during merge. we cannot lock
        // this until the commit phase though.

        Ok(())
    }

    fn commit_segment_merge(&self, source_segments: &Vec<u32>, dest_segment: u32, doc_ref_mapping: &HashMap<DocRef, u16>) -> Result<(), SegmentMergeError> {
        let write_batch = WriteBatch::default();

        // Activate new segment
        let kb = KeyBuilder::segment_active(dest_segment);
        if let Err(e) = write_batch.put(&kb.key(), b"") {
            return Err(RocksDBWriteError::new_put(kb.key().to_vec(), e).into());
        }

        // Deactivate old segments
        for source_segment in source_segments.iter() {
            // Activate new segment
            let kb = KeyBuilder::segment_active(*source_segment);
            if let Err(e) = write_batch.delete(&kb.key()) {
                return Err(RocksDBWriteError::new_delete(kb.key().to_vec(), e).into());
            }
        }

        // Update document index and commit
        // This will write the write batch
        try!(self.document_index.commit_segment_merge(&self.db, write_batch, source_segments, dest_segment, doc_ref_mapping));

        Ok(())
    }

    pub fn merge_segments(&self, source_segments: Vec<u32>) -> Result<u32, SegmentMergeError> {
        let dest_segment = try!(self.segments.new_segment(&self.db));

        // Generate a mapping between the ids of the documents in the old segments to the new one
        // This packs the id spaces of the old segments together:
        // For example, say we have to merge 3 segments with 100 documents each:
        //  - The first segment's ids will be the same as before
        //  - The second segment's ids will be remapped to 100 - 199
        //  - The third segment's ids will be remapped to 200 - 299

        let mut doc_ref_mapping: HashMap<DocRef, u16> = HashMap::new();
        let mut current_ord: u32 = 0;

        for source_segment in source_segments.iter() {
            let kb = KeyBuilder::segment_stat(*source_segment, b"total_docs");
            let total_docs = match self.db.get(&kb.key()) {
                Ok(Some(total_docs_bytes)) => {
                    BigEndian::read_i64(&total_docs_bytes)
                }
                Ok(None) => continue,
                Err(e) => return Err(RocksDBReadError::new(kb.key().to_vec(), e).into())
            };

            for source_ord in 0..total_docs {
                if current_ord >= 65536 {
                    return Err(SegmentMergeError::TooManyDocs);
                }

                let from = DocRef::from_segment_ord(*source_segment, source_ord as u16);
                doc_ref_mapping.insert(from, current_ord as u16);
                current_ord += 1;
            }
        }

        // Merge segment data
        // Most of the heavy lifting happens here. This merges all the immutable parts of
        // the segment (which is everything but the deletion list). It does not activate the
        // segment.
        // This means that nothing bad will happen if it crashes half way through -- the
        // worst that could happen is we're left with a partially-written segment that we
        // have to clean up.
        try!(self.merge_segment_data(&source_segments, dest_segment, &doc_ref_mapping));

        // Commit the merge
        // This activates the new segment and updates the document index. Effectively committing
        // the merge.
        // Throughout this stage we need an exclusive lock to the document index. This is to
        // prevent documents in the source segments being deleted/updated so we don't accidentally
        // undelete them (this will block until the merge is complete so they delete/update from
        // the new segment).
        try!(self.commit_segment_merge(&source_segments, dest_segment, &doc_ref_mapping));

        Ok(dest_segment)
    }
}
<commit_msg>Store merge segment ids in BTreeSet for better contains lookup performance<commit_after>use std::str;
use std::collections::{HashMap, BTreeSet};

use rocksdb::{Writable, IteratorMode, Direction, WriteBatch};
use byteorder::{ByteOrder, BigEndian, WriteBytesExt};

use RocksDBIndexStore;
use errors::{RocksDBReadError, RocksDBWriteError};
use document_index::DocRef;
use key_builder::KeyBuilder;
use search::doc_id_set::DocIdSet;

#[derive(Debug)]
pub enum SegmentMergeError {
    TooManyDocs,
    RocksDBReadError(RocksDBReadError),
    RocksDBWriteError(RocksDBWriteError),
}

impl From<RocksDBReadError> for SegmentMergeError {
    fn from(e: RocksDBReadError) -> SegmentMergeError {
        SegmentMergeError::RocksDBReadError(e)
    }
}

impl From<RocksDBWriteError> for SegmentMergeError {
    fn from(e: RocksDBWriteError) -> SegmentMergeError {
        SegmentMergeError::RocksDBWriteError(e)
    }
}

impl From<SegmentMergeError> for String {
    fn from(e: SegmentMergeError) -> String {
        format!("{:?}", e).to_string()
    }
}

impl RocksDBIndexStore {
    fn merge_segment_data(&self, source_segments: &Vec<u32>, dest_segment: u32, doc_ref_mapping: &HashMap<DocRef, u16>) -> Result<(), SegmentMergeError> {
        // Put source_segments in a BTreeSet as this is much faster for performing contains queries against
        let source_segments_btree = source_segments.iter().collect::<BTreeSet<_>>();

        // Merge the term directories
        // The term directory keys are ordered to be most convenient for retrieving all the segments
        // of for a term/field combination in one go (field/term/segment). So we don't end up pulling
        // in a lot of unwanted data, we firstly iterate the keys, it they one of the source segments
        // looking for then we load them and append them to our new segment.

        /// Converts term directory key strings "d1/2/3" into tuples of 3 i32s (1, 2, 3)
        fn parse_term_directory_key(key: &[u8]) -> (u32, u32, u32) {
            let mut nums_iter = key[1..].split(|b| *b == b'/').map(|s| str::from_utf8(s).unwrap().parse::<u32>().unwrap());
            (nums_iter.next().unwrap(), nums_iter.next().unwrap(), nums_iter.next().unwrap())
        }

        let mut current_td_key: Option<(u32, u32)> = None;
        let mut current_td = Vec::new();

        for k in self.db.keys_iterator(IteratorMode::From(b"d", Direction::Forward)) {
            if k[0] != b'd' {
                // No more term directories to merge
                break;
            }

            let (field, term, segment) = parse_term_directory_key(&k);

            if !source_segments_btree.contains(&segment) {
                continue;
            }

            if current_td_key != Some((field, term)) {
                // Finished current term directory. Write it to the DB and start the next one
                if let Some((field, term)) = current_td_key {
                    let kb = KeyBuilder::segment_dir_list(dest_segment, field, term);
                    if let Err(e) = self.db.put(&kb.key(), &current_td) {
                        return Err(RocksDBWriteError::new_put(kb.key().to_vec(), e).into());
                    }
                    current_td.clear();
                }

                current_td_key = Some((field, term));
            }

            // Merge term directory into the new one (and remap the doc ids)
            match self.db.get(&k) {
                Ok(Some(docid_set)) => {
                    for doc_id in DocIdSet::FromRDB(docid_set).iter() {
                        let doc_ref = DocRef::from_segment_ord(segment, doc_id);
                        let new_doc_id = doc_ref_mapping.get(&doc_ref).unwrap();
                        current_td.write_u16::<BigEndian>(*new_doc_id).unwrap();
                    }
                }
                Ok(None) => {},  // FIXME
                Err(e) => return Err(RocksDBReadError::new(k.to_vec(), e).into())
            }
        }

        // All done, write the last term directory
        if let Some((field, term)) = current_td_key {
            let kb = KeyBuilder::segment_dir_list(dest_segment, field, term);
            if let Err(e) = self.db.put(&kb.key(), &current_td) {
                return Err(RocksDBWriteError::new_put(kb.key().to_vec(), e).into());
            }
            current_td.clear();
        }

        // Merge the stored values
        // All stored value keys start with the segment id. So we need to:
        // - Iterate all stored value keys that are prefixed by one of the stored segment ids
        // - Remap their doc ids to the one in the new segment
        // - Write the value back with the new segment/doc ids in the key

        /// Converts stored value key strings "v1/2/3/v" into tuples of 3 i32s and a Vec<u8> (1, 2, 3, vec![b'v', b'a', b'l'])
        fn parse_stored_value_key(key: &[u8]) -> (u32, u32, u32, Vec<u8>) {
            let mut parts_iter = key[1..].split(|b| *b == b'/');
            let segment = str::from_utf8(parts_iter.next().unwrap()).unwrap().parse::<u32>().unwrap();
            let doc_id = str::from_utf8(parts_iter.next().unwrap()).unwrap().parse::<u32>().unwrap();
            let field_ord = str::from_utf8(parts_iter.next().unwrap()).unwrap().parse::<u32>().unwrap();
            let value_type = parts_iter.next().unwrap().to_vec();

            (segment, doc_id, field_ord, value_type)
        }

        for source_segment in source_segments.iter() {
            let kb = KeyBuilder::segment_stored_values_prefix(*source_segment);
            for (k, v) in self.db.iterator(IteratorMode::From(&kb.key(), Direction::Forward)) {
                if k[0] != b'v' {
                    // No more stored values to move
                    break;
                }

                let (segment, doc_id, field, value_type) = parse_stored_value_key(&k);

                if segment != *source_segment {
                    // Segment finished
                    break;
                }

                // Remap doc id
                let doc_ref = DocRef::from_segment_ord(segment, doc_id as u16);
                let new_doc_id = doc_ref_mapping.get(&doc_ref).unwrap();

                // Write value into new segment
                let kb = KeyBuilder::stored_field_value(dest_segment, *new_doc_id, field, &value_type);
                if let Err(e) = self.db.put(&kb.key(), &v) {
                    return Err(RocksDBWriteError::new_put(kb.key().to_vec(), e).into());
                }
            }
        }

        // Merge the statistics
        // Like stored values, these start with segment ids. But instead of just rewriting the
        // key, we need to sum up all the statistics across the segments being merged.

        let mut statistics = HashMap::new();

        /// Converts statistic key strings "s1/total_docs" into tuples of 1 i32 and a Vec<u8> (1, ['t', 'o', 't', ...])
        fn parse_statistic_key(key: &[u8]) -> (u32, Vec<u8>) {
            let mut parts_iter = key[1..].split(|b| *b == b'/');
            let segment = str::from_utf8(parts_iter.next().unwrap()).unwrap().parse::<u32>().unwrap();
            let statistic_name = parts_iter.next().unwrap().to_vec();

            (segment, statistic_name)
        }

        // Fetch and merge statistics
        for source_segment in source_segments.iter() {
            let kb = KeyBuilder::segment_stat_prefix(*source_segment);
            for (k, v) in self.db.iterator(IteratorMode::From(&kb.key(), Direction::Forward)) {
                if k[0] != b's' {
                    // No more statistics to merge
                    break;
                }

                let (segment, statistic_name) = parse_statistic_key(&k);

                if segment != *source_segment {
                    // Segment finished
                    break;
                }

                let mut stat = statistics.entry(statistic_name).or_insert(0);
                *stat += BigEndian::read_i64(&v);
            }
        }

        // Write merged statistics to new segment
        for (stat_name, stat_value) in statistics {
            let kb = KeyBuilder::segment_stat(dest_segment, &stat_name);
            let mut val_bytes = [0; 8];
            BigEndian::write_i64(&mut val_bytes, stat_value);
            if let Err(e) = self.db.put(&kb.key(), &val_bytes) {
                return Err(RocksDBWriteError::new_put(kb.key().to_vec(), e).into());
            }
        }

        // Note: Don't merge the deletion lists
        // Deletion lists can change at any time so we must lock the "document index"
        // before merging them so they can't be altered during merge. we cannot lock
        // this until the commit phase though.

        Ok(())
    }

    fn commit_segment_merge(&self, source_segments: &Vec<u32>, dest_segment: u32, doc_ref_mapping: &HashMap<DocRef, u16>) -> Result<(), SegmentMergeError> {
        let write_batch = WriteBatch::default();

        // Activate new segment
        let kb = KeyBuilder::segment_active(dest_segment);
        if let Err(e) = write_batch.put(&kb.key(), b"") {
            return Err(RocksDBWriteError::new_put(kb.key().to_vec(), e).into());
        }

        // Deactivate old segments
        for source_segment in source_segments.iter() {
            // Activate new segment
            let kb = KeyBuilder::segment_active(*source_segment);
            if let Err(e) = write_batch.delete(&kb.key()) {
                return Err(RocksDBWriteError::new_delete(kb.key().to_vec(), e).into());
            }
        }

        // Update document index and commit
        // This will write the write batch
        try!(self.document_index.commit_segment_merge(&self.db, write_batch, source_segments, dest_segment, doc_ref_mapping));

        Ok(())
    }

    pub fn merge_segments(&self, source_segments: Vec<u32>) -> Result<u32, SegmentMergeError> {
        let dest_segment = try!(self.segments.new_segment(&self.db));

        // Generate a mapping between the ids of the documents in the old segments to the new one
        // This packs the id spaces of the old segments together:
        // For example, say we have to merge 3 segments with 100 documents each:
        //  - The first segment's ids will be the same as before
        //  - The second segment's ids will be remapped to 100 - 199
        //  - The third segment's ids will be remapped to 200 - 299

        let mut doc_ref_mapping: HashMap<DocRef, u16> = HashMap::new();
        let mut current_ord: u32 = 0;

        for source_segment in source_segments.iter() {
            let kb = KeyBuilder::segment_stat(*source_segment, b"total_docs");
            let total_docs = match self.db.get(&kb.key()) {
                Ok(Some(total_docs_bytes)) => {
                    BigEndian::read_i64(&total_docs_bytes)
                }
                Ok(None) => continue,
                Err(e) => return Err(RocksDBReadError::new(kb.key().to_vec(), e).into())
            };

            for source_ord in 0..total_docs {
                if current_ord >= 65536 {
                    return Err(SegmentMergeError::TooManyDocs);
                }

                let from = DocRef::from_segment_ord(*source_segment, source_ord as u16);
                doc_ref_mapping.insert(from, current_ord as u16);
                current_ord += 1;
            }
        }

        // Merge segment data
        // Most of the heavy lifting happens here. This merges all the immutable parts of
        // the segment (which is everything but the deletion list). It does not activate the
        // segment.
        // This means that nothing bad will happen if it crashes half way through -- the
        // worst that could happen is we're left with a partially-written segment that we
        // have to clean up.
        try!(self.merge_segment_data(&source_segments, dest_segment, &doc_ref_mapping));

        // Commit the merge
        // This activates the new segment and updates the document index. Effectively committing
        // the merge.
        // Throughout this stage we need an exclusive lock to the document index. This is to
        // prevent documents in the source segments being deleted/updated so we don't accidentally
        // undelete them (this will block until the merge is complete so they delete/update from
        // the new segment).
        try!(self.commit_segment_merge(&source_segments, dest_segment, &doc_ref_mapping));

        Ok(dest_segment)
    }
}
<|endoftext|>


<commit_before>use std;

use bits;
use system::{SystemParams, P25Params};

/// Yields a series of scaled impulses vs time corresponding to given dibits.
pub struct C4FMImpulse<T, S: SystemParams> {
    system: std::marker::PhantomData<S>,
    /// The dibit source to iterate over.
    src: T,
    /// Current global sample index.
    sample: usize,
}

impl<T, S = P25Params> C4FMImpulse<T, S> where
    T: Iterator<Item = bits::Dibit>,
    S: SystemParams
{
    /// Construct a new `C4FMImpulse<T>` from the given source and sample rate.
    pub fn new(src: T) -> C4FMImpulse<T, S> {
        C4FMImpulse {
            system: std::marker::PhantomData,
            src: src,
            sample: 0,
        }
    }
}

impl<T, S> Iterator for C4FMImpulse<T, S> where
    T: Iterator<Item = bits::Dibit>,
    S: SystemParams
{
    type Item = f64;

    fn next(&mut self) -> Option<Self::Item> {
        // Store current sample and move to the next.
        let s = self.sample;
        self.sample += 1;

        // Impulse is only output at the beginning of a symbol period.
        if s % S::period() != 0 {
            return Some(0.0);
        }

        // Map the current dibit to a scaled impulse.
        if let Some(dibit) = self.src.next() {
            match dibit {
                bits::Dibit(0b01) => Some(1800.0),
                bits::Dibit(0b00) => Some(600.0),
                bits::Dibit(0b10) => Some(-600.0),
                bits::Dibit(0b11) => Some(-1800.0),
                _ => panic!("invalid dibit encountered"),
            }
        } else {
            None
        }
    }
}

/// Generates the alternating series of dibits used for the C4FM deviation test. The
/// resulting filtered waveform approximates a 1200Hz sine wave.
pub struct C4FMDeviationDibits {
    /// Used to alternate dibits.
    idx: usize,
}

impl C4FMDeviationDibits {
    /// Construct a new `C4FMDeviationDibits`.
    pub fn new() -> C4FMDeviationDibits {
        C4FMDeviationDibits {
            idx: 0,
        }
    }
}

impl Iterator for C4FMDeviationDibits {
    type Item = bits::Dibit;

    fn next(&mut self) -> Option<Self::Item> {
        let idx = self.idx;

        self.idx += 1;
        self.idx %= 4;

        Some(if idx < 2 {
            bits::Dibit(0b01)
        } else {
            bits::Dibit(0b11)
        })
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use super::super::bits;

    #[test]
    fn test_impulses() {
        const BITS: &'static [u8] = &[
            0b00011011,
        ];

        let d = bits::Dibits::new(BITS.iter().cloned());
        let mut imp = C4FMImpulse::new(d);

        assert!(imp.next().unwrap() == 600.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 1800.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == -600.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == -1800.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().is_none());
    }

    #[test]
    fn test_deviation() {
        let mut d = C4FMDeviationDibits::new();

        assert!(d.next().unwrap().0 == 0b01);
        assert!(d.next().unwrap().0 == 0b01);
        assert!(d.next().unwrap().0 == 0b11);
        assert!(d.next().unwrap().0 == 0b11);
        assert!(d.next().unwrap().0 == 0b01);
        assert!(d.next().unwrap().0 == 0b01);
        assert!(d.next().unwrap().0 == 0b11);
        assert!(d.next().unwrap().0 == 0b11);
    }
}
<commit_msg>Use unreachable!<commit_after>use std;

use bits;
use system::{SystemParams, P25Params};

/// Yields a series of scaled impulses vs time corresponding to given dibits.
pub struct C4FMImpulse<T, S: SystemParams> {
    system: std::marker::PhantomData<S>,
    /// The dibit source to iterate over.
    src: T,
    /// Current global sample index.
    sample: usize,
}

impl<T, S = P25Params> C4FMImpulse<T, S> where
    T: Iterator<Item = bits::Dibit>,
    S: SystemParams
{
    /// Construct a new `C4FMImpulse<T>` from the given source and sample rate.
    pub fn new(src: T) -> C4FMImpulse<T, S> {
        C4FMImpulse {
            system: std::marker::PhantomData,
            src: src,
            sample: 0,
        }
    }
}

impl<T, S> Iterator for C4FMImpulse<T, S> where
    T: Iterator<Item = bits::Dibit>,
    S: SystemParams
{
    type Item = f64;

    fn next(&mut self) -> Option<Self::Item> {
        // Store current sample and move to the next.
        let s = self.sample;
        self.sample += 1;

        // Impulse is only output at the beginning of a symbol period.
        if s % S::period() != 0 {
            return Some(0.0);
        }

        // Map the current dibit to a scaled impulse.
        if let Some(dibit) = self.src.next() {
            match dibit {
                bits::Dibit(0b01) => Some(1800.0),
                bits::Dibit(0b00) => Some(600.0),
                bits::Dibit(0b10) => Some(-600.0),
                bits::Dibit(0b11) => Some(-1800.0),
                _ => unreachable!(),
            }
        } else {
            None
        }
    }
}

/// Generates the alternating series of dibits used for the C4FM deviation test. The
/// resulting filtered waveform approximates a 1200Hz sine wave.
pub struct C4FMDeviationDibits {
    /// Used to alternate dibits.
    idx: usize,
}

impl C4FMDeviationDibits {
    /// Construct a new `C4FMDeviationDibits`.
    pub fn new() -> C4FMDeviationDibits {
        C4FMDeviationDibits {
            idx: 0,
        }
    }
}

impl Iterator for C4FMDeviationDibits {
    type Item = bits::Dibit;

    fn next(&mut self) -> Option<Self::Item> {
        let idx = self.idx;

        self.idx += 1;
        self.idx %= 4;

        Some(if idx < 2 {
            bits::Dibit(0b01)
        } else {
            bits::Dibit(0b11)
        })
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use super::super::bits;

    #[test]
    fn test_impulses() {
        const BITS: &'static [u8] = &[
            0b00011011,
        ];

        let d = bits::Dibits::new(BITS.iter().cloned());
        let mut imp = C4FMImpulse::new(d);

        assert!(imp.next().unwrap() == 600.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 1800.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == -600.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == -1800.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().is_none());
    }

    #[test]
    fn test_deviation() {
        let mut d = C4FMDeviationDibits::new();

        assert!(d.next().unwrap().0 == 0b01);
        assert!(d.next().unwrap().0 == 0b01);
        assert!(d.next().unwrap().0 == 0b11);
        assert!(d.next().unwrap().0 == 0b11);
        assert!(d.next().unwrap().0 == 0b01);
        assert!(d.next().unwrap().0 == 0b01);
        assert!(d.next().unwrap().0 == 0b11);
        assert!(d.next().unwrap().0 == 0b11);
    }
}
<|endoftext|>


<commit_before>extern crate libcratesio;

use libcratesio::Crate;

#[test]
fn basic_data() {
    let krate = Crate::by_name("requests").unwrap();
    println!("{:?}", krate);
    assert_eq!(krate.name, "requests");
}

#[test]
fn raw_data() {
    let krate = Crate::json_data("requests").unwrap();
    println!("{:#?}", krate);
    assert!(true);
}

#[test]
fn versions_iter() {
    let krate = Crate::by_name("requests").unwrap();
    for ver in krate.versions.iter() {
        println!("{:?}", ver);
    }
    assert!(true);
}
<commit_msg>Add error test boilerplate<commit_after>extern crate libcratesio;

use libcratesio::{Crate, Error};

#[test]
fn basic_data() {
    let krate = Crate::by_name("requests").unwrap();
    println!("{:?}", krate);
    assert_eq!(krate.name, "requests");
}

#[test]
fn raw_data() {
    let krate = Crate::json_data("requests").unwrap();
    println!("{:#?}", krate);
    assert!(true);
}

#[test]
fn versions_iter() {
    let krate = Crate::by_name("requests").unwrap();
    for ver in krate.versions.iter() {
        println!("{:?}", ver);
    }
    assert!(true);
}

#[test]
fn error() {
    let err = Crate::by_name("xxx").unwrap_err();
    println!("{:?}", err);
    assert!(true);
}
<|endoftext|>


<commit_before>#![cfg(unix)]

extern crate curl;
extern crate mio;

use std::collections::HashMap;
use std::io::{Read, Cursor};
use std::time::Duration;

use curl::easy::{Easy, List};
use curl::multi::Multi;

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed with {:?}", stringify!($e), e),
    })
}

use server::Server;
mod server;

#[test]
fn smoke() {
    let m = Multi::new();
    let mut e = Easy::new();

    let s = Server::new();
    s.receive("\
GET / HTTP/1.1\r\n\
Host: 127.0.0.1:$PORT\r\n\
Accept: */*\r\n\
\r\n");
    s.send("HTTP/1.1 200 OK\r\n\r\n");

    t!(e.url(&s.url("/")));
    let _e = t!(m.add(e));
    while t!(m.perform()) > 0 {
        // ...
    }
}

#[test]
fn smoke2() {
    let m = Multi::new();

    let s1 = Server::new();
    s1.receive("\
GET / HTTP/1.1\r\n\
Host: 127.0.0.1:$PORT\r\n\
Accept: */*\r\n\
\r\n");
    s1.send("HTTP/1.1 200 OK\r\n\r\n");

    let s2 = Server::new();
    s2.receive("\
GET / HTTP/1.1\r\n\
Host: 127.0.0.1:$PORT\r\n\
Accept: */*\r\n\
\r\n");
    s2.send("HTTP/1.1 200 OK\r\n\r\n");

    let mut e1 = Easy::new();
    t!(e1.url(&s1.url("/")));
    let _e1 = t!(m.add(e1));
    let mut e2 = Easy::new();
    t!(e2.url(&s2.url("/")));
    let _e2 = t!(m.add(e2));

    while t!(m.perform()) > 0 {
        // ...
    }

    let mut done = 0;
    m.messages(|msg| {
        msg.result().unwrap().unwrap();
        done += 1;
    });
    assert_eq!(done, 2);
}

#[test]
fn upload_lots() {
    use curl::multi::{Socket, SocketEvents, Events};

    #[derive(Debug)]
    enum Message {
        Timeout(Option<Duration>),
        Wait(Socket, SocketEvents, usize),
    }

    let mut m = Multi::new();
    let poll = t!(mio::Poll::new());
    let (tx, rx) = mio::channel::channel();
    let tx2 = tx.clone();
    t!(m.socket_function(move |socket, events, token| {
        t!(tx2.send(Message::Wait(socket, events, token)));
    }));
    t!(m.timer_function(move |dur| {
        t!(tx.send(Message::Timeout(dur)));
        true
    }));

    let s = Server::new();
    s.receive(&format!("\
PUT / HTTP/1.1\r\n\
Host: 127.0.0.1:$PORT\r\n\
Accept: */*\r\n\
Content-Length: 131072\r\n\
\r\n\
{}\n", vec!["a"; 128 * 1024 - 1].join("")));
    s.send("\
HTTP/1.1 200 OK\r\n\
\r\n");

    let mut data = vec![b'a'; 128 * 1024 - 1];
    data.push(b'\n');
    let mut data = Cursor::new(data);
    let mut list = List::new();
    t!(list.append("Expect:"));
    let mut h = Easy::new();
    t!(h.url(&s.url("/")));
    t!(h.put(true));
    t!(h.read_function(move |buf| {
        Ok(data.read(buf).unwrap())
    }));
    t!(h.in_filesize(128 * 1024));
    t!(h.upload(true));
    t!(h.http_headers(list));

    t!(poll.register(&rx,
                     mio::Token(0),
                     mio::Ready::all(),
                     mio::PollOpt::level()));

    let e = t!(m.add(h));

    assert!(t!(m.perform()) > 0);
    let mut next_token = 1;
    let mut token_map = HashMap::new();
    let mut cur_timeout = None;
    let mut events = mio::Events::with_capacity(128);
    let mut running = true;

    while running {
        let n = t!(poll.poll(&mut events, cur_timeout));

        if n == 0 {
            if t!(m.timeout()) == 0 {
                running = false;
            }
        }

        for event in events.iter() {
            while event.token() == mio::Token(0) {
                match rx.try_recv() {
                    Ok(Message::Timeout(dur)) => cur_timeout = dur,
                    Ok(Message::Wait(socket, events, token)) => {
                        let evented = mio::unix::EventedFd(&socket);
                        if events.remove() {
                            t!(poll.deregister(&evented));
                            token_map.remove(&token).unwrap();
                        } else {
                            let mut e = mio::Ready::none();
                            if events.input() {
                                e = e | mio::Ready::readable();
                            }
                            if events.output() {
                                e = e | mio::Ready::writable();
                            }
                            if token == 0 {
                                let token = next_token;
                                next_token += 1;
                                t!(m.assign(socket, token));
                                token_map.insert(token, socket);
                                t!(poll.register(&evented,
                                                 mio::Token(token),
                                                 e,
                                                 mio::PollOpt::level()));
                            } else {
                                t!(poll.reregister(&evented,
                                                   mio::Token(token),
                                                   e,
                                                   mio::PollOpt::level()));
                            }
                        }
                    }
                    Err(_) => break,
                }
            }

            if event.token() == mio::Token(0) {
                continue
            }

            let token = event.token();
            let socket = token_map[&token.into()];
            let mut e = Events::new();
            if event.kind().is_readable() {
                e.input(true);
            }
            if event.kind().is_writable() {
                e.output(true);
            }
            if event.kind().is_error() {
                e.error(true);
            }
            let remaining = t!(m.action(socket, &e));
            if remaining == 0 {
                running = false;
            }
        }
    }

    let mut done = 0;
    m.messages(|m| {
        m.result().unwrap().unwrap();
        done += 1;
    });
    assert_eq!(done, 1);

    let mut e = t!(m.remove(e));
    assert_eq!(t!(e.response_code()), 200);
}
<commit_msg>Let closing fds do deregistering<commit_after>#![cfg(unix)]

extern crate curl;
extern crate mio;

use std::collections::HashMap;
use std::io::{Read, Cursor};
use std::time::Duration;

use curl::easy::{Easy, List};
use curl::multi::Multi;

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed with {:?}", stringify!($e), e),
    })
}

use server::Server;
mod server;

#[test]
fn smoke() {
    let m = Multi::new();
    let mut e = Easy::new();

    let s = Server::new();
    s.receive("\
GET / HTTP/1.1\r\n\
Host: 127.0.0.1:$PORT\r\n\
Accept: */*\r\n\
\r\n");
    s.send("HTTP/1.1 200 OK\r\n\r\n");

    t!(e.url(&s.url("/")));
    let _e = t!(m.add(e));
    while t!(m.perform()) > 0 {
        // ...
    }
}

#[test]
fn smoke2() {
    let m = Multi::new();

    let s1 = Server::new();
    s1.receive("\
GET / HTTP/1.1\r\n\
Host: 127.0.0.1:$PORT\r\n\
Accept: */*\r\n\
\r\n");
    s1.send("HTTP/1.1 200 OK\r\n\r\n");

    let s2 = Server::new();
    s2.receive("\
GET / HTTP/1.1\r\n\
Host: 127.0.0.1:$PORT\r\n\
Accept: */*\r\n\
\r\n");
    s2.send("HTTP/1.1 200 OK\r\n\r\n");

    let mut e1 = Easy::new();
    t!(e1.url(&s1.url("/")));
    let _e1 = t!(m.add(e1));
    let mut e2 = Easy::new();
    t!(e2.url(&s2.url("/")));
    let _e2 = t!(m.add(e2));

    while t!(m.perform()) > 0 {
        // ...
    }

    let mut done = 0;
    m.messages(|msg| {
        msg.result().unwrap().unwrap();
        done += 1;
    });
    assert_eq!(done, 2);
}

#[test]
fn upload_lots() {
    use curl::multi::{Socket, SocketEvents, Events};

    #[derive(Debug)]
    enum Message {
        Timeout(Option<Duration>),
        Wait(Socket, SocketEvents, usize),
    }

    let mut m = Multi::new();
    let poll = t!(mio::Poll::new());
    let (tx, rx) = mio::channel::channel();
    let tx2 = tx.clone();
    t!(m.socket_function(move |socket, events, token| {
        t!(tx2.send(Message::Wait(socket, events, token)));
    }));
    t!(m.timer_function(move |dur| {
        t!(tx.send(Message::Timeout(dur)));
        true
    }));

    let s = Server::new();
    s.receive(&format!("\
PUT / HTTP/1.1\r\n\
Host: 127.0.0.1:$PORT\r\n\
Accept: */*\r\n\
Content-Length: 131072\r\n\
\r\n\
{}\n", vec!["a"; 128 * 1024 - 1].join("")));
    s.send("\
HTTP/1.1 200 OK\r\n\
\r\n");

    let mut data = vec![b'a'; 128 * 1024 - 1];
    data.push(b'\n');
    let mut data = Cursor::new(data);
    let mut list = List::new();
    t!(list.append("Expect:"));
    let mut h = Easy::new();
    t!(h.url(&s.url("/")));
    t!(h.put(true));
    t!(h.read_function(move |buf| {
        Ok(data.read(buf).unwrap())
    }));
    t!(h.in_filesize(128 * 1024));
    t!(h.upload(true));
    t!(h.http_headers(list));

    t!(poll.register(&rx,
                     mio::Token(0),
                     mio::Ready::all(),
                     mio::PollOpt::level()));

    let e = t!(m.add(h));

    assert!(t!(m.perform()) > 0);
    let mut next_token = 1;
    let mut token_map = HashMap::new();
    let mut cur_timeout = None;
    let mut events = mio::Events::with_capacity(128);
    let mut running = true;

    while running {
        let n = t!(poll.poll(&mut events, cur_timeout));

        if n == 0 {
            if t!(m.timeout()) == 0 {
                running = false;
            }
        }

        for event in events.iter() {
            while event.token() == mio::Token(0) {
                match rx.try_recv() {
                    Ok(Message::Timeout(dur)) => cur_timeout = dur,
                    Ok(Message::Wait(socket, events, token)) => {
                        let evented = mio::unix::EventedFd(&socket);
                        if events.remove() {
                            token_map.remove(&token).unwrap();
                        } else {
                            let mut e = mio::Ready::none();
                            if events.input() {
                                e = e | mio::Ready::readable();
                            }
                            if events.output() {
                                e = e | mio::Ready::writable();
                            }
                            if token == 0 {
                                let token = next_token;
                                next_token += 1;
                                t!(m.assign(socket, token));
                                token_map.insert(token, socket);
                                t!(poll.register(&evented,
                                                 mio::Token(token),
                                                 e,
                                                 mio::PollOpt::level()));
                            } else {
                                t!(poll.reregister(&evented,
                                                   mio::Token(token),
                                                   e,
                                                   mio::PollOpt::level()));
                            }
                        }
                    }
                    Err(_) => break,
                }
            }

            if event.token() == mio::Token(0) {
                continue
            }

            let token = event.token();
            let socket = token_map[&token.into()];
            let mut e = Events::new();
            if event.kind().is_readable() {
                e.input(true);
            }
            if event.kind().is_writable() {
                e.output(true);
            }
            if event.kind().is_error() {
                e.error(true);
            }
            let remaining = t!(m.action(socket, &e));
            if remaining == 0 {
                running = false;
            }
        }
    }

    let mut done = 0;
    m.messages(|m| {
        m.result().unwrap().unwrap();
        done += 1;
    });
    assert_eq!(done, 1);

    let mut e = t!(m.remove(e));
    assert_eq!(t!(e.response_code()), 200);
}
<|endoftext|>


<commit_before>#![deny(warnings)]
#![allow(unstable)]

extern crate cargo;
extern crate flate2;
extern crate git2;
extern crate hamcrest;
extern crate serialize;
extern crate tar;
extern crate term;
extern crate url;

#[macro_use]
extern crate log;

mod support;
macro_rules! test {
    ($name:ident $expr:expr) => (
        #[test]
        fn $name() {
            ::support::paths::setup();
            setup();
            $expr;
        }
    )
}

mod test_bad_config;
mod test_cargo;
mod test_cargo_bench;
mod test_cargo_build_auth;
mod test_cargo_build_lib;
mod test_cargo_clean;
mod test_cargo_compile;
mod test_cargo_compile_custom_build;
mod test_cargo_compile_git_deps;
mod test_cargo_compile_path_deps;
mod test_cargo_compile_plugins;
mod test_cargo_cross_compile;
mod test_cargo_doc;
mod test_cargo_features;
mod test_cargo_fetch;
mod test_cargo_freshness;
mod test_cargo_generate_lockfile;
mod test_cargo_new;
mod test_cargo_package;
mod test_cargo_profiles;
mod test_cargo_publish;
mod test_cargo_registry;
mod test_cargo_run;
mod test_cargo_search;
mod test_cargo_test;
mod test_cargo_version;
mod test_shell;
<commit_msg>Remove unnecessary allow(unstable)<commit_after>#![deny(warnings)]

extern crate cargo;
extern crate flate2;
extern crate git2;
extern crate hamcrest;
extern crate serialize;
extern crate tar;
extern crate term;
extern crate url;

#[macro_use]
extern crate log;

mod support;
macro_rules! test {
    ($name:ident $expr:expr) => (
        #[test]
        fn $name() {
            ::support::paths::setup();
            setup();
            $expr;
        }
    )
}

mod test_bad_config;
mod test_cargo;
mod test_cargo_bench;
mod test_cargo_build_auth;
mod test_cargo_build_lib;
mod test_cargo_clean;
mod test_cargo_compile;
mod test_cargo_compile_custom_build;
mod test_cargo_compile_git_deps;
mod test_cargo_compile_path_deps;
mod test_cargo_compile_plugins;
mod test_cargo_cross_compile;
mod test_cargo_doc;
mod test_cargo_features;
mod test_cargo_fetch;
mod test_cargo_freshness;
mod test_cargo_generate_lockfile;
mod test_cargo_new;
mod test_cargo_package;
mod test_cargo_profiles;
mod test_cargo_publish;
mod test_cargo_registry;
mod test_cargo_run;
mod test_cargo_search;
mod test_cargo_test;
mod test_cargo_version;
mod test_shell;
<|endoftext|>


<commit_before>use neb::ram::chunk;
use neb::ram::types;

pub const CHUNK_SIZE: usize = 2048;

macro_rules! test_nums {
    (
        $t:ident, $io:ident
    ) => {
        mod $t {
            use super::CHUNK_SIZE;
            use neb::ram::chunk::Chunks;
            use neb::ram::types;
            use rand;
            use std;
            #[test]
            fn test() {
                let rand_num = rand::random::<$t>();
                let test_data = vec![
                    std::$t::MIN,
                    std::$t::MAX,
                    rand_num,
                    0 as $t,
                    1 as $t,
                    2 as $t,
                    127 as $t,
                ];
                let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
                let counts = CHUNK_SIZE / types::$io::size(0) as usize;
                let chunk_addr = chunk.segments()[0].addr;
                for d in test_data {
                    for i in 0..counts {
                        let addr = chunk_addr + i * types::$io::size(0);
                        types::$io::write(&d, addr);
                        assert!(types::$io::read(addr) == d);
                    }
                    for i in 0..counts {
                        let addr = chunk_addr + i * types::$io::size(0);
                        assert!(types::$io::read(addr) == d);
                    }
                }
            }
        }
    };
}

test_nums!(i8, i8_io);
test_nums!(i16, i16_io);
test_nums!(i32, i32_io);
test_nums!(i64, i64_io);

test_nums!(u8, u8_io);
test_nums!(u16, u16_io);
test_nums!(u32, u32_io);
test_nums!(u64, u64_io);

test_nums!(isize, isize_io);
test_nums!(usize, usize_io);
test_nums!(f32, f32_io);
test_nums!(f64, f64_io);

mod pos2d32 {
    use super::CHUNK_SIZE;
    use neb::ram::chunk::Chunks;
    use neb::ram::types;
    use rand;
    use std;
    #[test]
    fn test() {
        let test_data = vec![
            types::Pos2d32 {
                x: std::f32::MIN,
                y: std::f32::MAX,
            },
            types::Pos2d32 {
                x: rand::random::<f32>(),
                y: rand::random::<f32>(),
            },
        ];
        let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
        let counts = CHUNK_SIZE / types::pos2d32_io::size(0) as usize;
        let chunk_addr = chunk.segments()[0].addr;
        for d in test_data {
            for i in 0..counts {
                let addr = chunk_addr + i * types::pos2d32_io::size(0);
                types::pos2d32_io::write(&d, addr);
                assert_eq!(types::pos2d32_io::read(addr), d);
            }
            for i in 0..counts {
                let addr = chunk_addr + i * types::pos2d32_io::size(0);
                assert_eq!(types::pos2d32_io::read(addr), d);
            }
        }
    }
}

mod pos2d64 {
    use super::CHUNK_SIZE;
    use neb::ram::chunk::Chunks;
    use neb::ram::types;
    use rand;
    use std;
    #[test]
    fn test() {
        let test_data = vec![
            types::Pos2d64 {
                x: std::f64::MIN,
                y: std::f64::MAX,
            },
            types::Pos2d64 {
                x: rand::random::<f64>(),
                y: rand::random::<f64>(),
            },
        ];
        let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
        let counts = CHUNK_SIZE / types::pos2d64_io::size(0) as usize;
        let chunk_addr = chunk.segments()[0].addr;
        for d in test_data {
            for i in 0..counts {
                let addr = chunk_addr + i * types::pos2d64_io::size(0);
                types::pos2d64_io::write(&d, addr);
                assert_eq!(types::pos2d64_io::read(addr), d);
            }
            for i in 0..counts {
                let addr = chunk_addr + i * types::pos2d64_io::size(0);
                assert_eq!(types::pos2d64_io::read(addr), d);
            }
        }
    }
}

mod pos3d32 {
    use super::CHUNK_SIZE;
    use neb::ram::chunk::Chunks;
    use neb::ram::types;
    use rand;
    use std;
    #[test]
    fn test() {
        let test_data = vec![
            types::Pos3d32 {
                x: std::f32::MIN,
                y: std::f32::MAX,
                z: rand::random::<f32>(),
            },
            types::Pos3d32 {
                x: rand::random::<f32>(),
                y: rand::random::<f32>(),
                z: rand::random::<f32>(),
            },
        ];
        let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
        let counts = CHUNK_SIZE / types::pos3d32_io::size(0) as usize;
        let chunk_addr = chunk.segments()[0].addr;
        for d in test_data {
            for i in 0..counts {
                let addr = chunk_addr + i * types::pos3d32_io::size(0);
                types::pos3d32_io::write(&d, addr);
                assert_eq!(types::pos3d32_io::read(addr), d);
            }
            for i in 0..counts {
                let addr = chunk_addr + i * types::pos3d32_io::size(0);
                assert_eq!(types::pos3d32_io::read(addr), d);
            }
        }
    }
}

mod pos3d64 {
    use super::CHUNK_SIZE;
    use neb::ram::chunk::Chunks;
    use neb::ram::types;
    use rand;
    use std;
    #[test]
    fn test() {
        let test_data = vec![
            types::Pos3d64 {
                x: std::f64::MIN,
                y: std::f64::MAX,
                z: rand::random::<f64>(),
            },
            types::Pos3d64 {
                x: rand::random::<f64>(),
                y: rand::random::<f64>(),
                z: rand::random::<f64>(),
            },
        ];
        let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
        let counts = CHUNK_SIZE / types::pos3d64_io::size(0) as usize;
        let chunk_addr = chunk.segments()[0].addr;
        for d in test_data {
            for i in 0..counts {
                let addr = chunk_addr + i * types::pos3d64_io::size(0);
                types::pos3d64_io::write(&d, addr);
                assert_eq!(types::pos3d64_io::read(addr), d);
            }
            for i in 0..counts {
                let addr = chunk_addr + i * types::pos3d64_io::size(0);
                assert_eq!(types::pos3d64_io::read(addr), d);
            }
        }
    }
}

mod uuid {
    use super::CHUNK_SIZE;
    use neb::ram::chunk::Chunks;
    use neb::ram::types;
    use neb::ram::types::Id;
    #[test]
    fn test() {
        let test_data = vec![Id {
            higher: 1,
            lower: 2,
        }];
        let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
        let counts = CHUNK_SIZE / types::id_io::size(0) as usize;
        let chunk_addr = chunk.segments()[0].addr;
        for d in test_data {
            for i in 0..counts {
                let addr = chunk_addr + i * types::id_io::size(0);
                types::id_io::write(&d, addr);
                assert_eq!(types::id_io::read(addr), d);
            }
            for i in 0..counts {
                let addr = chunk_addr + i * types::id_io::size(0);
                assert_eq!(types::id_io::read(addr), d);
            }
        }
    }
}

mod string {
    use super::CHUNK_SIZE;
    use neb::ram::chunk::Chunks;
    use neb::ram::types;
    use std::string::String;
    #[test]
    fn test() {
        let test_data = vec![
            "",
            "ಬಾ ಇಲ್ಲಿ ಸಂಭವಿಸ",
            "中文测试文本",
            "Hello Test",
            "💖",
        ];
        let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
        let mut addr = chunk.segments()[0].addr;
        for d in test_data.clone() {
            let test_str = String::from(d);
            types::string_io::write(&test_str, addr);
            let len = types::string_io::size(addr);
            let dec_str = types::string_io::read(addr);
            assert_eq!(dec_str, test_str);
            println!("{}", dec_str);
            addr += len;
        }
        addr = chunk.segments()[0].addr;
        for d in test_data.clone() {
            let test_str = String::from(d);
            let len = types::string_io::size(addr);
            assert_eq!(types::string_io::read(addr), test_str);
            addr += len;
        }
    }
}

#[test]
fn array_len_type() {
    assert_eq!(
        types::u32_io::size(0),
        types::get_size(types::ARRAY_LEN_TYPE_ID, 0)
    )
}

#[test]
fn null_type() {
    assert_eq!(
        types::u8_io::size(0),
        types::get_size(types::NULL_TYPE_ID, 0)
    )
}

#[test]
fn _in_map() {
    let mut map2 = types::Map::new();
    map2.insert(&String::from("a"), types::Value::I32(1));
    map2.insert(&String::from("b"), types::Value::I64(2));

    let mut map = types::Map::new();
    map.insert(&String::from("A"), types::Value::I32(1));
    map.insert(&String::from("B"), types::Value::Map(map2));

    assert_eq!(map.get(&String::from("A")).I32().unwrap(), &1);
    assert_eq!(map.get_in(&["B", "a"]).I32().unwrap(), &1);

    map.set_in(&["B", "a"], types::Value::I32(20)).unwrap();
    assert_eq!(map.get_in(&["B", "a"]).I32().unwrap(), &20);

    map.update_in(&["B", "b"], |value: &mut types::Value| {
        assert_eq!(value.I64().unwrap(), &2);
        *value = types::Value::I64(30);
    });
    assert_eq!(map.get_in(&["B", "b"]).I64().unwrap(), &30);
}

#[test]
fn index_mut_map() {
    let mut value = types::Value::Map(types::Map::new());
    value["a"] = types::Value::String(String::from("A"));
    value["b"] = types::Value::Array(vec![types::Value::U64(5)]);
    assert_eq!(value["a"].String().unwrap(), &String::from("A"));
    assert_eq!(value["b"][0 as usize].U64().unwrap(), &5);
    value["b"][0 as usize] = types::Value::U64(10);
    assert_eq!(value["b"][0 as usize].U64().unwrap(), &10);
}

#[test]
fn num_cast() {
    assert_eq!(1u32, 1u64 as u32);
}
<commit_msg>remove isize and usize type test<commit_after>use neb::ram::chunk;
use neb::ram::types;

pub const CHUNK_SIZE: usize = 2048;

macro_rules! test_nums {
    (
        $t:ident, $io:ident
    ) => {
        mod $t {
            use super::CHUNK_SIZE;
            use neb::ram::chunk::Chunks;
            use neb::ram::types;
            use rand;
            use std;
            #[test]
            fn test() {
                let rand_num = rand::random::<$t>();
                let test_data = vec![
                    std::$t::MIN,
                    std::$t::MAX,
                    rand_num,
                    0 as $t,
                    1 as $t,
                    2 as $t,
                    127 as $t,
                ];
                let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
                let counts = CHUNK_SIZE / types::$io::size(0) as usize;
                let chunk_addr = chunk.segments()[0].addr;
                for d in test_data {
                    for i in 0..counts {
                        let addr = chunk_addr + i * types::$io::size(0);
                        types::$io::write(&d, addr);
                        assert!(types::$io::read(addr) == d);
                    }
                    for i in 0..counts {
                        let addr = chunk_addr + i * types::$io::size(0);
                        assert!(types::$io::read(addr) == d);
                    }
                }
            }
        }
    };
}

test_nums!(i8, i8_io);
test_nums!(i16, i16_io);
test_nums!(i32, i32_io);
test_nums!(i64, i64_io);

test_nums!(u8, u8_io);
test_nums!(u16, u16_io);
test_nums!(u32, u32_io);
test_nums!(u64, u64_io);

test_nums!(f32, f32_io);
test_nums!(f64, f64_io);

mod pos2d32 {
    use super::CHUNK_SIZE;
    use neb::ram::chunk::Chunks;
    use neb::ram::types;
    use rand;
    use std;
    #[test]
    fn test() {
        let test_data = vec![
            types::Pos2d32 {
                x: std::f32::MIN,
                y: std::f32::MAX,
            },
            types::Pos2d32 {
                x: rand::random::<f32>(),
                y: rand::random::<f32>(),
            },
        ];
        let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
        let counts = CHUNK_SIZE / types::pos2d32_io::size(0) as usize;
        let chunk_addr = chunk.segments()[0].addr;
        for d in test_data {
            for i in 0..counts {
                let addr = chunk_addr + i * types::pos2d32_io::size(0);
                types::pos2d32_io::write(&d, addr);
                assert_eq!(types::pos2d32_io::read(addr), d);
            }
            for i in 0..counts {
                let addr = chunk_addr + i * types::pos2d32_io::size(0);
                assert_eq!(types::pos2d32_io::read(addr), d);
            }
        }
    }
}

mod pos2d64 {
    use super::CHUNK_SIZE;
    use neb::ram::chunk::Chunks;
    use neb::ram::types;
    use rand;
    use std;
    #[test]
    fn test() {
        let test_data = vec![
            types::Pos2d64 {
                x: std::f64::MIN,
                y: std::f64::MAX,
            },
            types::Pos2d64 {
                x: rand::random::<f64>(),
                y: rand::random::<f64>(),
            },
        ];
        let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
        let counts = CHUNK_SIZE / types::pos2d64_io::size(0) as usize;
        let chunk_addr = chunk.segments()[0].addr;
        for d in test_data {
            for i in 0..counts {
                let addr = chunk_addr + i * types::pos2d64_io::size(0);
                types::pos2d64_io::write(&d, addr);
                assert_eq!(types::pos2d64_io::read(addr), d);
            }
            for i in 0..counts {
                let addr = chunk_addr + i * types::pos2d64_io::size(0);
                assert_eq!(types::pos2d64_io::read(addr), d);
            }
        }
    }
}

mod pos3d32 {
    use super::CHUNK_SIZE;
    use neb::ram::chunk::Chunks;
    use neb::ram::types;
    use rand;
    use std;
    #[test]
    fn test() {
        let test_data = vec![
            types::Pos3d32 {
                x: std::f32::MIN,
                y: std::f32::MAX,
                z: rand::random::<f32>(),
            },
            types::Pos3d32 {
                x: rand::random::<f32>(),
                y: rand::random::<f32>(),
                z: rand::random::<f32>(),
            },
        ];
        let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
        let counts = CHUNK_SIZE / types::pos3d32_io::size(0) as usize;
        let chunk_addr = chunk.segments()[0].addr;
        for d in test_data {
            for i in 0..counts {
                let addr = chunk_addr + i * types::pos3d32_io::size(0);
                types::pos3d32_io::write(&d, addr);
                assert_eq!(types::pos3d32_io::read(addr), d);
            }
            for i in 0..counts {
                let addr = chunk_addr + i * types::pos3d32_io::size(0);
                assert_eq!(types::pos3d32_io::read(addr), d);
            }
        }
    }
}

mod pos3d64 {
    use super::CHUNK_SIZE;
    use neb::ram::chunk::Chunks;
    use neb::ram::types;
    use rand;
    use std;
    #[test]
    fn test() {
        let test_data = vec![
            types::Pos3d64 {
                x: std::f64::MIN,
                y: std::f64::MAX,
                z: rand::random::<f64>(),
            },
            types::Pos3d64 {
                x: rand::random::<f64>(),
                y: rand::random::<f64>(),
                z: rand::random::<f64>(),
            },
        ];
        let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
        let counts = CHUNK_SIZE / types::pos3d64_io::size(0) as usize;
        let chunk_addr = chunk.segments()[0].addr;
        for d in test_data {
            for i in 0..counts {
                let addr = chunk_addr + i * types::pos3d64_io::size(0);
                types::pos3d64_io::write(&d, addr);
                assert_eq!(types::pos3d64_io::read(addr), d);
            }
            for i in 0..counts {
                let addr = chunk_addr + i * types::pos3d64_io::size(0);
                assert_eq!(types::pos3d64_io::read(addr), d);
            }
        }
    }
}

mod uuid {
    use super::CHUNK_SIZE;
    use neb::ram::chunk::Chunks;
    use neb::ram::types;
    use neb::ram::types::Id;
    #[test]
    fn test() {
        let test_data = vec![Id {
            higher: 1,
            lower: 2,
        }];
        let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
        let counts = CHUNK_SIZE / types::id_io::size(0) as usize;
        let chunk_addr = chunk.segments()[0].addr;
        for d in test_data {
            for i in 0..counts {
                let addr = chunk_addr + i * types::id_io::size(0);
                types::id_io::write(&d, addr);
                assert_eq!(types::id_io::read(addr), d);
            }
            for i in 0..counts {
                let addr = chunk_addr + i * types::id_io::size(0);
                assert_eq!(types::id_io::read(addr), d);
            }
        }
    }
}

mod string {
    use super::CHUNK_SIZE;
    use neb::ram::chunk::Chunks;
    use neb::ram::types;
    use std::string::String;
    #[test]
    fn test() {
        let test_data = vec![
            "",
            "ಬಾ ಇಲ್ಲಿ ಸಂಭವಿಸ",
            "中文测试文本",
            "Hello Test",
            "💖",
        ];
        let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
        let mut addr = chunk.segments()[0].addr;
        for d in test_data.clone() {
            let test_str = String::from(d);
            types::string_io::write(&test_str, addr);
            let len = types::string_io::size(addr);
            let dec_str = types::string_io::read(addr);
            assert_eq!(dec_str, test_str);
            println!("{}", dec_str);
            addr += len;
        }
        addr = chunk.segments()[0].addr;
        for d in test_data.clone() {
            let test_str = String::from(d);
            let len = types::string_io::size(addr);
            assert_eq!(types::string_io::read(addr), test_str);
            addr += len;
        }
    }
}

#[test]
fn array_len_type() {
    assert_eq!(
        types::u32_io::size(0),
        types::get_size(types::ARRAY_LEN_TYPE_ID, 0)
    )
}

#[test]
fn null_type() {
    assert_eq!(
        types::u8_io::size(0),
        types::get_size(types::NULL_TYPE_ID, 0)
    )
}

#[test]
fn _in_map() {
    let mut map2 = types::Map::new();
    map2.insert(&String::from("a"), types::Value::I32(1));
    map2.insert(&String::from("b"), types::Value::I64(2));

    let mut map = types::Map::new();
    map.insert(&String::from("A"), types::Value::I32(1));
    map.insert(&String::from("B"), types::Value::Map(map2));

    assert_eq!(map.get(&String::from("A")).I32().unwrap(), &1);
    assert_eq!(map.get_in(&["B", "a"]).I32().unwrap(), &1);

    map.set_in(&["B", "a"], types::Value::I32(20)).unwrap();
    assert_eq!(map.get_in(&["B", "a"]).I32().unwrap(), &20);

    map.update_in(&["B", "b"], |value: &mut types::Value| {
        assert_eq!(value.I64().unwrap(), &2);
        *value = types::Value::I64(30);
    });
    assert_eq!(map.get_in(&["B", "b"]).I64().unwrap(), &30);
}

#[test]
fn index_mut_map() {
    let mut value = types::Value::Map(types::Map::new());
    value["a"] = types::Value::String(String::from("A"));
    value["b"] = types::Value::Array(vec![types::Value::U64(5)]);
    assert_eq!(value["a"].String().unwrap(), &String::from("A"));
    assert_eq!(value["b"][0 as usize].U64().unwrap(), &5);
    value["b"][0 as usize] = types::Value::U64(10);
    assert_eq!(value["b"][0 as usize].U64().unwrap(), &10);
}

#[test]
fn num_cast() {
    assert_eq!(1u32, 1u64 as u32);
}
<|endoftext|>


<commit_before>//! Higher level libtls API wrappers to use along with the Rust
//! standard library

use super::{TlsContext, TlsConfig};
use std::io;
use std::io::{Read, Write};
use std::net::TcpStream;

pub struct TlsConnection {
    cfg: TlsConfig,
}
impl TlsConnection {
    pub fn new() -> Option<TlsConnection> {
        if let Some(cfg) = TlsConfig::new() {
            Some(TlsConnection { cfg: cfg })
        } else {
            None
        }
    }

    /// Connect to server, and process the TLS handshake
    pub fn connect(self, hostname: &str, port: &str) -> io::Result<TlsStream> {
        let mut c = try!(TlsStream::new_client());
        try!(c.configure(self.cfg));
        try!(c.connect_servername(hostname, port, ""));
        if let Err(err) = c.handshake() {
            if err.wants_more() {
                try!(c.handshake());
            } else {
                return Err(io::Error::from(err));
            }
        }
        Ok(TlsStream { ctx: c })
    }

    pub fn set_ca_file(&mut self, path: &str) -> Option<()> {
        self.cfg.set_ca_file(path)
    }
    pub fn set_ca_path(&mut self, path: &str) -> Option<()> {
        self.cfg.set_ca_path(path)
    }
    pub fn set_ca_mem(&mut self, ca: &str) -> Option<()> {
        self.cfg.set_ca_mem(ca)
    }
    pub fn set_verify_depth(&mut self, depth: i32) {
        self.cfg.set_verify_depth(depth)
    }
    pub fn set_protocols(&mut self, protocols: &str) -> Option<()> {
        self.cfg.set_protocols(protocols)
    }
    pub fn set_ciphers(&mut self, ciphers: &str) -> Option<()> {
        self.cfg.set_ciphers(ciphers)
    }
    pub fn insecure_noverifycert(&mut self) {
        self.cfg.insecure_noverifycert()
    }
    pub fn insecure_noverifyname(&mut self) {
        self.cfg.insecure_noverifyname()
    }
}

pub struct TlsStream {
    ctx: TlsContext,
}

impl TlsStream {
    /// Convinience method to create TlsContext clients
    fn new_client() -> io::Result<TlsContext> {
        TlsContext::new_client()
            .ok_or(io::Error::new(io::ErrorKind::Other, "Failed to create new TLS context"))
    }

    /// Close the connection
    pub fn shutdown(&mut self) -> io::Result<()> {
        if let Err(err) = self.ctx.close() {
            if err.wants_more() {
                try!(self.ctx.close());
            } else {
                return Err(io::Error::from(err));
            }
        }
        Ok(())
    }

    /// Create a new TLS stream from an existing TCP stream
    pub fn from_tcp_stream(tcp: TcpStream, servername: &str) -> io::Result<TlsStream> {
        let mut c = try!(TlsStream::new_client());
        try!(c.connect_socket(tcp, servername)
              .map_err(|msg| io::Error::new(io::ErrorKind::Other, msg)));
        Ok(TlsStream { ctx: c })
    }

    pub fn certificate_issuer(&self) -> String {
        self.ctx.peer_cert_issuer()
    }
    pub fn certificate_hash(&self) -> String {
        self.ctx.peer_cert_hash()
    }
    pub fn certificate_subject(&self) -> String {
        self.ctx.peer_cert_subject()
    }
    pub fn version(&self) -> String {
        self.ctx.conn_version()
    }
    pub fn cipher(&self) -> String {
        self.ctx.conn_cipher()
    }
}

impl Read for TlsStream {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.ctx
            .read(buf)
            .map_err(|err| io::Error::from(err))
    }
}

impl Write for TlsStream {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.ctx
            .write(buf)
            .map_err(|err| io::Error::from(err))
    }
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl Drop for TlsStream {
    fn drop(&mut self) {
        let _ = self.ctx.close();
    }
}
<commit_msg>Move from_tcp_stream() to TlsConnection<commit_after>//! Higher level libtls API wrappers to use along with the Rust
//! standard library

use super::{TlsContext, TlsConfig};
use std::io;
use std::io::{Read, Write};
use std::net::TcpStream;

pub struct TlsConnection {
    cfg: TlsConfig,
}
impl TlsConnection {
    pub fn new() -> Option<TlsConnection> {
        if let Some(cfg) = TlsConfig::new() {
            Some(TlsConnection { cfg: cfg })
        } else {
            None
        }
    }

    /// Connect to server, and process the TLS handshake
    pub fn connect(self, hostname: &str, port: &str) -> io::Result<TlsStream> {
        let mut c = try!(TlsStream::new_client());
        try!(c.configure(self.cfg));
        try!(c.connect_servername(hostname, port, ""));
        if let Err(err) = c.handshake() {
            if err.wants_more() {
                try!(c.handshake());
            } else {
                return Err(io::Error::from(err));
            }
        }
        Ok(TlsStream { ctx: c })
    }

    /// Create a new TLS stream from an existing TCP stream
    pub fn from_tcp_stream(self, tcp: TcpStream, servername: &str) -> io::Result<TlsStream> {
        let mut c = try!(TlsStream::new_client());
        try!(c.configure(self.cfg));
        try!(c.connect_socket(tcp, servername)
              .map_err(|msg| io::Error::new(io::ErrorKind::Other, msg)));
        if let Err(err) = c.handshake() {
            if err.wants_more() {
                try!(c.handshake());
            } else {
                return Err(io::Error::from(err));
            }
        }
        Ok(TlsStream { ctx: c })
    }

    pub fn set_ca_file(&mut self, path: &str) -> Option<()> {
        self.cfg.set_ca_file(path)
    }
    pub fn set_ca_path(&mut self, path: &str) -> Option<()> {
        self.cfg.set_ca_path(path)
    }
    pub fn set_ca_mem(&mut self, ca: &str) -> Option<()> {
        self.cfg.set_ca_mem(ca)
    }
    pub fn set_verify_depth(&mut self, depth: i32) {
        self.cfg.set_verify_depth(depth)
    }
    pub fn set_protocols(&mut self, protocols: &str) -> Option<()> {
        self.cfg.set_protocols(protocols)
    }
    pub fn set_ciphers(&mut self, ciphers: &str) -> Option<()> {
        self.cfg.set_ciphers(ciphers)
    }
    pub fn insecure_noverifycert(&mut self) {
        self.cfg.insecure_noverifycert()
    }
    pub fn insecure_noverifyname(&mut self) {
        self.cfg.insecure_noverifyname()
    }
}

pub struct TlsStream {
    ctx: TlsContext,
}

impl TlsStream {
    /// Convinience method to create TlsContext clients
    fn new_client() -> io::Result<TlsContext> {
        TlsContext::new_client()
            .ok_or(io::Error::new(io::ErrorKind::Other, "Failed to create new TLS context"))
    }

    /// Close the connection
    pub fn shutdown(&mut self) -> io::Result<()> {
        if let Err(err) = self.ctx.close() {
            if err.wants_more() {
                try!(self.ctx.close());
            } else {
                return Err(io::Error::from(err));
            }
        }
        Ok(())
    }

    pub fn certificate_issuer(&self) -> String {
        self.ctx.peer_cert_issuer()
    }
    pub fn certificate_hash(&self) -> String {
        self.ctx.peer_cert_hash()
    }
    pub fn certificate_subject(&self) -> String {
        self.ctx.peer_cert_subject()
    }
    pub fn version(&self) -> String {
        self.ctx.conn_version()
    }
    pub fn cipher(&self) -> String {
        self.ctx.conn_cipher()
    }
}

impl Read for TlsStream {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.ctx
            .read(buf)
            .map_err(|err| io::Error::from(err))
    }
}

impl Write for TlsStream {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.ctx
            .write(buf)
            .map_err(|err| io::Error::from(err))
    }
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl Drop for TlsStream {
    fn drop(&mut self) {
        let _ = self.ctx.close();
    }
}
<|endoftext|>


<commit_before>use crate::NewlineStyle;

/// Apply this newline style to the formatted text. When the style is set
/// to `Auto`, the `raw_input_text` is used to detect the existing line
/// endings.
///
/// If the style is set to `Auto` and `raw_input_text` contains no
/// newlines, the `Native` style will be used.
pub(crate) fn apply_newline_style(
    newline_style: NewlineStyle,
    formatted_text: &mut String,
    raw_input_text: &str,
) {
    match effective_newline_style(newline_style, raw_input_text) {
        EffectiveNewlineStyle::Windows => {
            *formatted_text = convert_to_windows_newlines(formatted_text);
        }
        EffectiveNewlineStyle::Unix => {}
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum EffectiveNewlineStyle {
    Windows,
    Unix,
}

fn effective_newline_style(
    newline_style: NewlineStyle,
    raw_input_text: &str,
) -> EffectiveNewlineStyle {
    match newline_style {
        NewlineStyle::Auto => auto_detect_newline_style(raw_input_text),
        NewlineStyle::Native => native_newline_style(),
        NewlineStyle::Windows => EffectiveNewlineStyle::Windows,
        NewlineStyle::Unix => EffectiveNewlineStyle::Unix,
    }
}

const LINE_FEED: char = '\n';
const CARRIAGE_RETURN: char = '\r';

fn auto_detect_newline_style(raw_input_text: &str) -> EffectiveNewlineStyle {
    if let Some(pos) = raw_input_text.find(LINE_FEED) {
        let pos = pos.saturating_sub(1);
        if let Some(CARRIAGE_RETURN) = raw_input_text.chars().nth(pos) {
            EffectiveNewlineStyle::Windows
        } else {
            EffectiveNewlineStyle::Unix
        }
    } else {
        native_newline_style()
    }
}

fn native_newline_style() -> EffectiveNewlineStyle {
    if cfg!(windows) {
        EffectiveNewlineStyle::Windows
    } else {
        EffectiveNewlineStyle::Unix
    }
}

fn convert_to_windows_newlines(formatted_text: &String) -> String {
    let mut transformed = String::with_capacity(2 * formatted_text.capacity());
    for c in formatted_text.chars() {
        const WINDOWS_NEWLINE: &str = "\r\n";
        match c {
            LINE_FEED => transformed.push_str(WINDOWS_NEWLINE),
            CARRIAGE_RETURN => continue,
            c => transformed.push(c),
        }
    }
    transformed
}

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

    #[test]
    fn test_newline_style_auto_detect() {
        let lf = "One\nTwo\nThree";
        let crlf = "One\r\nTwo\r\nThree";
        let none = "One Two Three";

        assert_eq!(EffectiveNewlineStyle::Unix, auto_detect_newline_style(lf));
        assert_eq!(
            EffectiveNewlineStyle::Windows,
            auto_detect_newline_style(crlf)
        );

        if cfg!(windows) {
            assert_eq!(
                EffectiveNewlineStyle::Windows,
                auto_detect_newline_style(none)
            );
        } else {
            assert_eq!(EffectiveNewlineStyle::Unix, auto_detect_newline_style(none));
        }
    }

    #[test]
    fn test_newline_style_auto_apply() {
        let auto = NewlineStyle::Auto;

        let formatted_text = "One\nTwo\nThree";
        let raw_input_text = "One\nTwo\nThree";

        let mut out = String::from(formatted_text);
        apply_newline_style(auto, &mut out, raw_input_text);
        assert_eq!("One\nTwo\nThree", &out, "auto should detect 'lf'");

        let formatted_text = "One\nTwo\nThree";
        let raw_input_text = "One\r\nTwo\r\nThree";

        let mut out = String::from(formatted_text);
        apply_newline_style(auto, &mut out, raw_input_text);
        assert_eq!("One\r\nTwo\r\nThree", &out, "auto should detect 'crlf'");

        #[cfg(not(windows))]
        {
            let formatted_text = "One\nTwo\nThree";
            let raw_input_text = "One Two Three";

            let mut out = String::from(formatted_text);
            apply_newline_style(auto, &mut out, raw_input_text);
            assert_eq!(
                "One\nTwo\nThree", &out,
                "auto-native-unix should detect 'lf'"
            );
        }

        #[cfg(windows)]
        {
            let formatted_text = "One\nTwo\nThree";
            let raw_input_text = "One Two Three";

            let mut out = String::from(formatted_text);
            apply_newline_style(auto, &mut out, raw_input_text);
            assert_eq!(
                "One\r\nTwo\r\nThree", &out,
                "auto-native-windows should detect 'crlf'"
            );
        }
    }
}
<commit_msg>Split auto_detect tests into seperate fns<commit_after>use crate::NewlineStyle;

/// Apply this newline style to the formatted text. When the style is set
/// to `Auto`, the `raw_input_text` is used to detect the existing line
/// endings.
///
/// If the style is set to `Auto` and `raw_input_text` contains no
/// newlines, the `Native` style will be used.
pub(crate) fn apply_newline_style(
    newline_style: NewlineStyle,
    formatted_text: &mut String,
    raw_input_text: &str,
) {
    match effective_newline_style(newline_style, raw_input_text) {
        EffectiveNewlineStyle::Windows => {
            *formatted_text = convert_to_windows_newlines(formatted_text);
        }
        EffectiveNewlineStyle::Unix => {}
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum EffectiveNewlineStyle {
    Windows,
    Unix,
}

fn effective_newline_style(
    newline_style: NewlineStyle,
    raw_input_text: &str,
) -> EffectiveNewlineStyle {
    match newline_style {
        NewlineStyle::Auto => auto_detect_newline_style(raw_input_text),
        NewlineStyle::Native => native_newline_style(),
        NewlineStyle::Windows => EffectiveNewlineStyle::Windows,
        NewlineStyle::Unix => EffectiveNewlineStyle::Unix,
    }
}

const LINE_FEED: char = '\n';
const CARRIAGE_RETURN: char = '\r';

fn auto_detect_newline_style(raw_input_text: &str) -> EffectiveNewlineStyle {
    if let Some(pos) = raw_input_text.find(LINE_FEED) {
        let pos = pos.saturating_sub(1);
        if let Some(CARRIAGE_RETURN) = raw_input_text.chars().nth(pos) {
            EffectiveNewlineStyle::Windows
        } else {
            EffectiveNewlineStyle::Unix
        }
    } else {
        native_newline_style()
    }
}

fn native_newline_style() -> EffectiveNewlineStyle {
    if cfg!(windows) {
        EffectiveNewlineStyle::Windows
    } else {
        EffectiveNewlineStyle::Unix
    }
}

fn convert_to_windows_newlines(formatted_text: &String) -> String {
    let mut transformed = String::with_capacity(2 * formatted_text.capacity());
    for c in formatted_text.chars() {
        const WINDOWS_NEWLINE: &str = "\r\n";
        match c {
            LINE_FEED => transformed.push_str(WINDOWS_NEWLINE),
            CARRIAGE_RETURN => continue,
            c => transformed.push(c),
        }
    }
    transformed
}

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

    #[test]
    fn auto_detects_unix_newlines() {
        assert_eq!(
            EffectiveNewlineStyle::Unix,
            auto_detect_newline_style("One\nTwo\nThree")
        );
    }

    #[test]
    fn auto_detects_windows_newlines() {
        assert_eq!(
            EffectiveNewlineStyle::Windows,
            auto_detect_newline_style("One\r\nTwo\r\nThree")
        );
    }

    #[test]
    fn falls_back_to_native_newlines_if_no_newlines_are_found() {
        let expected_newline_style = if cfg!(windows) {
            EffectiveNewlineStyle::Windows
        } else {
            EffectiveNewlineStyle::Unix
        };
        assert_eq!(
            expected_newline_style,
            auto_detect_newline_style("One Two Three")
        );
    }

    #[test]
    fn test_newline_style_auto_apply() {
        let auto = NewlineStyle::Auto;

        let formatted_text = "One\nTwo\nThree";
        let raw_input_text = "One\nTwo\nThree";

        let mut out = String::from(formatted_text);
        apply_newline_style(auto, &mut out, raw_input_text);
        assert_eq!("One\nTwo\nThree", &out, "auto should detect 'lf'");

        let formatted_text = "One\nTwo\nThree";
        let raw_input_text = "One\r\nTwo\r\nThree";

        let mut out = String::from(formatted_text);
        apply_newline_style(auto, &mut out, raw_input_text);
        assert_eq!("One\r\nTwo\r\nThree", &out, "auto should detect 'crlf'");

        #[cfg(not(windows))]
        {
            let formatted_text = "One\nTwo\nThree";
            let raw_input_text = "One Two Three";

            let mut out = String::from(formatted_text);
            apply_newline_style(auto, &mut out, raw_input_text);
            assert_eq!(
                "One\nTwo\nThree", &out,
                "auto-native-unix should detect 'lf'"
            );
        }

        #[cfg(windows)]
        {
            let formatted_text = "One\nTwo\nThree";
            let raw_input_text = "One Two Three";

            let mut out = String::from(formatted_text);
            apply_newline_style(auto, &mut out, raw_input_text);
            assert_eq!(
                "One\r\nTwo\r\nThree", &out,
                "auto-native-windows should detect 'crlf'"
            );
        }
    }
}
<|endoftext|>