<commit_before>use std::thread;
use std::sync::mpsc;
use std::hash::Hash;
use std::collections::HashMap;

use index::boolean_index::{Result, Error, IndexingError};
use index::boolean_index::posting::Listing;
use chunked_storage::{ChunkedStorage, IndexingChunk};
use storage::Storage;

const SORT_THREADS: usize = 4;

/// Indexes a document collection for later retrieval
/// Returns the number of documents indexed
pub fn index_documents<TDocsIterator, TDocIterator, TStorage, TTerm>
    (documents: TDocsIterator,
     storage: TStorage)
     -> Result<(usize, ChunkedStorage, HashMap<TTerm, u64>)>
    where TDocsIterator: Iterator<Item = TDocIterator>,
          TDocIterator: Iterator<Item = TTerm>,
          TStorage: Storage<IndexingChunk> + 'static,
          TTerm: Ord + Hash
{
    let (merged_tx, merged_rx) = mpsc::sync_channel(64);
    let mut document_count = 0;
    // Initialize and start sorting threads
    let mut chunk_tx = Vec::with_capacity(SORT_THREADS);
    let mut sort_threads = Vec::with_capacity(SORT_THREADS);
    for _ in 0..SORT_THREADS {
        let (tx, rx) = mpsc::channel();
        chunk_tx.push(tx);
        let m_tx = merged_tx.clone();
        sort_threads.push(thread::spawn(|| sort_and_group_chunk(rx, m_tx)));
    }
    drop(merged_tx);
    let inv_index = thread::spawn(|| invert_index(merged_rx, storage));
    let mut term_ids = HashMap::new();
    let mut buffer = Vec::with_capacity(213400);
    let mut term_count = 0;
    // For every document in the collection
    let mut chunk_count = 0;
    for (doc_id, document) in documents.enumerate() {
        // Enumerate over its terms
        for (term_position, term) in document.into_iter().enumerate() {
            // Has term already been seen? Is it already in the vocabulary?
            if let Some(term_id) = term_ids.get(&term) {
                buffer.push((*term_id, doc_id as u64, term_position as u32));
                continue;
            }
            term_ids.insert(term, term_count as u64);
            buffer.push((term_count as u64, doc_id as u64, term_position as u32));
            term_count += 1;
        }
        // Term was not yet indexed. Add it
        document_count += 1;
        if document_count % 256 == 0 {
            let index = chunk_count % SORT_THREADS;
            let old_len = buffer.len();
            try!(chunk_tx[index].send(buffer));
            buffer = Vec::with_capacity(old_len + old_len / 10);
            chunk_count += 1;
        }
    }
    try!(chunk_tx[chunk_count % SORT_THREADS].send(buffer));
    drop(chunk_tx);
    // Join sort threads
    if sort_threads.into_iter().any(|thread| thread.join().is_err()) {
        return Err(Error::Indexing(IndexingError::ThreadPanic));
    }
    // Join invert index thread and save result
    let chunked_postings = match inv_index.join() {
        Ok(res) => try!(res),
        Err(_) => return Err(Error::Indexing(IndexingError::ThreadPanic)),
    };

    Ok((document_count, chunked_postings, term_ids))
}

/// Receives chunks of (term_id, doc_id, position) tripels
/// Sorts and groups them by term_id and doc_id then sends them
fn sort_and_group_chunk(ids: mpsc::Receiver<Vec<(u64, u64, u32)>>,
                        grouped_chunks: mpsc::SyncSender<Vec<(u64, Listing)>>) {

    while let Ok(mut chunk) = ids.recv() {
        // Sort triples by term_id
        chunk.sort_by_key(|&(a, _, _)| a);
        let mut grouped_chunk = Vec::with_capacity(chunk.len());
        let mut last_tid = 0;
        let mut term_counter = 0;
        // Group by term_id and doc_id
        for (i, &(term_id, doc_id, pos)) in chunk.iter().enumerate() {
            // if term is the first term or different to the last term (new group)
            if last_tid < term_id || i == 0 {
                term_counter += 1;
                // Term_id has to be added
                grouped_chunk.push((term_id, vec![(doc_id, vec![pos])]));
                last_tid = term_id;
                continue;
            }
            // Term_id is already known.
            {
                let mut posting = grouped_chunk[term_counter - 1].1.last_mut().unwrap();
                // Check if last doc_id equals this doc_id
                if posting.0 == doc_id {
                    // If so only push the new position
                    posting.1.push(pos);
                    continue;
                }
            }
            // Otherwise add a whole new posting
            grouped_chunk[term_counter - 1].1.push((doc_id, vec![pos]));
        }
        // Send grouped chunk to merger thread
        // (yes, this is a verb: https://en.wiktionary.org/wiki/grouped#English)
        grouped_chunks.send(grouped_chunk).unwrap();
    }
}

fn invert_index<TStorage>(grouped_chunks: mpsc::Receiver<Vec<(u64, Listing)>>,
                          storage: TStorage)
                          -> Result<ChunkedStorage>
    where TStorage: Storage<IndexingChunk> + 'static
{
    let mut storage = ChunkedStorage::new(10000, Box::new(storage));
    while let Ok(chunk) = grouped_chunks.recv() {
        let threshold = storage.len();
        for (term_id, listing) in chunk {
            println!("{:?}", listing);
            let uterm_id = term_id as usize;
            // Get chunk to write to or create if unknown
            let result = {
                let stor_chunk = if uterm_id < threshold {
                    storage.get_current_mut(term_id)
                } else {
                    storage.new_chunk(term_id)
                };
                stor_chunk.append(&listing)
            };
            // Listing did not fit into current chunk completly
            // Get the next and put it in there.
            // Repeat until done
            if let Err(mut position) = result {
                loop {
                    let next_chunk = try!(storage.next_chunk(term_id));
                    if let Err(new_position) = next_chunk.append(&listing[position..]) {
                        if new_position == 0 {
                            // TODO: FIXME
                            panic!("Position list was longer than chunksize. Go Home!");
                        }
                        position += new_position;
                    } else {
                        break;
                    }
                }
            }
        }

    }
    Ok(storage)
}

#[cfg(test)]
mod tests {

    use std::thread;
    use std::sync::mpsc;

    use utils::persistence::Volatile;
    use index::boolean_index::posting::decode_from_storage;
    use storage::RamStorage;

    #[test]
    fn basic_sorting() {
        let (trp_tx, trp_rx) = mpsc::channel();
        let (sorted_tx, sorted_rx) = mpsc::sync_channel(64);

        thread::spawn(|| super::sort_and_group_chunk(trp_rx, sorted_tx));

        // (term_id, doc_id, position)
        // Document 0: "0, 0, 1"
        // Document 1: "0"
        trp_tx.send(vec![(0, 0, 1), (0, 0, 2), (1, 0, 3), (0, 1, 0)]).unwrap();
        assert_eq!(sorted_rx.recv().unwrap(),
                   vec![(0, vec![(0, vec![1, 2]), (1, vec![0])]), (1, vec![(0, vec![3])])]);
    }

    #[test]
    fn extended_sorting() {
        let (trp_tx, trp_rx) = mpsc::channel();
        let (sorted_tx, sorted_rx) = mpsc::sync_channel(64);

        thread::spawn(|| super::sort_and_group_chunk(trp_rx, sorted_tx));

        trp_tx.send((0..100).map(|i| (i, i, i as u32)).collect::<Vec<_>>()).unwrap();
        let sorted = sorted_rx.recv().unwrap();
        assert_eq!(sorted,
                   (0..100).map(|i| (i, vec![(i, vec![i as u32])])).collect::<Vec<_>>());

        trp_tx.send((0..100).map(|i| (i, i, i as u32)).collect::<Vec<_>>()).unwrap();
        let sorted = sorted_rx.recv().unwrap();
        assert_eq!(sorted,
                   (0..100).map(|i| (i, vec![(i, vec![i as u32])])).collect::<Vec<_>>());

        trp_tx.send((200..300).map(|i| (i, i, i as u32)).collect::<Vec<_>>()).unwrap();
        let sorted = sorted_rx.recv().unwrap();
        assert_eq!(sorted,
                   (200..300).map(|i| (i, vec![(i, vec![i as u32])])).collect::<Vec<_>>());
    }

    #[test]
    fn basic_inverting() {
        let (sorted_tx, sorted_rx) = mpsc::sync_channel(64);
        let result = thread::spawn(|| super::invert_index(sorted_rx, RamStorage::new()));

        sorted_tx.send((0..100).map(|i| (i, vec![(i, vec![i as u32])])).collect::<Vec<_>>()).unwrap();
        drop(sorted_tx);

        let chunked_storage = result.join().unwrap().unwrap();
        assert_eq!(chunked_storage.len(), 100);
        assert_eq!(decode_from_storage(&chunked_storage, 0).unwrap(),
                   vec![(0, vec![0u32])]);
        assert_eq!(decode_from_storage(&chunked_storage, 99).unwrap(),
                   vec![(99, vec![99u32])]);
    }

    #[test]
    fn chunk_overflowing_inverting() {
        let (sorted_tx, sorted_rx) = mpsc::sync_channel(64);
        let result = thread::spawn(|| super::invert_index(sorted_rx, RamStorage::new()));

        sorted_tx.send((0..10)
                .map(|i| (i, (i..i+100).map(|k| (k, (0..10).collect::<Vec<_>>())).collect::<Vec<_>>()))
                .collect::<Vec<_>>())
            .unwrap();
        drop(sorted_tx);

        let chunked_storage = result.join().unwrap().unwrap();
        assert_eq!(chunked_storage.len(), 10);
        assert_eq!(decode_from_storage(&chunked_storage, 0).unwrap(),
                   (0..100).map(|k| (k, (0..10).collect::<Vec<_>>())).collect::<Vec<_>>());

    }

}
<commit_msg>removed debug statement<commit_after>use std::thread;
use std::sync::mpsc;
use std::hash::Hash;
use std::collections::HashMap;

use index::boolean_index::{Result, Error, IndexingError};
use index::boolean_index::posting::Listing;
use chunked_storage::{ChunkedStorage, IndexingChunk};
use storage::Storage;

const SORT_THREADS: usize = 4;

/// Indexes a document collection for later retrieval
/// Returns the number of documents indexed
pub fn index_documents<TDocsIterator, TDocIterator, TStorage, TTerm>
    (documents: TDocsIterator,
     storage: TStorage)
     -> Result<(usize, ChunkedStorage, HashMap<TTerm, u64>)>
    where TDocsIterator: Iterator<Item = TDocIterator>,
          TDocIterator: Iterator<Item = TTerm>,
          TStorage: Storage<IndexingChunk> + 'static,
          TTerm: Ord + Hash
{
    let (merged_tx, merged_rx) = mpsc::sync_channel(64);
    let mut document_count = 0;
    // Initialize and start sorting threads
    let mut chunk_tx = Vec::with_capacity(SORT_THREADS);
    let mut sort_threads = Vec::with_capacity(SORT_THREADS);
    for _ in 0..SORT_THREADS {
        let (tx, rx) = mpsc::channel();
        chunk_tx.push(tx);
        let m_tx = merged_tx.clone();
        sort_threads.push(thread::spawn(|| sort_and_group_chunk(rx, m_tx)));
    }
    drop(merged_tx);
    let inv_index = thread::spawn(|| invert_index(merged_rx, storage));
    let mut term_ids = HashMap::new();
    let mut buffer = Vec::with_capacity(213400);
    let mut term_count = 0;
    // For every document in the collection
    let mut chunk_count = 0;
    for (doc_id, document) in documents.enumerate() {
        // Enumerate over its terms
        for (term_position, term) in document.into_iter().enumerate() {
            // Has term already been seen? Is it already in the vocabulary?
            if let Some(term_id) = term_ids.get(&term) {
                buffer.push((*term_id, doc_id as u64, term_position as u32));
                continue;
            }
            term_ids.insert(term, term_count as u64);
            buffer.push((term_count as u64, doc_id as u64, term_position as u32));
            term_count += 1;
        }
        // Term was not yet indexed. Add it
        document_count += 1;
        if document_count % 256 == 0 {
            let index = chunk_count % SORT_THREADS;
            let old_len = buffer.len();
            try!(chunk_tx[index].send(buffer));
            buffer = Vec::with_capacity(old_len + old_len / 10);
            chunk_count += 1;
        }
    }
    try!(chunk_tx[chunk_count % SORT_THREADS].send(buffer));
    drop(chunk_tx);
    // Join sort threads
    if sort_threads.into_iter().any(|thread| thread.join().is_err()) {
        return Err(Error::Indexing(IndexingError::ThreadPanic));
    }
    // Join invert index thread and save result
    let chunked_postings = match inv_index.join() {
        Ok(res) => try!(res),
        Err(_) => return Err(Error::Indexing(IndexingError::ThreadPanic)),
    };

    Ok((document_count, chunked_postings, term_ids))
}

/// Receives chunks of (term_id, doc_id, position) tripels
/// Sorts and groups them by term_id and doc_id then sends them
fn sort_and_group_chunk(ids: mpsc::Receiver<Vec<(u64, u64, u32)>>,
                        grouped_chunks: mpsc::SyncSender<Vec<(u64, Listing)>>) {

    while let Ok(mut chunk) = ids.recv() {
        // Sort triples by term_id
        chunk.sort_by_key(|&(a, _, _)| a);
        let mut grouped_chunk = Vec::with_capacity(chunk.len());
        let mut last_tid = 0;
        let mut term_counter = 0;
        // Group by term_id and doc_id
        for (i, &(term_id, doc_id, pos)) in chunk.iter().enumerate() {
            // if term is the first term or different to the last term (new group)
            if last_tid < term_id || i == 0 {
                term_counter += 1;
                // Term_id has to be added
                grouped_chunk.push((term_id, vec![(doc_id, vec![pos])]));
                last_tid = term_id;
                continue;
            }
            // Term_id is already known.
            {
                let mut posting = grouped_chunk[term_counter - 1].1.last_mut().unwrap();
                // Check if last doc_id equals this doc_id
                if posting.0 == doc_id {
                    // If so only push the new position
                    posting.1.push(pos);
                    continue;
                }
            }
            // Otherwise add a whole new posting
            grouped_chunk[term_counter - 1].1.push((doc_id, vec![pos]));
        }
        // Send grouped chunk to merger thread
        // (yes, this is a verb: https://en.wiktionary.org/wiki/grouped#English)
        grouped_chunks.send(grouped_chunk).unwrap();
    }
}

fn invert_index<TStorage>(grouped_chunks: mpsc::Receiver<Vec<(u64, Listing)>>,
                          storage: TStorage)
                          -> Result<ChunkedStorage>
    where TStorage: Storage<IndexingChunk> + 'static
{
    let mut storage = ChunkedStorage::new(10000, Box::new(storage));
    while let Ok(chunk) = grouped_chunks.recv() {
        let threshold = storage.len();
        for (term_id, listing) in chunk {
            let uterm_id = term_id as usize;
            // Get chunk to write to or create if unknown
            let result = {
                let stor_chunk = if uterm_id < threshold {
                    storage.get_current_mut(term_id)
                } else {
                    storage.new_chunk(term_id)
                };
                stor_chunk.append(&listing)
            };
            // Listing did not fit into current chunk completly
            // Get the next and put it in there.
            // Repeat until done
            if let Err(mut position) = result {
                loop {
                    let next_chunk = try!(storage.next_chunk(term_id));
                    if let Err(new_position) = next_chunk.append(&listing[position..]) {
                        if new_position == 0 {
                            // TODO: FIXME
                            panic!("Position list was longer than chunksize. Go Home!");
                        }
                        position += new_position;
                    } else {
                        break;
                    }
                }
            }
        }

    }
    Ok(storage)
}

#[cfg(test)]
mod tests {

    use std::thread;
    use std::sync::mpsc;

    use utils::persistence::Volatile;
    use index::boolean_index::posting::decode_from_storage;
    use storage::RamStorage;

    #[test]
    fn basic_sorting() {
        let (trp_tx, trp_rx) = mpsc::channel();
        let (sorted_tx, sorted_rx) = mpsc::sync_channel(64);

        thread::spawn(|| super::sort_and_group_chunk(trp_rx, sorted_tx));

        // (term_id, doc_id, position)
        // Document 0: "0, 0, 1"
        // Document 1: "0"
        trp_tx.send(vec![(0, 0, 1), (0, 0, 2), (1, 0, 3), (0, 1, 0)]).unwrap();
        assert_eq!(sorted_rx.recv().unwrap(),
                   vec![(0, vec![(0, vec![1, 2]), (1, vec![0])]), (1, vec![(0, vec![3])])]);
    }

    #[test]
    fn extended_sorting() {
        let (trp_tx, trp_rx) = mpsc::channel();
        let (sorted_tx, sorted_rx) = mpsc::sync_channel(64);

        thread::spawn(|| super::sort_and_group_chunk(trp_rx, sorted_tx));

        trp_tx.send((0..100).map(|i| (i, i, i as u32)).collect::<Vec<_>>()).unwrap();
        let sorted = sorted_rx.recv().unwrap();
        assert_eq!(sorted,
                   (0..100).map(|i| (i, vec![(i, vec![i as u32])])).collect::<Vec<_>>());

        trp_tx.send((0..100).map(|i| (i, i, i as u32)).collect::<Vec<_>>()).unwrap();
        let sorted = sorted_rx.recv().unwrap();
        assert_eq!(sorted,
                   (0..100).map(|i| (i, vec![(i, vec![i as u32])])).collect::<Vec<_>>());

        trp_tx.send((200..300).map(|i| (i, i, i as u32)).collect::<Vec<_>>()).unwrap();
        let sorted = sorted_rx.recv().unwrap();
        assert_eq!(sorted,
                   (200..300).map(|i| (i, vec![(i, vec![i as u32])])).collect::<Vec<_>>());
    }

    #[test]
    fn basic_inverting() {
        let (sorted_tx, sorted_rx) = mpsc::sync_channel(64);
        let result = thread::spawn(|| super::invert_index(sorted_rx, RamStorage::new()));

        sorted_tx.send((0..100).map(|i| (i, vec![(i, vec![i as u32])])).collect::<Vec<_>>()).unwrap();
        drop(sorted_tx);

        let chunked_storage = result.join().unwrap().unwrap();
        assert_eq!(chunked_storage.len(), 100);
        assert_eq!(decode_from_storage(&chunked_storage, 0).unwrap(),
                   vec![(0, vec![0u32])]);
        assert_eq!(decode_from_storage(&chunked_storage, 99).unwrap(),
                   vec![(99, vec![99u32])]);
    }

    #[test]
    fn chunk_overflowing_inverting() {
        let (sorted_tx, sorted_rx) = mpsc::sync_channel(64);
        let result = thread::spawn(|| super::invert_index(sorted_rx, RamStorage::new()));

        sorted_tx.send((0..10)
                .map(|i| (i, (i..i+100).map(|k| (k, (0..10).collect::<Vec<_>>())).collect::<Vec<_>>()))
                .collect::<Vec<_>>())
            .unwrap();
        drop(sorted_tx);

        let chunked_storage = result.join().unwrap().unwrap();
        assert_eq!(chunked_storage.len(), 10);
        assert_eq!(decode_from_storage(&chunked_storage, 0).unwrap(),
                   (0..100).map(|k| (k, (0..10).collect::<Vec<_>>())).collect::<Vec<_>>());

    }

}
<|endoftext|>


<commit_before>//! Sanitize incoming packets at the ethernet layer
<commit_msg>net/eth: Add type EthernetPackageSanitizer<commit_after>//! Sanitize incoming packets at the ethernet layer

use core::mem;

use net::Packet;

use net::conn::filter::PacketSanitizer;

use super::defs::Header;

/// Sanitize a packet at the ethernet level
pub struct EthernetPacketSanitizer;

impl PacketSanitizer for EthernetPacketSanitizer {
    /// Determine if the packet is valid at the ethernet level and if we should
    /// accept it
    fn sanitize(pkt: &mut Packet) -> Result<(), ()> {
        // Verify the packet
        // For now we only accept packets that targets directly the interface
        // the packet was received on. The only exception is broadcast packets
        {
            // Incoming packet *MUST* have an interface set
            let intf = try!(pkt.interface().ok_or(()));

            // Get a reference over the ethernet header
            let hdr = try!(pkt.link_header::<Header>().ok_or(()));

            // For now we only accept packets that are either for us or
            // broadcast
            if *intf.read().hw_addr_ref() != hdr.dest &&
                !hdr.dest.is_broadcast() {
                return Err(())
            }
        }

        unsafe {
            // Set the size of the link layer header (i.e. size of the ethernet
            // header)
            *pkt.link_hdr_size_mut() = mem::size_of::<Header>();
        }

        // Accept packet
        Ok(())
    }
}
<|endoftext|>


<commit_before>pub use imp::{gzip, identity, MaybeGzip};

#[cfg(feature = "gzip")]
mod imp {
    use std::io;
    use std::pin::Pin;
    use std::task::{Context, Poll};

    use async_compression::stream::GzipDecoder;
    use bytes::Bytes;
    use futures_core::{Stream, TryStream};
    use futures_util::future::Either;
    use futures_util::ready;
    use pin_project_lite::pin_project;

    use crate::error::Error;

    pub type MaybeGzip<S> = Either<Gzip<S>, S>;

    pin_project! {
        pub struct Gzip<S: TryStream<Ok = Bytes>> {
            #[pin]
            inner: GzipDecoder<Adapter<S>>,
        }
    }

    pin_project! {
        struct Adapter<S>
        where
            S: TryStream,
        {
            #[pin]
            inner: S,
            error: Option<S::Error>,
        }
    }

    impl<S: TryStream<Ok = Bytes>> Gzip<S> {
        fn new(s: S) -> Self {
            Gzip {
                inner: GzipDecoder::new(Adapter {
                    inner: s,
                    error: None,
                }),
            }
        }
    }

    impl<S: TryStream<Ok = Bytes, Error = Error<E>>, E> Stream for Gzip<S> {
        type Item = Result<Bytes, Error<E>>;

        fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
            let mut this = self.project();
            // This cannot be `this.map_ok(..).map_err(..).poll_next(..)`
            // because `this` is borrowed inside `map_err`.
            this.inner.as_mut().poll_next(cx).map(|option| {
                option.map(|result| {
                    result.map_err(|e| {
                        this.inner
                            .get_pin_mut()
                            .project()
                            .error
                            .take()
                            .unwrap_or(Error::Gzip(e))
                    })
                })
            })
        }
    }

    impl<S: TryStream<Ok = Bytes>> Stream for Adapter<S> {
        type Item = io::Result<Bytes>;

        fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
            let mut this = self.project();
            match ready!(this.inner.as_mut().try_poll_next(cx)) {
                Some(result) => Poll::Ready(Some(result.map(Into::into).map_err(|e| {
                    *this.error = Some(e);
                    io::Error::from_raw_os_error(0)
                }))),
                None => Poll::Ready(None),
            }
        }
    }

    pub fn gzip<S: TryStream<Ok = Bytes>>(s: S) -> MaybeGzip<S> {
        Either::Left(Gzip::new(s))
    }

    pub fn identity<S: TryStream<Ok = Bytes>>(s: S) -> MaybeGzip<S> {
        Either::Right(s)
    }
}

#[cfg(not(feature = "gzip"))]
mod imp {
    use bytes::Bytes;
    use futures_core::TryStream;

    pub type MaybeGzip<S> = S;

    pub fn gzip<S: TryStream<Ok = Bytes>>(s: S) -> MaybeGzip<S> {
        s
    }

    pub fn identity<S: TryStream<Ok = Bytes>>(s: S) -> MaybeGzip<S> {
        s
    }
}
<commit_msg>Minor cleanup<commit_after>pub use imp::{gzip, identity, MaybeGzip};

#[cfg(feature = "gzip")]
mod imp {
    use std::io;
    use std::pin::Pin;
    use std::task::{Context, Poll};

    use async_compression::stream::GzipDecoder;
    use bytes::Bytes;
    use futures_core::{Stream, TryStream};
    use futures_util::future::Either;
    use futures_util::ready;
    use pin_project_lite::pin_project;

    use crate::error::Error;

    pub type MaybeGzip<S> = Either<Gzip<S>, S>;

    pin_project! {
        pub struct Gzip<S: TryStream<Ok = Bytes>> {
            #[pin]
            inner: GzipDecoder<Adapter<S>>,
        }
    }

    pin_project! {
        struct Adapter<S>
        where
            S: TryStream,
        {
            #[pin]
            inner: S,
            error: Option<S::Error>,
        }
    }

    impl<S: TryStream<Ok = Bytes>> Gzip<S> {
        fn new(s: S) -> Self {
            Gzip {
                inner: GzipDecoder::new(Adapter {
                    inner: s,
                    error: None,
                }),
            }
        }
    }

    impl<S: TryStream<Ok = Bytes, Error = Error<E>>, E> Stream for Gzip<S> {
        type Item = Result<Bytes, Error<E>>;

        fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
            let mut inner = self.project().inner;
            // This cannot be `Pin::new(&mut inner.map_err(..)).poll_next(cx)`
            // because `inner` is borrowed inside `map_err`.
            inner.as_mut().poll_next(cx).map(|option| {
                option.map(|result| {
                    result.map_err(|e| {
                        inner
                            .get_pin_mut()
                            .project()
                            .error
                            .take()
                            .unwrap_or(Error::Gzip(e))
                    })
                })
            })
        }
    }

    impl<S: TryStream<Ok = Bytes>> Stream for Adapter<S> {
        type Item = io::Result<Bytes>;

        fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
            let mut this = self.project();
            match ready!(this.inner.as_mut().try_poll_next(cx)) {
                Some(result) => Poll::Ready(Some(result.map(Into::into).map_err(|e| {
                    *this.error = Some(e);
                    io::Error::from_raw_os_error(0)
                }))),
                None => Poll::Ready(None),
            }
        }
    }

    pub fn gzip<S: TryStream<Ok = Bytes>>(s: S) -> MaybeGzip<S> {
        Either::Left(Gzip::new(s))
    }

    pub fn identity<S: TryStream<Ok = Bytes>>(s: S) -> MaybeGzip<S> {
        Either::Right(s)
    }
}

#[cfg(not(feature = "gzip"))]
mod imp {
    use bytes::Bytes;
    use futures_core::TryStream;

    pub type MaybeGzip<S> = S;

    pub fn gzip<S: TryStream<Ok = Bytes>>(s: S) -> MaybeGzip<S> {
        s
    }

    pub fn identity<S: TryStream<Ok = Bytes>>(s: S) -> MaybeGzip<S> {
        s
    }
}
<|endoftext|>


<commit_before>use std::old_io;
use std::old_io::{fs, File, IoErrorKind};
use std::collections::BTreeMap;
use std::sync::mpsc::{Sender, Receiver};

use toml::{self, Value};

use serialize::Decodable;

pub struct ConfigReader
{
    config_map: Value, //BTreeMap<String, Value>,
}

impl ConfigReader
{
    pub fn new() -> ConfigReader
    {
        // Create the configuration directory if it does not exist yet.
        let configdir = Path::new("config/");
        // This returns a Result with an error if the directory already exists or the user does not
        // have write permissions. We ignore that possibility for now.
        fs::mkdir(&configdir, old_io::USER_RWX);

        // Open the configuration file.
        let configpath  =  Path::new("config/redstart.toml");
        let mut configfile = match File::open(&configpath)
        {
            // File does exists -> return file descriptor.
            Ok(f) => f,
            // File does *not* exist -> create file, dump default config, return file descriptor
            Err(e) =>
            {
                match e.kind
                {
                    IoErrorKind::PermissionDenied => panic!("Could not read config file. Does it have the correct permissions?"),
                    IoErrorKind::FileNotFound =>
                    {
                        let mut fd = File::create(&configpath);
                        fd.write(b"[General]\r\nname=\"RedStart\"\r\n[Networking]\r\naddress = \"127.0.0.1\"\r\nport = 8080\r\n[Logging]\r\nloglevel = \"NORMAL\"\r\nlogfile = \"log/default.log\"\r\n"
);
                        let mut fd = File::open(&configpath);
                        fd.unwrap()
                    }
                    _ => panic!("File error: {}!", e),
                }
            }
        };
        let configstring = configfile.read_to_string().unwrap();
        let mut configparser = toml::Parser::new(configstring.as_slice());
        let table = match configparser.parse()
        {
            Some(val) => val,
            None => panic!("Configfile parse error! Check config syntax!"),
        };
        println!("{:?}", table);
        let value: Value = Value::Table(table);
        ConfigReader { config_map: value }
    }

    /// Return the value that belongs to the key given. If no value was found, `None` will be returned
    pub fn get_value<T: Decodable>(&mut self, key: &str) -> Option<T>
    {
        match self.config_map.lookup(key)
        {
            Some(value) => toml::decode::<T>(value.clone()),
            None => None
        }
    }

    /// Return the value that belongs to the key given. If no value was found, a given default value
    /// will be returned.
    pub fn get_value_or<T: Decodable>(&mut self, key: &str, default: T) -> T
    {
        match self.get_value::<T>(key)
        {
            Some(e) => e,
            None => default,
        }
    }
}
<commit_msg>RedStart now opens 'config/redstart.toml' relative to the binaries path and not relative to the current working directory<commit_after>use std::os;
use std::old_io;
use std::old_io::{fs, File, IoErrorKind};
use std::collections::BTreeMap;
use std::sync::mpsc::{Sender, Receiver};

use toml::{self, Value};

use serialize::Decodable;

pub struct ConfigReader
{
    config_map: Value, //BTreeMap<String, Value>,
}

impl ConfigReader
{
    pub fn new() -> ConfigReader
    {
        let curr_dir = os::self_exe_path().expect("huh?");
        // Create the configuration directory if it does not exist yet.
        let configdir = curr_dir.join("config/");
        //let configdir = Path::new("config/");
        // This returns a Result with an error if the directory already exists or the user does not
        // have write permissions. We ignore that possibility for now.
        fs::mkdir(&configdir, old_io::USER_RWX);

        // Open the configuration file.
        let configpath  = curr_dir.join("config/redstart.toml");
        //let configpath  = Path::new("config/redstart.toml");
        let mut configfile = match File::open(&configpath)
        {
            // File does exists -> return file descriptor.
            Ok(f) => f,
            // File does *not* exist -> create file, dump default config, return file descriptor
            Err(e) =>
            {
                match e.kind
                {
                    IoErrorKind::PermissionDenied => panic!("Could not read config file. Does it have the correct permissions?"),
                    IoErrorKind::FileNotFound =>
                    {
                        let mut fd = File::create(&configpath);
                        fd.write(b"[General]\r\nname=\"RedStart\"\r\n[Networking]\r\naddress = \"127.0.0.1\"\r\nport = 8080\r\n[Logging]\r\nloglevel = \"NORMAL\"\r\nlogfile = \"log/default.log\"\r\n"
);
                        let mut fd = File::open(&configpath);
                        fd.unwrap()
                    }
                    _ => panic!("File error: {}!", e),
                }
            }
        };
        let configstring = configfile.read_to_string().unwrap();
        let mut configparser = toml::Parser::new(configstring.as_slice());
        let table = match configparser.parse()
        {
            Some(val) => val,
            None => panic!("Configfile parse error! Check config syntax!"),
        };
        println!("{:?}", table);
        let value: Value = Value::Table(table);
        ConfigReader { config_map: value }
    }

    /// Return the value that belongs to the key given. If no value was found, `None` will be returned
    pub fn get_value<T: Decodable>(&mut self, key: &str) -> Option<T>
    {
        match self.config_map.lookup(key)
        {
            Some(value) => toml::decode::<T>(value.clone()),
            None => None
        }
    }

    /// Return the value that belongs to the key given. If no value was found, a given default value
    /// will be returned.
    pub fn get_value_or<T: Decodable>(&mut self, key: &str, default: T) -> T
    {
        match self.get_value::<T>(key)
        {
            Some(e) => e,
            None => default,
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use self::TypeVariableValue::*;
use hir::def_id::{DefId};
use syntax::ast;
use syntax_pos::Span;
use ty::{self, Ty};

use std::cmp::min;
use std::marker::PhantomData;
use std::mem;
use std::u32;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::snapshot_vec as sv;
use rustc_data_structures::unify as ut;

pub struct TypeVariableTable<'tcx> {
    values: sv::SnapshotVec<Delegate<'tcx>>,

    /// Two variables are unified in `eq_relations` when we have a
    /// constraint `?X == ?Y`.
    eq_relations: ut::UnificationTable<ty::TyVid>,

    /// Two variables are unified in `eq_relations` when we have a
    /// constraint `?X <: ?Y` *or* a constraint `?Y <: ?X`. This second
    /// table exists only to help with the occurs check. In particular,
    /// we want to report constraints like these as an occurs check
    /// violation:
    ///
    ///     ?1 <: ?3
    ///     Box<?3> <: ?1
    ///
    /// This works because `?1` and `?3` are unified in the
    /// `sub_relations` relation (not in `eq_relations`). Then when we
    /// process the `Box<?3> <: ?1` constraint, we do an occurs check
    /// on `Box<?3>` and find a potential cycle.
    ///
    /// This is reasonable because, in Rust, subtypes have the same
    /// "skeleton" and hence there is no possible type such that
    /// (e.g.)  `Box<?3> <: ?3` for any `?3`.
    sub_relations: ut::UnificationTable<ty::TyVid>,
}

/// Reasons to create a type inference variable
#[derive(Copy, Clone, Debug)]
pub enum TypeVariableOrigin {
    MiscVariable(Span),
    NormalizeProjectionType(Span),
    TypeInference(Span),
    TypeParameterDefinition(Span, ast::Name),

    /// one of the upvars or closure kind parameters in a `ClosureSubsts`
    /// (before it has been determined)
    ClosureSynthetic(Span),
    SubstitutionPlaceholder(Span),
    AutoDeref(Span),
    AdjustmentType(Span),
    DivergingStmt(Span),
    DivergingBlockExpr(Span),
    DivergingFn(Span),
    LatticeVariable(Span),
    Generalized(ty::TyVid),
}

pub type TypeVariableMap = FxHashMap<ty::TyVid, TypeVariableOrigin>;

struct TypeVariableData<'tcx> {
    value: TypeVariableValue<'tcx>,
    origin: TypeVariableOrigin,
    diverging: bool
}

enum TypeVariableValue<'tcx> {
    Known(Ty<'tcx>),
    Bounded {
        default: Option<Default<'tcx>>
    }
}

// We will use this to store the required information to recapitulate what happened when
// an error occurs.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Default<'tcx> {
    pub ty: Ty<'tcx>,
    /// The span where the default was incurred
    pub origin_span: Span,
    /// The definition that the default originates from
    pub def_id: DefId
}

pub struct Snapshot {
    snapshot: sv::Snapshot,
    eq_snapshot: ut::Snapshot<ty::TyVid>,
    sub_snapshot: ut::Snapshot<ty::TyVid>,
}

struct Instantiate<'tcx> {
    vid: ty::TyVid,
    default: Option<Default<'tcx>>,
}

struct Delegate<'tcx>(PhantomData<&'tcx ()>);

impl<'tcx> TypeVariableTable<'tcx> {
    pub fn new() -> TypeVariableTable<'tcx> {
        TypeVariableTable {
            values: sv::SnapshotVec::new(),
            eq_relations: ut::UnificationTable::new(),
            sub_relations: ut::UnificationTable::new(),
        }
    }

    pub fn default(&self, vid: ty::TyVid) -> Option<Default<'tcx>> {
        match &self.values.get(vid.index as usize).value {
            &Known(_) => None,
            &Bounded { ref default, .. } => default.clone()
        }
    }

    pub fn var_diverges<'a>(&'a self, vid: ty::TyVid) -> bool {
        self.values.get(vid.index as usize).diverging
    }

    pub fn var_origin(&self, vid: ty::TyVid) -> &TypeVariableOrigin {
        &self.values.get(vid.index as usize).origin
    }

    /// Records that `a == b`, depending on `dir`.
    ///
    /// Precondition: neither `a` nor `b` are known.
    pub fn equate(&mut self, a: ty::TyVid, b: ty::TyVid) {
        debug_assert!(self.probe(a).is_none());
        debug_assert!(self.probe(b).is_none());
        self.eq_relations.union(a, b);
        self.sub_relations.union(a, b);
    }

    /// Records that `a <: b`, depending on `dir`.
    ///
    /// Precondition: neither `a` nor `b` are known.
    pub fn sub(&mut self, a: ty::TyVid, b: ty::TyVid) {
        debug_assert!(self.probe(a).is_none());
        debug_assert!(self.probe(b).is_none());
        self.sub_relations.union(a, b);
    }

    /// Instantiates `vid` with the type `ty`.
    ///
    /// Precondition: `vid` must not have been previously instantiated.
    pub fn instantiate(&mut self, vid: ty::TyVid, ty: Ty<'tcx>) {
        let vid = self.root_var(vid);
        debug_assert!(self.probe_root(vid).is_none());

        let old_value = {
            let vid_data = &mut self.values[vid.index as usize];
            mem::replace(&mut vid_data.value, TypeVariableValue::Known(ty))
        };

        match old_value {
            TypeVariableValue::Bounded { default } => {
                self.values.record(Instantiate { vid: vid, default: default });
            }
            TypeVariableValue::Known(old_ty) => {
                bug!("instantiating type variable `{:?}` twice: new-value = {:?}, old-value={:?}",
                     vid, ty, old_ty)
            }
        }
    }

    pub fn new_var(&mut self,
                   diverging: bool,
                   origin: TypeVariableOrigin,
                   default: Option<Default<'tcx>>,) -> ty::TyVid {
        debug!("new_var(diverging={:?}, origin={:?})", diverging, origin);
        self.eq_relations.new_key(());
        self.sub_relations.new_key(());
        let index = self.values.push(TypeVariableData {
            value: Bounded { default: default },
            origin,
            diverging,
        });
        let v = ty::TyVid { index: index as u32 };
        debug!("new_var: diverging={:?} index={:?}", diverging, v);
        v
    }

    pub fn num_vars(&self) -> usize {
        self.values.len()
    }

    /// Returns the "root" variable of `vid` in the `eq_relations`
    /// equivalence table. All type variables that have been equated
    /// will yield the same root variable (per the union-find
    /// algorithm), so `root_var(a) == root_var(b)` implies that `a ==
    /// b` (transitively).
    pub fn root_var(&mut self, vid: ty::TyVid) -> ty::TyVid {
        self.eq_relations.find(vid)
    }

    /// Returns the "root" variable of `vid` in the `sub_relations`
    /// equivalence table. All type variables that have been are
    /// related via equality or subtyping will yield the same root
    /// variable (per the union-find algorithm), so `sub_root_var(a)
    /// == sub_root_var(b)` implies that:
    ///
    ///     exists X. (a <: X || X <: a) && (b <: X || X <: b)
    pub fn sub_root_var(&mut self, vid: ty::TyVid) -> ty::TyVid {
        self.sub_relations.find(vid)
    }

    /// True if `a` and `b` have same "sub-root" (i.e., exists some
    /// type X such that `forall i in {a, b}. (i <: X || X <: i)`.
    pub fn sub_unified(&mut self, a: ty::TyVid, b: ty::TyVid) -> bool {
        self.sub_root_var(a) == self.sub_root_var(b)
    }

    pub fn probe(&mut self, vid: ty::TyVid) -> Option<Ty<'tcx>> {
        let vid = self.root_var(vid);
        self.probe_root(vid)
    }

    pub fn origin(&self, vid: ty::TyVid) -> TypeVariableOrigin {
        self.values.get(vid.index as usize).origin.clone()
    }

    /// Retrieves the type of `vid` given that it is currently a root in the unification table
    pub fn probe_root(&mut self, vid: ty::TyVid) -> Option<Ty<'tcx>> {
        debug_assert!(self.root_var(vid) == vid);
        match self.values.get(vid.index as usize).value {
            Bounded { .. } => None,
            Known(t) => Some(t)
        }
    }

    pub fn replace_if_possible(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
        match t.sty {
            ty::TyInfer(ty::TyVar(v)) => {
                match self.probe(v) {
                    None => t,
                    Some(u) => u
                }
            }
            _ => t,
        }
    }

    pub fn snapshot(&mut self) -> Snapshot {
        Snapshot {
            snapshot: self.values.start_snapshot(),
            eq_snapshot: self.eq_relations.snapshot(),
            sub_snapshot: self.sub_relations.snapshot(),
        }
    }

    pub fn rollback_to(&mut self, s: Snapshot) {
        debug!("rollback_to{:?}", {
            for action in self.values.actions_since_snapshot(&s.snapshot) {
                match *action {
                    sv::UndoLog::NewElem(index) => {
                        debug!("inference variable _#{}t popped", index)
                    }
                    _ => { }
                }
            }
        });

        let Snapshot { snapshot, eq_snapshot, sub_snapshot } = s;
        self.values.rollback_to(snapshot);
        self.eq_relations.rollback_to(eq_snapshot);
        self.sub_relations.rollback_to(sub_snapshot);
    }

    pub fn commit(&mut self, s: Snapshot) {
        let Snapshot { snapshot, eq_snapshot, sub_snapshot } = s;
        self.values.commit(snapshot);
        self.eq_relations.commit(eq_snapshot);
        self.sub_relations.commit(sub_snapshot);
    }

    /// Returns a map `{V1 -> V2}`, where the keys `{V1}` are
    /// ty-variables created during the snapshot, and the values
    /// `{V2}` are the root variables that they were unified with,
    /// along with their origin.
    pub fn types_created_since_snapshot(&mut self, s: &Snapshot) -> TypeVariableMap {
        let actions_since_snapshot = self.values.actions_since_snapshot(&s.snapshot);

        actions_since_snapshot
            .iter()
            .filter_map(|action| match action {
                &sv::UndoLog::NewElem(index) => Some(ty::TyVid { index: index as u32 }),
                _ => None,
            })
            .map(|vid| {
                let origin = self.values.get(vid.index as usize).origin.clone();
                (vid, origin)
            })
            .collect()
    }

    pub fn types_escaping_snapshot(&mut self, s: &Snapshot) -> Vec<Ty<'tcx>> {
        /*!
         * Find the set of type variables that existed *before* `s`
         * but which have only been unified since `s` started, and
         * return the types with which they were unified. So if we had
         * a type variable `V0`, then we started the snapshot, then we
         * created a type variable `V1`, unifed `V0` with `T0`, and
         * unified `V1` with `T1`, this function would return `{T0}`.
         */

        let mut new_elem_threshold = u32::MAX;
        let mut escaping_types = Vec::new();
        let actions_since_snapshot = self.values.actions_since_snapshot(&s.snapshot);
        debug!("actions_since_snapshot.len() = {}", actions_since_snapshot.len());
        for action in actions_since_snapshot {
            match *action {
                sv::UndoLog::NewElem(index) => {
                    // if any new variables were created during the
                    // snapshot, remember the lower index (which will
                    // always be the first one we see). Note that this
                    // action must precede those variables being
                    // specified.
                    new_elem_threshold = min(new_elem_threshold, index as u32);
                    debug!("NewElem({}) new_elem_threshold={}", index, new_elem_threshold);
                }

                sv::UndoLog::Other(Instantiate { vid, .. }) => {
                    if vid.index < new_elem_threshold {
                        // quick check to see if this variable was
                        // created since the snapshot started or not.
                        let escaping_type = match self.values.get(vid.index as usize).value {
                            Bounded { .. } => bug!(),
                            Known(ty) => ty,
                        };
                        escaping_types.push(escaping_type);
                    }
                    debug!("SpecifyVar({:?}) new_elem_threshold={}", vid, new_elem_threshold);
                }

                _ => { }
            }
        }

        escaping_types
    }

    pub fn unsolved_variables(&mut self) -> Vec<ty::TyVid> {
        (0..self.values.len())
            .filter_map(|i| {
                let vid = ty::TyVid { index: i as u32 };
                if self.probe(vid).is_some() {
                    None
                } else {
                    Some(vid)
                }
            })
            .collect()
    }
}

impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> {
    type Value = TypeVariableData<'tcx>;
    type Undo = Instantiate<'tcx>;

    fn reverse(values: &mut Vec<TypeVariableData<'tcx>>, action: Instantiate<'tcx>) {
        let Instantiate { vid, default } = action;
        values[vid.index as usize].value = Bounded {
            default,
        };
    }
}
<commit_msg>use `{}` for `Known` variant just for more parity<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use self::TypeVariableValue::*;
use hir::def_id::{DefId};
use syntax::ast;
use syntax_pos::Span;
use ty::{self, Ty};

use std::cmp::min;
use std::marker::PhantomData;
use std::mem;
use std::u32;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::snapshot_vec as sv;
use rustc_data_structures::unify as ut;

pub struct TypeVariableTable<'tcx> {
    values: sv::SnapshotVec<Delegate<'tcx>>,

    /// Two variables are unified in `eq_relations` when we have a
    /// constraint `?X == ?Y`.
    eq_relations: ut::UnificationTable<ty::TyVid>,

    /// Two variables are unified in `eq_relations` when we have a
    /// constraint `?X <: ?Y` *or* a constraint `?Y <: ?X`. This second
    /// table exists only to help with the occurs check. In particular,
    /// we want to report constraints like these as an occurs check
    /// violation:
    ///
    ///     ?1 <: ?3
    ///     Box<?3> <: ?1
    ///
    /// This works because `?1` and `?3` are unified in the
    /// `sub_relations` relation (not in `eq_relations`). Then when we
    /// process the `Box<?3> <: ?1` constraint, we do an occurs check
    /// on `Box<?3>` and find a potential cycle.
    ///
    /// This is reasonable because, in Rust, subtypes have the same
    /// "skeleton" and hence there is no possible type such that
    /// (e.g.)  `Box<?3> <: ?3` for any `?3`.
    sub_relations: ut::UnificationTable<ty::TyVid>,
}

/// Reasons to create a type inference variable
#[derive(Copy, Clone, Debug)]
pub enum TypeVariableOrigin {
    MiscVariable(Span),
    NormalizeProjectionType(Span),
    TypeInference(Span),
    TypeParameterDefinition(Span, ast::Name),

    /// one of the upvars or closure kind parameters in a `ClosureSubsts`
    /// (before it has been determined)
    ClosureSynthetic(Span),
    SubstitutionPlaceholder(Span),
    AutoDeref(Span),
    AdjustmentType(Span),
    DivergingStmt(Span),
    DivergingBlockExpr(Span),
    DivergingFn(Span),
    LatticeVariable(Span),
    Generalized(ty::TyVid),
}

pub type TypeVariableMap = FxHashMap<ty::TyVid, TypeVariableOrigin>;

struct TypeVariableData<'tcx> {
    value: TypeVariableValue<'tcx>,
    origin: TypeVariableOrigin,
    diverging: bool
}

enum TypeVariableValue<'tcx> {
    Known {
        value: Ty<'tcx>
    },
    Bounded {
        default: Option<Default<'tcx>>
    }
}

// We will use this to store the required information to recapitulate what happened when
// an error occurs.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Default<'tcx> {
    pub ty: Ty<'tcx>,
    /// The span where the default was incurred
    pub origin_span: Span,
    /// The definition that the default originates from
    pub def_id: DefId
}

pub struct Snapshot {
    snapshot: sv::Snapshot,
    eq_snapshot: ut::Snapshot<ty::TyVid>,
    sub_snapshot: ut::Snapshot<ty::TyVid>,
}

struct Instantiate<'tcx> {
    vid: ty::TyVid,
    default: Option<Default<'tcx>>,
}

struct Delegate<'tcx>(PhantomData<&'tcx ()>);

impl<'tcx> TypeVariableTable<'tcx> {
    pub fn new() -> TypeVariableTable<'tcx> {
        TypeVariableTable {
            values: sv::SnapshotVec::new(),
            eq_relations: ut::UnificationTable::new(),
            sub_relations: ut::UnificationTable::new(),
        }
    }

    pub fn default(&self, vid: ty::TyVid) -> Option<Default<'tcx>> {
        match &self.values.get(vid.index as usize).value {
            &Known { .. } => None,
            &Bounded { ref default, .. } => default.clone()
        }
    }

    pub fn var_diverges<'a>(&'a self, vid: ty::TyVid) -> bool {
        self.values.get(vid.index as usize).diverging
    }

    pub fn var_origin(&self, vid: ty::TyVid) -> &TypeVariableOrigin {
        &self.values.get(vid.index as usize).origin
    }

    /// Records that `a == b`, depending on `dir`.
    ///
    /// Precondition: neither `a` nor `b` are known.
    pub fn equate(&mut self, a: ty::TyVid, b: ty::TyVid) {
        debug_assert!(self.probe(a).is_none());
        debug_assert!(self.probe(b).is_none());
        self.eq_relations.union(a, b);
        self.sub_relations.union(a, b);
    }

    /// Records that `a <: b`, depending on `dir`.
    ///
    /// Precondition: neither `a` nor `b` are known.
    pub fn sub(&mut self, a: ty::TyVid, b: ty::TyVid) {
        debug_assert!(self.probe(a).is_none());
        debug_assert!(self.probe(b).is_none());
        self.sub_relations.union(a, b);
    }

    /// Instantiates `vid` with the type `ty`.
    ///
    /// Precondition: `vid` must not have been previously instantiated.
    pub fn instantiate(&mut self, vid: ty::TyVid, ty: Ty<'tcx>) {
        let vid = self.root_var(vid);
        debug_assert!(self.probe_root(vid).is_none());

        let old_value = {
            let vid_data = &mut self.values[vid.index as usize];
            mem::replace(&mut vid_data.value, TypeVariableValue::Known { value: ty })
        };

        match old_value {
            TypeVariableValue::Bounded { default } => {
                self.values.record(Instantiate { vid: vid, default: default });
            }
            TypeVariableValue::Known { value: old_ty } => {
                bug!("instantiating type variable `{:?}` twice: new-value = {:?}, old-value={:?}",
                     vid, ty, old_ty)
            }
        }
    }

    pub fn new_var(&mut self,
                   diverging: bool,
                   origin: TypeVariableOrigin,
                   default: Option<Default<'tcx>>,) -> ty::TyVid {
        debug!("new_var(diverging={:?}, origin={:?})", diverging, origin);
        self.eq_relations.new_key(());
        self.sub_relations.new_key(());
        let index = self.values.push(TypeVariableData {
            value: Bounded { default: default },
            origin,
            diverging,
        });
        let v = ty::TyVid { index: index as u32 };
        debug!("new_var: diverging={:?} index={:?}", diverging, v);
        v
    }

    pub fn num_vars(&self) -> usize {
        self.values.len()
    }

    /// Returns the "root" variable of `vid` in the `eq_relations`
    /// equivalence table. All type variables that have been equated
    /// will yield the same root variable (per the union-find
    /// algorithm), so `root_var(a) == root_var(b)` implies that `a ==
    /// b` (transitively).
    pub fn root_var(&mut self, vid: ty::TyVid) -> ty::TyVid {
        self.eq_relations.find(vid)
    }

    /// Returns the "root" variable of `vid` in the `sub_relations`
    /// equivalence table. All type variables that have been are
    /// related via equality or subtyping will yield the same root
    /// variable (per the union-find algorithm), so `sub_root_var(a)
    /// == sub_root_var(b)` implies that:
    ///
    ///     exists X. (a <: X || X <: a) && (b <: X || X <: b)
    pub fn sub_root_var(&mut self, vid: ty::TyVid) -> ty::TyVid {
        self.sub_relations.find(vid)
    }

    /// True if `a` and `b` have same "sub-root" (i.e., exists some
    /// type X such that `forall i in {a, b}. (i <: X || X <: i)`.
    pub fn sub_unified(&mut self, a: ty::TyVid, b: ty::TyVid) -> bool {
        self.sub_root_var(a) == self.sub_root_var(b)
    }

    pub fn probe(&mut self, vid: ty::TyVid) -> Option<Ty<'tcx>> {
        let vid = self.root_var(vid);
        self.probe_root(vid)
    }

    pub fn origin(&self, vid: ty::TyVid) -> TypeVariableOrigin {
        self.values.get(vid.index as usize).origin.clone()
    }

    /// Retrieves the type of `vid` given that it is currently a root in the unification table
    pub fn probe_root(&mut self, vid: ty::TyVid) -> Option<Ty<'tcx>> {
        debug_assert!(self.root_var(vid) == vid);
        match self.values.get(vid.index as usize).value {
            Bounded { .. } => None,
            Known { value } => Some(value)
        }
    }

    pub fn replace_if_possible(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
        match t.sty {
            ty::TyInfer(ty::TyVar(v)) => {
                match self.probe(v) {
                    None => t,
                    Some(u) => u
                }
            }
            _ => t,
        }
    }

    pub fn snapshot(&mut self) -> Snapshot {
        Snapshot {
            snapshot: self.values.start_snapshot(),
            eq_snapshot: self.eq_relations.snapshot(),
            sub_snapshot: self.sub_relations.snapshot(),
        }
    }

    pub fn rollback_to(&mut self, s: Snapshot) {
        debug!("rollback_to{:?}", {
            for action in self.values.actions_since_snapshot(&s.snapshot) {
                match *action {
                    sv::UndoLog::NewElem(index) => {
                        debug!("inference variable _#{}t popped", index)
                    }
                    _ => { }
                }
            }
        });

        let Snapshot { snapshot, eq_snapshot, sub_snapshot } = s;
        self.values.rollback_to(snapshot);
        self.eq_relations.rollback_to(eq_snapshot);
        self.sub_relations.rollback_to(sub_snapshot);
    }

    pub fn commit(&mut self, s: Snapshot) {
        let Snapshot { snapshot, eq_snapshot, sub_snapshot } = s;
        self.values.commit(snapshot);
        self.eq_relations.commit(eq_snapshot);
        self.sub_relations.commit(sub_snapshot);
    }

    /// Returns a map `{V1 -> V2}`, where the keys `{V1}` are
    /// ty-variables created during the snapshot, and the values
    /// `{V2}` are the root variables that they were unified with,
    /// along with their origin.
    pub fn types_created_since_snapshot(&mut self, s: &Snapshot) -> TypeVariableMap {
        let actions_since_snapshot = self.values.actions_since_snapshot(&s.snapshot);

        actions_since_snapshot
            .iter()
            .filter_map(|action| match action {
                &sv::UndoLog::NewElem(index) => Some(ty::TyVid { index: index as u32 }),
                _ => None,
            })
            .map(|vid| {
                let origin = self.values.get(vid.index as usize).origin.clone();
                (vid, origin)
            })
            .collect()
    }

    pub fn types_escaping_snapshot(&mut self, s: &Snapshot) -> Vec<Ty<'tcx>> {
        /*!
         * Find the set of type variables that existed *before* `s`
         * but which have only been unified since `s` started, and
         * return the types with which they were unified. So if we had
         * a type variable `V0`, then we started the snapshot, then we
         * created a type variable `V1`, unifed `V0` with `T0`, and
         * unified `V1` with `T1`, this function would return `{T0}`.
         */

        let mut new_elem_threshold = u32::MAX;
        let mut escaping_types = Vec::new();
        let actions_since_snapshot = self.values.actions_since_snapshot(&s.snapshot);
        debug!("actions_since_snapshot.len() = {}", actions_since_snapshot.len());
        for action in actions_since_snapshot {
            match *action {
                sv::UndoLog::NewElem(index) => {
                    // if any new variables were created during the
                    // snapshot, remember the lower index (which will
                    // always be the first one we see). Note that this
                    // action must precede those variables being
                    // specified.
                    new_elem_threshold = min(new_elem_threshold, index as u32);
                    debug!("NewElem({}) new_elem_threshold={}", index, new_elem_threshold);
                }

                sv::UndoLog::Other(Instantiate { vid, .. }) => {
                    if vid.index < new_elem_threshold {
                        // quick check to see if this variable was
                        // created since the snapshot started or not.
                        let escaping_type = match self.values.get(vid.index as usize).value {
                            Bounded { .. } => bug!(),
                            Known { value } => value,
                        };
                        escaping_types.push(escaping_type);
                    }
                    debug!("SpecifyVar({:?}) new_elem_threshold={}", vid, new_elem_threshold);
                }

                _ => { }
            }
        }

        escaping_types
    }

    pub fn unsolved_variables(&mut self) -> Vec<ty::TyVid> {
        (0..self.values.len())
            .filter_map(|i| {
                let vid = ty::TyVid { index: i as u32 };
                if self.probe(vid).is_some() {
                    None
                } else {
                    Some(vid)
                }
            })
            .collect()
    }
}

impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> {
    type Value = TypeVariableData<'tcx>;
    type Undo = Instantiate<'tcx>;

    fn reverse(values: &mut Vec<TypeVariableData<'tcx>>, action: Instantiate<'tcx>) {
        let Instantiate { vid, default } = action;
        values[vid.index as usize].value = Bounded {
            default,
        };
    }
}
<|endoftext|>


<commit_before>#![allow(unknown_lints)]

use ty::layout::{Align, HasDataLayout, Size};
use ty;

use super::{EvalResult, Pointer, PointerArithmetic, Allocation};

/// Represents a constant value in Rust. ByVal and ScalarPair are optimizations which
/// matches Value's optimizations for easy conversions between these two types
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash)]
pub enum ConstValue<'tcx> {
    /// Used only for types with layout::abi::Scalar ABI and ZSTs which use Scalar::Undef
    Scalar(Scalar),
    /// Used only for types with layout::abi::ScalarPair
    ScalarPair(Scalar, Scalar),
    /// Used only for the remaining cases. An allocation + offset into the allocation
    ByRef(&'tcx Allocation, Size),
}

impl<'tcx> ConstValue<'tcx> {
    #[inline]
    pub fn from_byval_value(val: Value) -> Self {
        match val {
            Value::ByRef(..) => bug!(),
            Value::ScalarPair(a, b) => ConstValue::ScalarPair(a, b),
            Value::Scalar(val) => ConstValue::Scalar(val),
        }
    }

    #[inline]
    pub fn to_byval_value(&self) -> Option<Value> {
        match *self {
            ConstValue::ByRef(..) => None,
            ConstValue::ScalarPair(a, b) => Some(Value::ScalarPair(a, b)),
            ConstValue::Scalar(val) => Some(Value::Scalar(val)),
        }
    }

    #[inline]
    pub fn from_primval(val: Scalar) -> Self {
        ConstValue::Scalar(val)
    }

    #[inline]
    pub fn to_primval(&self) -> Option<Scalar> {
        match *self {
            ConstValue::ByRef(..) => None,
            ConstValue::ScalarPair(..) => None,
            ConstValue::Scalar(val) => Some(val),
        }
    }

    #[inline]
    pub fn to_bits(&self, size: Size) -> Option<u128> {
        self.to_primval()?.to_bits(size).ok()
    }

    #[inline]
    pub fn to_ptr(&self) -> Option<Pointer> {
        self.to_primval()?.to_ptr().ok()
    }
}

/// A `Value` represents a single self-contained Rust value.
///
/// A `Value` can either refer to a block of memory inside an allocation (`ByRef`) or to a primitve
/// value held directly, outside of any allocation (`ByVal`).  For `ByRef`-values, we remember
/// whether the pointer is supposed to be aligned or not (also see Place).
///
/// For optimization of a few very common cases, there is also a representation for a pair of
/// primitive values (`ScalarPair`). It allows Miri to avoid making allocations for checked binary
/// operations and fat pointers. This idea was taken from rustc's codegen.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
pub enum Value {
    ByRef(Scalar, Align),
    Scalar(Scalar),
    ScalarPair(Scalar, Scalar),
}

impl<'tcx> ty::TypeFoldable<'tcx> for Value {
    fn super_fold_with<'gcx: 'tcx, F: ty::fold::TypeFolder<'gcx, 'tcx>>(&self, _: &mut F) -> Self {
        *self
    }
    fn super_visit_with<V: ty::fold::TypeVisitor<'tcx>>(&self, _: &mut V) -> bool {
        false
    }
}

impl<'tcx> Scalar {
    pub fn ptr_null<C: HasDataLayout>(cx: C) -> Self {
        Scalar::Bits {
            bits: 0,
            defined: cx.data_layout().pointer_size.bits() as u8,
    }
    }

    pub fn ptr_signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> EvalResult<'tcx, Self> {
        let layout = cx.data_layout();
        match self {
            Scalar::Bits { bits, defined } => {
                let pointer_size = layout.pointer_size.bits() as u8;
                if defined < pointer_size {
                    err!(ReadUndefBytes)
                } else {
                    Ok(Scalar::Bits {
                        bits: layout.signed_offset(bits as u64, i)? as u128,
                        defined: pointer_size,
                    })
            }
            }
            Scalar::Ptr(ptr) => ptr.signed_offset(i, layout).map(Scalar::Ptr),
        }
    }

    pub fn ptr_offset<C: HasDataLayout>(self, i: Size, cx: C) -> EvalResult<'tcx, Self> {
        let layout = cx.data_layout();
        match self {
            Scalar::Bits { bits, defined } => {
                let pointer_size = layout.pointer_size.bits() as u8;
                if defined < pointer_size {
                    err!(ReadUndefBytes)
                } else {
                    Ok(Scalar::Bits {
                        bits: layout.offset(bits as u64, i.bytes())? as u128,
                        defined: pointer_size,
                    })
            }
            }
            Scalar::Ptr(ptr) => ptr.offset(i, layout).map(Scalar::Ptr),
        }
    }

    pub fn ptr_wrapping_signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> EvalResult<'tcx, Self> {
        let layout = cx.data_layout();
        match self {
            Scalar::Bits { bits, defined } => {
                let pointer_size = layout.pointer_size.bits() as u8;
                if defined < pointer_size {
                    err!(ReadUndefBytes)
                } else {
                    Ok(Scalar::Bits {
                        bits: layout.wrapping_signed_offset(bits as u64, i) as u128,
                        defined: pointer_size,
                    })
            }
            }
            Scalar::Ptr(ptr) => Ok(Scalar::Ptr(ptr.wrapping_signed_offset(i, layout))),
        }
    }

    pub fn is_null_ptr<C: HasDataLayout>(self, cx: C) -> EvalResult<'tcx, bool> {
        match self {
            Scalar::Bits {
                bits, defined,
            } => if defined < cx.data_layout().pointer_size.bits() as u8 {
                err!(ReadUndefBytes)
            } else {
                Ok(bits == 0)
            },
            Scalar::Ptr(_) => Ok(false),
        }
    }

    pub fn to_value_with_len<C: HasDataLayout>(self, len: u64, cx: C) -> Value {
        Value::ScalarPair(self, Scalar::Bits {
            bits: len as u128,
            defined: cx.data_layout().pointer_size.bits() as u8,
        })
    }

    pub fn to_value_with_vtable(self, vtable: Pointer) -> Value {
        Value::ScalarPair(self, Scalar::Ptr(vtable))
    }

    pub fn to_value(self) -> Value {
        Value::Scalar(self)
    }
}

impl From<Pointer> for Scalar {
    fn from(ptr: Pointer) -> Self {
        Scalar::Ptr(ptr)
    }
}

/// A `Scalar` represents an immediate, primitive value existing outside of a
/// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 8 bytes in
/// size. Like a range of bytes in an `Allocation`, a `Scalar` can either represent the raw bytes
/// of a simple value or a pointer into another `Allocation`
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
pub enum Scalar {
    /// The raw bytes of a simple value.
    Bits {
        /// number of bits that are valid and may be read
        defined: u8,
        bits: u128,
    },

    /// A pointer into an `Allocation`. An `Allocation` in the `memory` module has a list of
    /// relocations, but a `Scalar` is only large enough to contain one, so we just represent the
    /// relocation and its associated offset together as a `Pointer` here.
    Ptr(Pointer),
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ScalarKind {
    I8, I16, I32, I64, I128,
    U8, U16, U32, U64, U128,
    F32, F64,
    Ptr, FnPtr,
    Bool,
    Char,
}

impl<'tcx> Scalar {
    pub fn undef() -> Self {
        Scalar::Bits { bits: 0, defined: 0 }
    }

    pub fn from_bool(b: bool) -> Self {
        // FIXME: can we make defined `1`?
        Scalar::Bits { bits: b as u128, defined: 8 }
    }

    pub fn from_char(c: char) -> Self {
        Scalar::Bits { bits: c as u128, defined: 32 }
    }

    pub fn to_bits(self, size: Size) -> EvalResult<'tcx, u128> {
        match self {
            Scalar::Bits { defined: 0, .. } => err!(ReadUndefBytes),
            Scalar::Bits { bits, defined } if size.bits() <= defined as u64 => Ok(bits),
            Scalar::Bits { .. } => err!(ReadUndefBytes),
            Scalar::Ptr(_) => err!(ReadPointerAsBytes),
        }
    }

    pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
        match self {
            Scalar::Bits {..} => err!(ReadBytesAsPointer),
            Scalar::Ptr(p) => Ok(p),
        }
    }

    pub fn is_bits(self) -> bool {
        match self {
            Scalar::Bits { .. } => true,
            _ => false,
        }
    }

    pub fn is_ptr(self) -> bool {
        match self {
            Scalar::Ptr(_) => true,
            _ => false,
        }
    }

    pub fn to_bool(self) -> EvalResult<'tcx, bool> {
        match self {
            Scalar::Bits { bits: 0, defined: 8 } => Ok(false),
            Scalar::Bits { bits: 1, defined: 8 } => Ok(true),
            _ => err!(InvalidBool),
        }
    }
}

impl ScalarKind {
    pub fn is_int(self) -> bool {
        use self::ScalarKind::*;
        match self {
            I8 | I16 | I32 | I64 | I128 | U8 | U16 | U32 | U64 | U128 => true,
            _ => false,
        }
    }

    pub fn is_signed_int(self) -> bool {
        use self::ScalarKind::*;
        match self {
            I8 | I16 | I32 | I64 | I128 => true,
            _ => false,
        }
    }

    pub fn is_float(self) -> bool {
        use self::ScalarKind::*;
        match self {
            F32 | F64 => true,
            _ => false,
        }
    }

    pub fn from_uint_size(size: Size) -> Self {
        match size.bytes() {
            1 => ScalarKind::U8,
            2 => ScalarKind::U16,
            4 => ScalarKind::U32,
            8 => ScalarKind::U64,
            16 => ScalarKind::U128,
            _ => bug!("can't make uint with size {}", size.bytes()),
        }
    }

    pub fn from_int_size(size: Size) -> Self {
        match size.bytes() {
            1 => ScalarKind::I8,
            2 => ScalarKind::I16,
            4 => ScalarKind::I32,
            8 => ScalarKind::I64,
            16 => ScalarKind::I128,
            _ => bug!("can't make int with size {}", size.bytes()),
        }
    }

    pub fn is_ptr(self) -> bool {
        use self::ScalarKind::*;
        match self {
            Ptr | FnPtr => true,
            _ => false,
        }
    }
}
<commit_msg>Formatting nit<commit_after>#![allow(unknown_lints)]

use ty::layout::{Align, HasDataLayout, Size};
use ty;

use super::{EvalResult, Pointer, PointerArithmetic, Allocation};

/// Represents a constant value in Rust. ByVal and ScalarPair are optimizations which
/// matches Value's optimizations for easy conversions between these two types
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash)]
pub enum ConstValue<'tcx> {
    /// Used only for types with layout::abi::Scalar ABI and ZSTs which use Scalar::Undef
    Scalar(Scalar),
    /// Used only for types with layout::abi::ScalarPair
    ScalarPair(Scalar, Scalar),
    /// Used only for the remaining cases. An allocation + offset into the allocation
    ByRef(&'tcx Allocation, Size),
}

impl<'tcx> ConstValue<'tcx> {
    #[inline]
    pub fn from_byval_value(val: Value) -> Self {
        match val {
            Value::ByRef(..) => bug!(),
            Value::ScalarPair(a, b) => ConstValue::ScalarPair(a, b),
            Value::Scalar(val) => ConstValue::Scalar(val),
        }
    }

    #[inline]
    pub fn to_byval_value(&self) -> Option<Value> {
        match *self {
            ConstValue::ByRef(..) => None,
            ConstValue::ScalarPair(a, b) => Some(Value::ScalarPair(a, b)),
            ConstValue::Scalar(val) => Some(Value::Scalar(val)),
        }
    }

    #[inline]
    pub fn from_primval(val: Scalar) -> Self {
        ConstValue::Scalar(val)
    }

    #[inline]
    pub fn to_primval(&self) -> Option<Scalar> {
        match *self {
            ConstValue::ByRef(..) => None,
            ConstValue::ScalarPair(..) => None,
            ConstValue::Scalar(val) => Some(val),
        }
    }

    #[inline]
    pub fn to_bits(&self, size: Size) -> Option<u128> {
        self.to_primval()?.to_bits(size).ok()
    }

    #[inline]
    pub fn to_ptr(&self) -> Option<Pointer> {
        self.to_primval()?.to_ptr().ok()
    }
}

/// A `Value` represents a single self-contained Rust value.
///
/// A `Value` can either refer to a block of memory inside an allocation (`ByRef`) or to a primitve
/// value held directly, outside of any allocation (`ByVal`).  For `ByRef`-values, we remember
/// whether the pointer is supposed to be aligned or not (also see Place).
///
/// For optimization of a few very common cases, there is also a representation for a pair of
/// primitive values (`ScalarPair`). It allows Miri to avoid making allocations for checked binary
/// operations and fat pointers. This idea was taken from rustc's codegen.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
pub enum Value {
    ByRef(Scalar, Align),
    Scalar(Scalar),
    ScalarPair(Scalar, Scalar),
}

impl<'tcx> ty::TypeFoldable<'tcx> for Value {
    fn super_fold_with<'gcx: 'tcx, F: ty::fold::TypeFolder<'gcx, 'tcx>>(&self, _: &mut F) -> Self {
        *self
    }
    fn super_visit_with<V: ty::fold::TypeVisitor<'tcx>>(&self, _: &mut V) -> bool {
        false
    }
}

impl<'tcx> Scalar {
    pub fn ptr_null<C: HasDataLayout>(cx: C) -> Self {
        Scalar::Bits {
            bits: 0,
            defined: cx.data_layout().pointer_size.bits() as u8,
        }
    }

    pub fn ptr_signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> EvalResult<'tcx, Self> {
        let layout = cx.data_layout();
        match self {
            Scalar::Bits { bits, defined } => {
                let pointer_size = layout.pointer_size.bits() as u8;
                if defined < pointer_size {
                    err!(ReadUndefBytes)
                } else {
                    Ok(Scalar::Bits {
                        bits: layout.signed_offset(bits as u64, i)? as u128,
                        defined: pointer_size,
                    })
            }
            }
            Scalar::Ptr(ptr) => ptr.signed_offset(i, layout).map(Scalar::Ptr),
        }
    }

    pub fn ptr_offset<C: HasDataLayout>(self, i: Size, cx: C) -> EvalResult<'tcx, Self> {
        let layout = cx.data_layout();
        match self {
            Scalar::Bits { bits, defined } => {
                let pointer_size = layout.pointer_size.bits() as u8;
                if defined < pointer_size {
                    err!(ReadUndefBytes)
                } else {
                    Ok(Scalar::Bits {
                        bits: layout.offset(bits as u64, i.bytes())? as u128,
                        defined: pointer_size,
                    })
            }
            }
            Scalar::Ptr(ptr) => ptr.offset(i, layout).map(Scalar::Ptr),
        }
    }

    pub fn ptr_wrapping_signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> EvalResult<'tcx, Self> {
        let layout = cx.data_layout();
        match self {
            Scalar::Bits { bits, defined } => {
                let pointer_size = layout.pointer_size.bits() as u8;
                if defined < pointer_size {
                    err!(ReadUndefBytes)
                } else {
                    Ok(Scalar::Bits {
                        bits: layout.wrapping_signed_offset(bits as u64, i) as u128,
                        defined: pointer_size,
                    })
            }
            }
            Scalar::Ptr(ptr) => Ok(Scalar::Ptr(ptr.wrapping_signed_offset(i, layout))),
        }
    }

    pub fn is_null_ptr<C: HasDataLayout>(self, cx: C) -> EvalResult<'tcx, bool> {
        match self {
            Scalar::Bits {
                bits, defined,
            } => if defined < cx.data_layout().pointer_size.bits() as u8 {
                err!(ReadUndefBytes)
            } else {
                Ok(bits == 0)
            },
            Scalar::Ptr(_) => Ok(false),
        }
    }

    pub fn to_value_with_len<C: HasDataLayout>(self, len: u64, cx: C) -> Value {
        Value::ScalarPair(self, Scalar::Bits {
            bits: len as u128,
            defined: cx.data_layout().pointer_size.bits() as u8,
        })
    }

    pub fn to_value_with_vtable(self, vtable: Pointer) -> Value {
        Value::ScalarPair(self, Scalar::Ptr(vtable))
    }

    pub fn to_value(self) -> Value {
        Value::Scalar(self)
    }
}

impl From<Pointer> for Scalar {
    fn from(ptr: Pointer) -> Self {
        Scalar::Ptr(ptr)
    }
}

/// A `Scalar` represents an immediate, primitive value existing outside of a
/// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 8 bytes in
/// size. Like a range of bytes in an `Allocation`, a `Scalar` can either represent the raw bytes
/// of a simple value or a pointer into another `Allocation`
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
pub enum Scalar {
    /// The raw bytes of a simple value.
    Bits {
        /// number of bits that are valid and may be read
        defined: u8,
        bits: u128,
    },

    /// A pointer into an `Allocation`. An `Allocation` in the `memory` module has a list of
    /// relocations, but a `Scalar` is only large enough to contain one, so we just represent the
    /// relocation and its associated offset together as a `Pointer` here.
    Ptr(Pointer),
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ScalarKind {
    I8, I16, I32, I64, I128,
    U8, U16, U32, U64, U128,
    F32, F64,
    Ptr, FnPtr,
    Bool,
    Char,
}

impl<'tcx> Scalar {
    pub fn undef() -> Self {
        Scalar::Bits { bits: 0, defined: 0 }
    }

    pub fn from_bool(b: bool) -> Self {
        // FIXME: can we make defined `1`?
        Scalar::Bits { bits: b as u128, defined: 8 }
    }

    pub fn from_char(c: char) -> Self {
        Scalar::Bits { bits: c as u128, defined: 32 }
    }

    pub fn to_bits(self, size: Size) -> EvalResult<'tcx, u128> {
        match self {
            Scalar::Bits { defined: 0, .. } => err!(ReadUndefBytes),
            Scalar::Bits { bits, defined } if size.bits() <= defined as u64 => Ok(bits),
            Scalar::Bits { .. } => err!(ReadUndefBytes),
            Scalar::Ptr(_) => err!(ReadPointerAsBytes),
        }
    }

    pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
        match self {
            Scalar::Bits {..} => err!(ReadBytesAsPointer),
            Scalar::Ptr(p) => Ok(p),
        }
    }

    pub fn is_bits(self) -> bool {
        match self {
            Scalar::Bits { .. } => true,
            _ => false,
        }
    }

    pub fn is_ptr(self) -> bool {
        match self {
            Scalar::Ptr(_) => true,
            _ => false,
        }
    }

    pub fn to_bool(self) -> EvalResult<'tcx, bool> {
        match self {
            Scalar::Bits { bits: 0, defined: 8 } => Ok(false),
            Scalar::Bits { bits: 1, defined: 8 } => Ok(true),
            _ => err!(InvalidBool),
        }
    }
}

impl ScalarKind {
    pub fn is_int(self) -> bool {
        use self::ScalarKind::*;
        match self {
            I8 | I16 | I32 | I64 | I128 | U8 | U16 | U32 | U64 | U128 => true,
            _ => false,
        }
    }

    pub fn is_signed_int(self) -> bool {
        use self::ScalarKind::*;
        match self {
            I8 | I16 | I32 | I64 | I128 => true,
            _ => false,
        }
    }

    pub fn is_float(self) -> bool {
        use self::ScalarKind::*;
        match self {
            F32 | F64 => true,
            _ => false,
        }
    }

    pub fn from_uint_size(size: Size) -> Self {
        match size.bytes() {
            1 => ScalarKind::U8,
            2 => ScalarKind::U16,
            4 => ScalarKind::U32,
            8 => ScalarKind::U64,
            16 => ScalarKind::U128,
            _ => bug!("can't make uint with size {}", size.bytes()),
        }
    }

    pub fn from_int_size(size: Size) -> Self {
        match size.bytes() {
            1 => ScalarKind::I8,
            2 => ScalarKind::I16,
            4 => ScalarKind::I32,
            8 => ScalarKind::I64,
            16 => ScalarKind::I128,
            _ => bug!("can't make int with size {}", size.bytes()),
        }
    }

    pub fn is_ptr(self) -> bool {
        use self::ScalarKind::*;
        match self {
            Ptr | FnPtr => true,
            _ => false,
        }
    }
}
<|endoftext|>