<commit_before>use Result;
use termdict::TermDictionaryBuilderImpl;
use super::TermInfo;
use schema::Field;
use schema::FieldEntry;
use schema::FieldType;
use schema::Schema;
use schema::TextIndexingOptions;
use directory::WritePtr;
use compression::{NUM_DOCS_PER_BLOCK, BlockEncoder, CompositeEncoder};
use DocId;
use core::Segment;
use std::io::{self, Write};
use compression::VIntEncoder;
use common::VInt;
use common::BinarySerializable;
use common::CountingWriter;
use termdict::TermDictionaryBuilder;

/// `PostingsSerializer` is in charge of serializing
/// postings on disk, in the
/// * `.idx` (inverted index)
/// * `.pos` (positions file)
/// * `.term` (term dictionary)
///
/// `PostingsWriter` are in charge of pushing the data to the
/// serializer.
///
/// The serializer expects to receive the following calls
/// in this order :
/// * `set_field(...)`
/// * `new_term(...)`
/// * `write_doc(...)`
/// * `write_doc(...)`
/// * `write_doc(...)`
/// * ...
/// * `close_term()`
/// * `new_term(...)`
/// * `write_doc(...)`
/// * ...
/// * `close_term()`
/// * `set_field(...)`
/// * ...
/// * `close()`
///
/// Terms have to be pushed in a lexicographically-sorted order.
/// Within a term, document have to be pushed in increasing order.
///
/// A description of the serialization format is
/// [available here](https://fulmicoton.gitbooks.io/tantivy-doc/content/inverted-index.html).
pub struct PostingsSerializer {
    terms_fst_builder: TermDictionaryBuilderImpl<WritePtr, TermInfo>,
    postings_write: CountingWriter<WritePtr>,
    positions_write: CountingWriter<WritePtr>,
    last_doc_id_encoded: u32,
    positions_encoder: CompositeEncoder,
    block_encoder: BlockEncoder,
    doc_ids: Vec<DocId>,
    term_freqs: Vec<u32>,
    position_deltas: Vec<u32>,
    schema: Schema,
    text_indexing_options: TextIndexingOptions,
    term_open: bool,
    current_term_info: TermInfo,
}

impl PostingsSerializer {
    /// Open a new `PostingsSerializer` for the given segment
    pub fn new(terms_write: WritePtr,
               postings_write: WritePtr,
               positions_write: WritePtr,
               schema: Schema)
               -> Result<PostingsSerializer> {
        let terms_fst_builder = try!(TermDictionaryBuilderImpl::new(terms_write));
        Ok(PostingsSerializer {
               terms_fst_builder: terms_fst_builder,
               postings_write: CountingWriter::wrap(postings_write),
               positions_write: CountingWriter::wrap(positions_write),
               last_doc_id_encoded: 0u32,
               positions_encoder: CompositeEncoder::new(),
               block_encoder: BlockEncoder::new(),
               doc_ids: Vec::new(),
               term_freqs: Vec::new(),
               position_deltas: Vec::new(),
               schema: schema,
               text_indexing_options: TextIndexingOptions::Unindexed,
               term_open: false,
               current_term_info: TermInfo::default(),
           })
    }

    /// Open a new `PostingsSerializer` for the given segment
    pub fn open(segment: &mut Segment) -> Result<PostingsSerializer> {
        use SegmentComponent::{TERMS, POSTINGS, POSITIONS};
        PostingsSerializer::new(segment.open_write(TERMS)?,
                                segment.open_write(POSTINGS)?,
                                segment.open_write(POSITIONS)?,
                                segment.schema())
    }

    /// Must be called before starting pushing terms of
    /// a given field.
    ///
    /// Loads the indexing options for the given field.
    pub fn new_field(&mut self, field: Field) {
        let field_entry: &FieldEntry = self.schema.get_field_entry(field);
        self.text_indexing_options = match *field_entry.field_type() {
            FieldType::Str(ref text_options) => text_options.get_indexing_options(),
            FieldType::U64(ref int_options) |
            FieldType::I64(ref int_options) => {
                if int_options.is_indexed() {
                    TextIndexingOptions::Unindexed
                } else {
                    TextIndexingOptions::Untokenized
                }
            }
        };
    }

    /// Starts the postings for a new term.
    /// * term - the term. It needs to come after the previous term according
    ///   to the lexicographical order.
    /// * doc_freq - return the number of document containing the term.
    pub fn new_term(&mut self, term: &[u8]) -> io::Result<()> {
        if self.term_open {
            panic!("Called new_term, while the previous term was not closed.");
        }
        self.term_open = true;
        self.doc_ids.clear();
        self.last_doc_id_encoded = 0;
        self.term_freqs.clear();
        self.position_deltas.clear();
        self.current_term_info = TermInfo {
            doc_freq: 0,
            postings_offset: self.postings_write.written_bytes() as u32,
            positions_offset: self.positions_write.written_bytes() as u32,
        };
        self.terms_fst_builder.insert_key(term)
    }

    /// Finish the serialization for this term postings.
    ///
    /// If the current block is incomplete, it need to be encoded
    /// using `VInt` encoding.
    pub fn close_term(&mut self) -> io::Result<()> {
        if self.term_open {

            self.terms_fst_builder
                .insert_value(&self.current_term_info)?;

            if !self.doc_ids.is_empty() {
                // we have doc ids waiting to be written
                // this happens when the number of doc ids is
                // not a perfect multiple of our block size.
                //
                // In that case, the remaining part is encoded
                // using variable int encoding.
                {
                    let block_encoded =
                        self.block_encoder
                            .compress_vint_sorted(&self.doc_ids, self.last_doc_id_encoded);
                    self.postings_write.write_all(block_encoded)?;
                    self.doc_ids.clear();
                }
                // ... Idem for term frequencies
                if self.text_indexing_options.is_termfreq_enabled() {
                    let block_encoded = self.block_encoder
                        .compress_vint_unsorted(&self.term_freqs[..]);
                    for num in block_encoded {
                        num.serialize(&mut self.postings_write)?;
                    }
                    self.term_freqs.clear();
                }
            }
            // On the other hand, positions are entirely buffered until the
            // end of the term, at which point they are compressed and written.
            if self.text_indexing_options.is_position_enabled() {
                let posdelta_len = VInt(self.position_deltas.len() as u64);
                posdelta_len.serialize(&mut self.positions_write)?;
                let positions_encoded: &[u8] = self.positions_encoder
                    .compress_unsorted(&self.position_deltas[..]);
                self.positions_write.write_all(positions_encoded)?;
                self.position_deltas.clear();
            }
            self.term_open = false;
        }
        Ok(())
    }

    /// Serialize the information that a document contains the current term,
    /// its term frequency, and the position deltas.
    ///
    /// At this point, the positions are already `delta-encoded`.
    /// For instance, if the positions are `2, 3, 17`,
    /// `position_deltas` is `2, 1, 14`
    ///
    /// Term frequencies and positions may be ignored by the serializer depending
    /// on the configuration of the field in the `Schema`.
    pub fn write_doc(&mut self,
                     doc_id: DocId,
                     term_freq: u32,
                     position_deltas: &[u32])
                     -> io::Result<()> {
        self.current_term_info.doc_freq += 1;
        self.doc_ids.push(doc_id);
        if self.text_indexing_options.is_termfreq_enabled() {
            self.term_freqs.push(term_freq as u32);
        }
        if self.text_indexing_options.is_position_enabled() {
            self.position_deltas.extend_from_slice(position_deltas);
        }
        if self.doc_ids.len() == NUM_DOCS_PER_BLOCK {
            {
                // encode the doc ids
                let block_encoded: &[u8] =
                    self.block_encoder
                        .compress_block_sorted(&self.doc_ids, self.last_doc_id_encoded);
                self.last_doc_id_encoded = self.doc_ids[self.doc_ids.len() - 1];
                self.postings_write.write_all(block_encoded)?;
            }
            if self.text_indexing_options.is_termfreq_enabled() {
                // encode the term_freqs
                let block_encoded: &[u8] = self.block_encoder
                    .compress_block_unsorted(&self.term_freqs);
                self.postings_write.write_all(block_encoded)?;
                self.term_freqs.clear();
            }
            self.doc_ids.clear();
        }
        Ok(())
    }

    /// Closes the serializer.
    pub fn close(mut self) -> io::Result<()> {
        try!(self.close_term());
        try!(self.terms_fst_builder.finish());
        try!(self.postings_write.flush());
        try!(self.positions_write.flush());
        Ok(())
    }
}
<commit_msg>NOBUG simplified code.<commit_after>use Result;
use termdict::TermDictionaryBuilderImpl;
use super::TermInfo;
use schema::Field;
use schema::FieldEntry;
use schema::FieldType;
use schema::Schema;
use schema::TextIndexingOptions;
use directory::WritePtr;
use compression::{NUM_DOCS_PER_BLOCK, BlockEncoder, CompositeEncoder};
use DocId;
use core::Segment;
use std::io::{self, Write};
use compression::VIntEncoder;
use common::VInt;
use common::BinarySerializable;
use common::CountingWriter;
use termdict::TermDictionaryBuilder;

/// `PostingsSerializer` is in charge of serializing
/// postings on disk, in the
/// * `.idx` (inverted index)
/// * `.pos` (positions file)
/// * `.term` (term dictionary)
///
/// `PostingsWriter` are in charge of pushing the data to the
/// serializer.
///
/// The serializer expects to receive the following calls
/// in this order :
/// * `set_field(...)`
/// * `new_term(...)`
/// * `write_doc(...)`
/// * `write_doc(...)`
/// * `write_doc(...)`
/// * ...
/// * `close_term()`
/// * `new_term(...)`
/// * `write_doc(...)`
/// * ...
/// * `close_term()`
/// * `set_field(...)`
/// * ...
/// * `close()`
///
/// Terms have to be pushed in a lexicographically-sorted order.
/// Within a term, document have to be pushed in increasing order.
///
/// A description of the serialization format is
/// [available here](https://fulmicoton.gitbooks.io/tantivy-doc/content/inverted-index.html).
pub struct PostingsSerializer {
    terms_fst_builder: TermDictionaryBuilderImpl<WritePtr, TermInfo>,
    postings_write: CountingWriter<WritePtr>,
    positions_write: CountingWriter<WritePtr>,
    last_doc_id_encoded: u32,
    positions_encoder: CompositeEncoder,
    block_encoder: BlockEncoder,
    doc_ids: Vec<DocId>,
    term_freqs: Vec<u32>,
    position_deltas: Vec<u32>,
    schema: Schema,
    text_indexing_options: TextIndexingOptions,
    term_open: bool,
    current_term_info: TermInfo,
}

impl PostingsSerializer {
    /// Open a new `PostingsSerializer` for the given segment
    pub fn new(terms_write: WritePtr,
               postings_write: WritePtr,
               positions_write: WritePtr,
               schema: Schema)
               -> Result<PostingsSerializer> {
        let terms_fst_builder = try!(TermDictionaryBuilderImpl::new(terms_write));
        Ok(PostingsSerializer {
               terms_fst_builder: terms_fst_builder,
               postings_write: CountingWriter::wrap(postings_write),
               positions_write: CountingWriter::wrap(positions_write),
               last_doc_id_encoded: 0u32,
               positions_encoder: CompositeEncoder::new(),
               block_encoder: BlockEncoder::new(),
               doc_ids: Vec::new(),
               term_freqs: Vec::new(),
               position_deltas: Vec::new(),
               schema: schema,
               text_indexing_options: TextIndexingOptions::Unindexed,
               term_open: false,
               current_term_info: TermInfo::default(),
           })
    }

    /// Open a new `PostingsSerializer` for the given segment
    pub fn open(segment: &mut Segment) -> Result<PostingsSerializer> {
        use SegmentComponent::{TERMS, POSTINGS, POSITIONS};
        PostingsSerializer::new(segment.open_write(TERMS)?,
                                segment.open_write(POSTINGS)?,
                                segment.open_write(POSITIONS)?,
                                segment.schema())
    }

    /// Must be called before starting pushing terms of
    /// a given field.
    ///
    /// Loads the indexing options for the given field.
    pub fn new_field(&mut self, field: Field) {
        let field_entry: &FieldEntry = self.schema.get_field_entry(field);
        self.text_indexing_options = match *field_entry.field_type() {
            FieldType::Str(ref text_options) => text_options.get_indexing_options(),
            FieldType::U64(ref int_options) |
            FieldType::I64(ref int_options) => {
                if int_options.is_indexed() {
                    TextIndexingOptions::Unindexed
                } else {
                    TextIndexingOptions::Untokenized
                }
            }
        };
    }

    /// Starts the postings for a new term.
    /// * term - the term. It needs to come after the previous term according
    ///   to the lexicographical order.
    /// * doc_freq - return the number of document containing the term.
    pub fn new_term(&mut self, term: &[u8]) -> io::Result<()> {
        if self.term_open {
            panic!("Called new_term, while the previous term was not closed.");
        }
        self.term_open = true;
        self.doc_ids.clear();
        self.last_doc_id_encoded = 0;
        self.term_freqs.clear();
        self.position_deltas.clear();
        self.current_term_info = TermInfo {
            doc_freq: 0,
            postings_offset: self.postings_write.written_bytes() as u32,
            positions_offset: self.positions_write.written_bytes() as u32,
        };
        self.terms_fst_builder.insert_key(term)
    }

    /// Finish the serialization for this term postings.
    ///
    /// If the current block is incomplete, it need to be encoded
    /// using `VInt` encoding.
    pub fn close_term(&mut self) -> io::Result<()> {
        if self.term_open {

            self.terms_fst_builder
                .insert_value(&self.current_term_info)?;

            if !self.doc_ids.is_empty() {
                // we have doc ids waiting to be written
                // this happens when the number of doc ids is
                // not a perfect multiple of our block size.
                //
                // In that case, the remaining part is encoded
                // using variable int encoding.
                {
                    let block_encoded =
                        self.block_encoder
                            .compress_vint_sorted(&self.doc_ids, self.last_doc_id_encoded);
                    self.postings_write.write_all(block_encoded)?;
                    self.doc_ids.clear();
                }
                // ... Idem for term frequencies
                if self.text_indexing_options.is_termfreq_enabled() {
                    let block_encoded = self.block_encoder
                        .compress_vint_unsorted(&self.term_freqs[..]);
                    self.postings_write.write_all(block_encoded)?;
                    self.term_freqs.clear();
                }
            }
            // On the other hand, positions are entirely buffered until the
            // end of the term, at which point they are compressed and written.
            if self.text_indexing_options.is_position_enabled() {
                let posdelta_len = VInt(self.position_deltas.len() as u64);
                posdelta_len.serialize(&mut self.positions_write)?;
                let positions_encoded: &[u8] = self.positions_encoder
                    .compress_unsorted(&self.position_deltas[..]);
                self.positions_write.write_all(positions_encoded)?;
                self.position_deltas.clear();
            }
            self.term_open = false;
        }
        Ok(())
    }

    /// Serialize the information that a document contains the current term,
    /// its term frequency, and the position deltas.
    ///
    /// At this point, the positions are already `delta-encoded`.
    /// For instance, if the positions are `2, 3, 17`,
    /// `position_deltas` is `2, 1, 14`
    ///
    /// Term frequencies and positions may be ignored by the serializer depending
    /// on the configuration of the field in the `Schema`.
    pub fn write_doc(&mut self,
                     doc_id: DocId,
                     term_freq: u32,
                     position_deltas: &[u32])
                     -> io::Result<()> {
        self.current_term_info.doc_freq += 1;
        self.doc_ids.push(doc_id);
        if self.text_indexing_options.is_termfreq_enabled() {
            self.term_freqs.push(term_freq as u32);
        }
        if self.text_indexing_options.is_position_enabled() {
            self.position_deltas.extend_from_slice(position_deltas);
        }
        if self.doc_ids.len() == NUM_DOCS_PER_BLOCK {
            {
                // encode the doc ids
                let block_encoded: &[u8] =
                    self.block_encoder
                        .compress_block_sorted(&self.doc_ids, self.last_doc_id_encoded);
                self.last_doc_id_encoded = self.doc_ids[self.doc_ids.len() - 1];
                self.postings_write.write_all(block_encoded)?;
            }
            if self.text_indexing_options.is_termfreq_enabled() {
                // encode the term_freqs
                let block_encoded: &[u8] = self.block_encoder
                    .compress_block_unsorted(&self.term_freqs);
                self.postings_write.write_all(block_encoded)?;
                self.term_freqs.clear();
            }
            self.doc_ids.clear();
        }
        Ok(())
    }

    /// Closes the serializer.
    pub fn close(mut self) -> io::Result<()> {
        try!(self.close_term());
        try!(self.terms_fst_builder.finish());
        try!(self.postings_write.flush());
        try!(self.positions_write.flush());
        Ok(())
    }
}
<|endoftext|>


<commit_before>fn replicate<A:Clone>(x:A, l:uint) -> Vec<A> {
    let i = 0u;
    let mut res = Vec::new();
    for _ in range(i,l) {
        res.push(x.clone());
    }
    res
}

fn pad_right(c:char, l:uint, str:String) -> String {
    let str_len = str.len();
    if l > str_len {
        let padding = replicate(String::from_chars([c]), l - str_len).concat();
        let mut res = str.clone();
        res.push_str(padding.as_slice());
        res
    } else {
        str
    }
}

fn pad_left(c:char, l:uint, str:String) -> String {
    let str_len = str.len();
    if l > str_len {
      let mut res = replicate(String::from_chars([c]), l - str_len).concat();
      res.push_str(str.as_slice());
      res
    } else {
        str
    }
}

pub fn nl_space(i:uint) -> String {
    pad_right(' ', i + String::from_str("\n").len(), String::from_str("\n"))
}

pub fn spaces(i:uint) -> String {
    pad_left(' ', i, String::from_str(""))
}

<commit_msg>Use iterator to repeat elem<commit_after>use std::iter::Repeat;

fn replicate<A:Clone>(x:A, l:uint) -> Vec<A> {
    FromIterator::from_iter(Repeat::new(x).take(l))
}

fn pad_right(c:char, l:uint, str:String) -> String {
    let str_len = str.len();
    if l > str_len {
        let padding = replicate(String::from_chars([c]), l - str_len).concat();
        let mut res = str.clone();
        res.push_str(padding.as_slice());
        res
    } else {
        str
    }
}

fn pad_left(c:char, l:uint, str:String) -> String {
    let str_len = str.len();
    if l > str_len {
      let mut res = replicate(String::from_chars([c]), l - str_len).concat();
      res.push_str(str.as_slice());
      res
    } else {
        str
    }
}

pub fn nl_space(i:uint) -> String {
    pad_right(' ', i + String::from_str("\n").len(), String::from_str("\n"))
}

pub fn spaces(i:uint) -> String {
    pad_left(' ', i, String::from_str(""))
}
<|endoftext|>


<commit_before>use rand;
use std::cmp::min;
#[allow(deprecated)]
use std::mem::uninitialized;
use std::ptr::{copy_nonoverlapping, read_unaligned};

/// Generate a random frame mask.
#[inline]
pub fn generate_mask() -> [u8; 4] {
    rand::random()
}

/// Mask/unmask a frame.
#[inline]
pub fn apply_mask(buf: &mut [u8], mask: [u8; 4]) {
    apply_mask_fast32(buf, mask)
}

/// A safe unoptimized mask application.
#[inline]
#[allow(dead_code)]
fn apply_mask_fallback(buf: &mut [u8], mask: [u8; 4]) {
    for (i, byte) in buf.iter_mut().enumerate() {
        *byte ^= mask[i & 3];
    }
}

/// Faster version of `apply_mask()` which operates on 4-byte blocks.
#[inline]
#[allow(dead_code, clippy::cast_ptr_alignment)]
fn apply_mask_fast32(buf: &mut [u8], mask: [u8; 4]) {
    let mask_u32: u32 = unsafe { read_unaligned(mask.as_ptr() as *const u32) };

    let mut ptr = buf.as_mut_ptr();
    let mut len = buf.len();

    // Possible first unaligned block.
    let head = min(len, (4 - (ptr as usize & 3)) & 3);
    let mask_u32 = if head > 0 {
        unsafe {
            xor_mem(ptr, mask_u32, head);
            ptr = ptr.add(head);
        }
        len -= head;
        if cfg!(target_endian = "big") {
            mask_u32.rotate_left(8 * head as u32)
        } else {
            mask_u32.rotate_right(8 * head as u32)
        }
    } else {
        mask_u32
    };

    if len > 0 {
        debug_assert_eq!(ptr as usize % 4, 0);
    }

    // Properly aligned middle of the data.
    while len > 4 {
        unsafe {
            *(ptr as *mut u32) ^= mask_u32;
            ptr = ptr.offset(4);
            len -= 4;
        }
    }

    // Possible last block.
    if len > 0 {
        unsafe {
            xor_mem(ptr, mask_u32, len);
        }
    }
}

#[inline]
// TODO: copy_nonoverlapping here compiles to call memcpy. While it is not so inefficient,
// it could be done better. The compiler does not see that len is limited to 3.
unsafe fn xor_mem(ptr: *mut u8, mask: u32, len: usize) {
    #[allow(deprecated)]
    let mut b: u32 = uninitialized();
    #[allow(trivial_casts)]
    copy_nonoverlapping(ptr, &mut b as *mut _ as *mut u8, len);
    b ^= mask;
    #[allow(trivial_casts)]
    copy_nonoverlapping(&b as *const _ as *const u8, ptr, len);
}

#[cfg(test)]
mod tests {

    use super::{apply_mask_fallback, apply_mask_fast32};

    #[test]
    fn test_apply_mask() {
        let mask = [0x6d, 0xb6, 0xb2, 0x80];
        let unmasked = vec![
            0xf3, 0x00, 0x01, 0x02, 0x03, 0x80, 0x81, 0x82, 0xff, 0xfe, 0x00, 0x17, 0x74, 0xf9,
            0x12, 0x03,
        ];

        // Check masking with proper alignment.
        {
            let mut masked = unmasked.clone();
            apply_mask_fallback(&mut masked, mask);

            let mut masked_fast = unmasked.clone();
            apply_mask_fast32(&mut masked_fast, mask);

            assert_eq!(masked, masked_fast);
        }

        // Check masking without alignment.
        {
            let mut masked = unmasked.clone();
            apply_mask_fallback(&mut masked[1..], mask);

            let mut masked_fast = unmasked.clone();
            apply_mask_fast32(&mut masked_fast[1..], mask);

            assert_eq!(masked, masked_fast);
        }
    }
}
<commit_msg>infra/apply_mask: test more case for apply_mask<commit_after>use std::cmp::min;
#[allow(deprecated)]
use std::mem::uninitialized;
use std::ptr::{copy_nonoverlapping, read_unaligned};

/// Generate a random frame mask.
#[inline]
pub fn generate_mask() -> [u8; 4] {
    rand::random()
}

/// Mask/unmask a frame.
#[inline]
pub fn apply_mask(buf: &mut [u8], mask: [u8; 4]) {
    apply_mask_fast32(buf, mask)
}

/// A safe unoptimized mask application.
#[inline]
#[allow(dead_code)]
fn apply_mask_fallback(buf: &mut [u8], mask: [u8; 4]) {
    for (i, byte) in buf.iter_mut().enumerate() {
        *byte ^= mask[i & 3];
    }
}

/// Faster version of `apply_mask()` which operates on 4-byte blocks.
#[inline]
#[allow(dead_code, clippy::cast_ptr_alignment)]
fn apply_mask_fast32(buf: &mut [u8], mask: [u8; 4]) {
    let mask_u32: u32 = unsafe { read_unaligned(mask.as_ptr() as *const u32) };

    let mut ptr = buf.as_mut_ptr();
    let mut len = buf.len();

    // Possible first unaligned block.
    let head = min(len, (4 - (ptr as usize & 3)) & 3);
    let mask_u32 = if head > 0 {
        unsafe {
            xor_mem(ptr, mask_u32, head);
            ptr = ptr.add(head);
        }
        len -= head;
        if cfg!(target_endian = "big") {
            mask_u32.rotate_left(8 * head as u32)
        } else {
            mask_u32.rotate_right(8 * head as u32)
        }
    } else {
        mask_u32
    };

    if len > 0 {
        debug_assert_eq!(ptr as usize % 4, 0);
    }

    // Properly aligned middle of the data.
    while len > 4 {
        unsafe {
            *(ptr as *mut u32) ^= mask_u32;
            ptr = ptr.offset(4);
            len -= 4;
        }
    }

    // Possible last block.
    if len > 0 {
        unsafe {
            xor_mem(ptr, mask_u32, len);
        }
    }
}

#[inline]
// TODO: copy_nonoverlapping here compiles to call memcpy. While it is not so inefficient,
// it could be done better. The compiler does not see that len is limited to 3.
unsafe fn xor_mem(ptr: *mut u8, mask: u32, len: usize) {
    #[allow(deprecated)]
    let mut b: u32 = uninitialized();
    #[allow(trivial_casts)]
    copy_nonoverlapping(ptr, &mut b as *mut _ as *mut u8, len);
    b ^= mask;
    #[allow(trivial_casts)]
    copy_nonoverlapping(&b as *const _ as *const u8, ptr, len);
}

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

    #[test]
    fn test_apply_mask() {
        let mask = [0x6d, 0xb6, 0xb2, 0x80];
        let unmasked = vec![
            0xf3, 0x00, 0x01, 0x02, 0x03, 0x80, 0x81, 0x82, 0xff, 0xfe, 0x00, 0x17, 0x74, 0xf9,
            0x12, 0x03,
        ];

        for data_len in 0..=unmasked.len() {
            let unmasked = &unmasked[0..data_len];
            // Check masking with different alignment.
            for off in 0..=3 {
                if unmasked.len() < off {
                    continue;
                }
                let mut masked = unmasked.to_vec();
                apply_mask_fallback(&mut masked[off..], mask);

                let mut masked_fast = unmasked.to_vec();
                apply_mask_fast32(&mut masked_fast[off..], mask);

                assert_eq!(masked, masked_fast);
            }
        }
    }
}
<|endoftext|>


<commit_before>#[link(name = "rusp",
       vers = "0.1",
       author = "Brendan Zabarauskas",
       url = "https://github.com/bjz/rusp")];

#[comment = "A minimal Lisp dialect for Rust."];
#[crate_type = "lib"];

// Inspired by Peter Norvig's [Lis.py](http://norvig.com/lispy.html)

use std::hashmap::*;

pub mod parse;
pub mod pprint;

///
/// Symbol identifier
///
#[deriving(Eq, Clone, IterBytes)]
pub struct Ident(~str);

///
/// Holds a typed value from the environment
///
#[deriving(Eq, Clone)]
pub enum Value {
    Empty,
    Boolean(bool),
    Integer(int),
    Float(float),
    String(~str),
    ///
    /// Quoted expression
    ///
    /// ~~~
    /// (quote <expr>)
    /// ~~~
    ///
    Quote(@Expr),
    ///
    /// Anonymous function
    ///
    /// ~~~
    /// (fn (<ident>*) <expr>)
    /// ~~~
    ///
    Lambda(~[Ident], @Expr, @mut Env),
}

///
/// Primitive language expressions
///
#[deriving(Eq, Clone)]
pub enum Expr {
    ///
    /// Symbol reference
    ///
    /// ~~~
    /// <ident>
    /// ~~~
    ///
    Symbol(Ident),
    ///
    /// Constant literal
    ///
    /// ~~~
    /// <val>
    /// ~~~
    ///
    Literal(Value),
    ///
    /// Conditional expression
    ///
    /// ~~~
    /// (if <test> <conseq> <alt>)
    /// ~~~
    ///
    If(@Expr, @Expr, @Expr),
    ///
    /// Symbol definition
    ///
    /// ~~~
    /// (let <ident> <expr>)
    /// ~~~
    ///
    Let(Ident, @Expr),
    ///
    /// Procedure call
    ///
    /// ~~~
    /// (<expr> <expr>+)
    /// ~~~
    ///
    Call(@Expr, ~[@Expr]),
}

#[deriving(Eq)]
pub struct Env {
    values: HashMap<Ident, Value>,
    outer: Option<@mut Env>,
}

impl Env {
    /// Initializes an empty environment
    pub fn empty() -> @mut Env {
        @mut Env { values: HashMap::new(), outer: None }
    }

    /// Initializes a new environment with the specified values
    pub fn new(values: &[(Ident, Value)], outer: Option<@mut Env>) -> @mut Env {
        let env = @mut Env {
            values: HashMap::new(),
            outer: outer,
        };
        for values.each |&(id, val)| {
            env.define(id, val);
        }
        env
    }

    /// Defines a new identifier/value pair
    pub fn define(&mut self, ident: Ident, val: Value) -> bool {
        self.values.insert(ident, val)
    }

    /// Attempts to find a value corresponding to the supplied identifier
    pub fn find(&self, ident: &Ident) -> Option<Value> {
        match self.values.find(ident) {
            Some(val) => Some(val.clone()),
            None => self.outer.chain(|env| env.find(ident)),
        }
    }
}

pub type EvalResult = Result<Value, ~str>;

impl Expr {
    ///
    /// Evaluates an expression tree in the supplied environment
    ///
    pub fn eval(&self, env: @mut Env) -> EvalResult {
        match *self {
            Symbol(ref id) =>{
                match env.find(id) {
                    Some(val) => Ok(val),
                    None => Err(fmt!("The value of `%s` was not defined in this environment", id.to_str())),
                }
            }
            Literal(ref val) => {
                Ok(val.clone())
            }
            If(test, conseq, alt) => {
                do test.eval(env).chain |val| {
                    match val {
                        Boolean(true) => conseq.eval(env),
                        Boolean(false) => alt.eval(env),
                        _ => Err(fmt!("expected Boolean value, found: %?", val)),
                    }
                }
            }
            Let(ref id, expr) => {
                do expr.eval(env).chain |val| {
                    if env.define(id.clone(), val) {
                        Ok(Empty)
                    } else {
                        Err(fmt!("`%s` was already defined in this environment.", id.to_str()))
                    }
                }
            }
            Call(_,_) => fail!(),
        }
    }
}

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

    #[test]
    fn test_env() {
        let outer = Env::new([
            (Ident(~"a"), Integer(0)),
            (Ident(~"b"), Float(1.0)),
            (Ident(~"c"), String(~"hi")),
        ], None);

        let inner = Env::new([
            (Ident(~"a"), Integer(3)),
            (Ident(~"b"), Integer(4)),
        ], Some(outer));

        assert_eq!(outer.find(&Ident(~"a")), Some(Integer(0)));
        assert_eq!(outer.find(&Ident(~"b")), Some(Float(1.0)));
        assert_eq!(outer.find(&Ident(~"c")), Some(String(~"hi")));
        assert_eq!(inner.find(&Ident(~"a")), Some(Integer(3)));
        assert_eq!(inner.find(&Ident(~"b")), Some(Integer(4)));
        assert_eq!(inner.find(&Ident(~"c")), Some(String(~"hi")));
    }

    #[test]
    fn test_eval_symbol() {
        let env = Env::new([
            (Ident(~"a"), Integer(0)),
            (Ident(~"b"), Float(1.0)),
            (Ident(~"c"), String(~"hi")),
        ], None);

        assert_eq!(Symbol(Ident(~"a")).eval(env).get(), Integer(0));
        assert_eq!(Symbol(Ident(~"b")).eval(env).get(), Float(1.0));
        assert_eq!(Symbol(Ident(~"c")).eval(env).get(), String(~"hi"));
        assert!(Symbol(Ident(~"d")).eval(env).is_err());
    }

    #[test]
    fn test_eval_literal() {
        assert_eq!(Literal(Empty).eval(Env::empty()).get(), Empty);
        assert_eq!(Literal(Integer(1)).eval(Env::empty()).get(), Integer(1));
        assert_eq!(Literal(Float(1.0)).eval(Env::empty()).get(), Float(1.0));
        assert_eq!(Literal(String(~"hi")).eval(Env::empty()).get(), String(~"hi"));
        assert_eq!(Literal(Quote(@Literal(Empty))).eval(Env::empty()).get(),
                   Quote(@Literal(Empty)));
    }

    #[test]
    fn test_eval_if() {
        fn not(test: Value) -> EvalResult {
            If(
                @Literal(test),
                @Literal(Boolean(false)),
                @Literal(Boolean(true))
            ).eval(Env::empty())
        }

        assert_eq!(not(Boolean(true)).get(), Boolean(false));
        assert_eq!(not(Boolean(false)).get(), Boolean(true));
        assert!(not(String(~"hi")).is_err());
    }

    #[test]
    fn test_eval_lambda() {

    }

    #[test]
    fn test_eval_let() {
        let env = Env::empty();
        assert!(Let(Ident(~"a"), @Literal(Integer(0))).eval(env).is_ok());
        assert!(Let(Ident(~"b"), @Literal(Float(1.0))).eval(env).is_ok());
        assert!(Let(Ident(~"c"), @Literal(String(~"hi"))).eval(env).is_ok());

        assert_eq!(env.find(&Ident(~"a")), Some(Integer(0)));
        assert_eq!(env.find(&Ident(~"b")), Some(Float(1.0)));
        assert_eq!(env.find(&Ident(~"c")), Some(String(~"hi")));

        assert!(Let(Ident(~"c"), @Literal(Empty)).eval(env).is_err());
    }

    #[test]
    fn test_eval_call() {

    }
}<commit_msg>Use refs in match patterns<commit_after>#[link(name = "rusp",
       vers = "0.1",
       author = "Brendan Zabarauskas",
       url = "https://github.com/bjz/rusp")];

#[comment = "A minimal Lisp dialect for Rust."];
#[crate_type = "lib"];

// Inspired by Peter Norvig's [Lis.py](http://norvig.com/lispy.html)

use std::hashmap::*;

pub mod parse;
pub mod pprint;

///
/// Symbol identifier
///
#[deriving(Eq, Clone, IterBytes)]
pub struct Ident(~str);

///
/// Holds a typed value from the environment
///
#[deriving(Eq, Clone)]
pub enum Value {
    Empty,
    Boolean(bool),
    Integer(int),
    Float(float),
    String(~str),
    ///
    /// Quoted expression
    ///
    /// ~~~
    /// (quote <expr>)
    /// ~~~
    ///
    Quote(@Expr),
    ///
    /// Anonymous function
    ///
    /// ~~~
    /// (fn (<ident>*) <expr>)
    /// ~~~
    ///
    Lambda(~[Ident], @Expr, @mut Env),
}

///
/// Primitive language expressions
///
#[deriving(Eq, Clone)]
pub enum Expr {
    ///
    /// Symbol reference
    ///
    /// ~~~
    /// <ident>
    /// ~~~
    ///
    Symbol(Ident),
    ///
    /// Constant literal
    ///
    /// ~~~
    /// <val>
    /// ~~~
    ///
    Literal(Value),
    ///
    /// Conditional expression
    ///
    /// ~~~
    /// (if <test> <conseq> <alt>)
    /// ~~~
    ///
    If(@Expr, @Expr, @Expr),
    ///
    /// Symbol definition
    ///
    /// ~~~
    /// (let <ident> <expr>)
    /// ~~~
    ///
    Let(Ident, @Expr),
    ///
    /// Procedure call
    ///
    /// ~~~
    /// (<expr> <expr>+)
    /// ~~~
    ///
    Call(@Expr, ~[@Expr]),
}

#[deriving(Eq)]
pub struct Env {
    values: HashMap<Ident, Value>,
    outer: Option<@mut Env>,
}

impl Env {
    /// Initializes an empty environment
    pub fn empty() -> @mut Env {
        @mut Env { values: HashMap::new(), outer: None }
    }

    /// Initializes a new environment with the specified values
    pub fn new(values: &[(Ident, Value)], outer: Option<@mut Env>) -> @mut Env {
        let env = @mut Env {
            values: HashMap::new(),
            outer: outer,
        };
        for values.each |&(id, val)| {
            env.define(id, val);
        }
        env
    }

    /// Defines a new identifier/value pair
    pub fn define(&mut self, ident: Ident, val: Value) -> bool {
        self.values.insert(ident, val)
    }

    /// Attempts to find a value corresponding to the supplied identifier
    pub fn find(&self, ident: &Ident) -> Option<Value> {
        match self.values.find(ident) {
            Some(val) => Some(val.clone()),
            None => self.outer.chain(|env| env.find(ident)),
        }
    }
}

pub type EvalResult = Result<Value, ~str>;

impl Expr {
    ///
    /// Evaluates an expression tree in the supplied environment
    ///
    pub fn eval(&self, env: @mut Env) -> EvalResult {
        match *self {
            Symbol(ref id) =>{
                match env.find(id) {
                    Some(val) => Ok(val),
                    None => Err(fmt!("The value of `%s` was not defined in this environment", id.to_str())),
                }
            }
            Literal(ref val) => {
                Ok(val.clone())
            }
            If(ref test, ref conseq, ref alt) => {
                do test.eval(env).chain |val| {
                    match val {
                        Boolean(true) => conseq.eval(env),
                        Boolean(false) => alt.eval(env),
                        _ => Err(fmt!("expected Boolean value, found: %?", val)),
                    }
                }
            }
            Let(ref id, ref expr) => {
                do expr.eval(env).chain |val| {
                    if env.define(id.clone(), val) {
                        Ok(Empty)
                    } else {
                        Err(fmt!("`%s` was already defined in this environment.", id.to_str()))
                    }
                }
            }
            Call(_,_) => fail!(),
        }
    }
}

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

    #[test]
    fn test_env() {
        let outer = Env::new([
            (Ident(~"a"), Integer(0)),
            (Ident(~"b"), Float(1.0)),
            (Ident(~"c"), String(~"hi")),
        ], None);

        let inner = Env::new([
            (Ident(~"a"), Integer(3)),
            (Ident(~"b"), Integer(4)),
        ], Some(outer));

        assert_eq!(outer.find(&Ident(~"a")), Some(Integer(0)));
        assert_eq!(outer.find(&Ident(~"b")), Some(Float(1.0)));
        assert_eq!(outer.find(&Ident(~"c")), Some(String(~"hi")));
        assert_eq!(inner.find(&Ident(~"a")), Some(Integer(3)));
        assert_eq!(inner.find(&Ident(~"b")), Some(Integer(4)));
        assert_eq!(inner.find(&Ident(~"c")), Some(String(~"hi")));
    }

    #[test]
    fn test_eval_symbol() {
        let env = Env::new([
            (Ident(~"a"), Integer(0)),
            (Ident(~"b"), Float(1.0)),
            (Ident(~"c"), String(~"hi")),
        ], None);

        assert_eq!(Symbol(Ident(~"a")).eval(env).get(), Integer(0));
        assert_eq!(Symbol(Ident(~"b")).eval(env).get(), Float(1.0));
        assert_eq!(Symbol(Ident(~"c")).eval(env).get(), String(~"hi"));
        assert!(Symbol(Ident(~"d")).eval(env).is_err());
    }

    #[test]
    fn test_eval_literal() {
        assert_eq!(Literal(Empty).eval(Env::empty()).get(), Empty);
        assert_eq!(Literal(Integer(1)).eval(Env::empty()).get(), Integer(1));
        assert_eq!(Literal(Float(1.0)).eval(Env::empty()).get(), Float(1.0));
        assert_eq!(Literal(String(~"hi")).eval(Env::empty()).get(), String(~"hi"));
        assert_eq!(Literal(Quote(@Literal(Empty))).eval(Env::empty()).get(),
                   Quote(@Literal(Empty)));
    }

    #[test]
    fn test_eval_if() {
        fn not(test: Value) -> EvalResult {
            If(
                @Literal(test),
                @Literal(Boolean(false)),
                @Literal(Boolean(true))
            ).eval(Env::empty())
        }

        assert_eq!(not(Boolean(true)).get(), Boolean(false));
        assert_eq!(not(Boolean(false)).get(), Boolean(true));
        assert!(not(String(~"hi")).is_err());
    }

    #[test]
    fn test_eval_lambda() {

    }

    #[test]
    fn test_eval_let() {
        let env = Env::empty();
        assert!(Let(Ident(~"a"), @Literal(Integer(0))).eval(env).is_ok());
        assert!(Let(Ident(~"b"), @Literal(Float(1.0))).eval(env).is_ok());
        assert!(Let(Ident(~"c"), @Literal(String(~"hi"))).eval(env).is_ok());

        assert_eq!(env.find(&Ident(~"a")), Some(Integer(0)));
        assert_eq!(env.find(&Ident(~"b")), Some(Float(1.0)));
        assert_eq!(env.find(&Ident(~"c")), Some(String(~"hi")));

        assert!(Let(Ident(~"c"), @Literal(Empty)).eval(env).is_err());
    }

    #[test]
    fn test_eval_call() {

    }
}<|endoftext|>


<commit_before>use alloc::sync::Arc;
use alloc::vec::Vec;
use spin::{Mutex, RwLock};

use crate::context::{self, Context};

#[derive(Debug)]
pub struct WaitCondition {
    contexts: Mutex<Vec<Arc<RwLock<Context>>>>
}

impl WaitCondition {
    pub fn new() -> WaitCondition {
        WaitCondition {
            contexts: Mutex::new(Vec::new())
        }
    }

    pub fn notify(&self) -> usize {
        let mut contexts = self.contexts.lock();
        let len = contexts.len();
        while let Some(context_lock) = contexts.pop() {
            context_lock.write().unblock();
        }
        len
    }

    pub fn wait(&self) -> bool {
        let id;
        {
            let context_lock = {
                let contexts = context::contexts();
                let context_lock = contexts.current().expect("WaitCondition::wait: no context");
                Arc::clone(&context_lock)
            };

            {
                let mut context = context_lock.write();
                id = context.id;
                context.block();
            }

            self.contexts.lock().push(context_lock);
        }

        unsafe { context::switch(); }

        let mut waited = true;

        {
            let mut contexts = self.contexts.lock();

            let mut i = 0;
            while i < contexts.len() {
                let remove = {
                    let context = contexts[i].read();
                    context.id == id
                };

                if remove {
                    contexts.remove(i);
                    waited = false;
                    break;
                } else {
                    i += 1;
                }
            }
        }

        waited
    }
}

impl Drop for WaitCondition {
    fn drop(&mut self){
        self.notify();
    }
}
<commit_msg>Add notify_signal method to WaitCondition to simulate being woken by a signal<commit_after>use alloc::sync::Arc;
use alloc::vec::Vec;
use spin::{Mutex, RwLock};

use crate::context::{self, Context};

#[derive(Debug)]
pub struct WaitCondition {
    contexts: Mutex<Vec<Arc<RwLock<Context>>>>
}

impl WaitCondition {
    pub fn new() -> WaitCondition {
        WaitCondition {
            contexts: Mutex::new(Vec::new())
        }
    }

    // Notify all waiters
    pub fn notify(&self) -> usize {
        let mut contexts = self.contexts.lock();
        let len = contexts.len();
        while let Some(context_lock) = contexts.pop() {
            context_lock.write().unblock();
        }
        len
    }

    // Notify as though a signal woke the waiters
    pub unsafe fn notify_signal(&self) -> usize {
        let contexts = self.contexts.lock();
        let len = contexts.len();
        for context_lock in contexts.iter() {
            context_lock.write().unblock();
        }
        len
    }

    // Wait until notified. Returns false if resumed by a signal or the notify_signal function
    pub fn wait(&self) -> bool {
        let id;
        {
            let context_lock = {
                let contexts = context::contexts();
                let context_lock = contexts.current().expect("WaitCondition::wait: no context");
                Arc::clone(&context_lock)
            };

            {
                let mut context = context_lock.write();
                id = context.id;
                context.block();
            }

            self.contexts.lock().push(context_lock);
        }

        unsafe { context::switch(); }

        let mut waited = true;

        {
            let mut contexts = self.contexts.lock();

            let mut i = 0;
            while i < contexts.len() {
                let remove = {
                    let context = contexts[i].read();
                    context.id == id
                };

                if remove {
                    contexts.remove(i);
                    waited = false;
                    break;
                } else {
                    i += 1;
                }
            }
        }

        waited
    }
}

impl Drop for WaitCondition {
    fn drop(&mut self){
        unsafe { self.notify_signal() };
    }
}
<|endoftext|>


<commit_before>#![deny(
        trivial_casts, trivial_numeric_casts,
        unsafe_code,
        unstable_features,
        unused_extern_crates, unused_import_braces, unused_qualifications)]
#![warn(unused_results)]

extern crate bio;
extern crate csv;
extern crate itertools;
extern crate linked_hash_map;
extern crate multimap;
#[macro_use]
extern crate quick_error;
extern crate regex;

use std::num::ParseFloatError;

pub use bio::utils::Strand;
pub use bio::io::gff::GffType;
use csv::Error as CsvError;
use regex::Error as RegexError;

mod model;
pub use model::{Feature, ModelError, FeatureKind,
                EBuilder, Exon, ExonFeature, ExonFeatureKind,
                TBuilder, Transcript, TranscriptFeature, TranscriptFeatureKind,
                GBuilder, Gene, GeneFeature, GeneFeatureKind};

mod io_refflat;
pub use io_refflat::{Reader as RefFlatReader, Writer as RefFlatWriter,
                     RefFlatError, RefFlatRow, RefFlatRecord,
                     RefFlatRecordsStream, RefFlatTranscriptsStream, RefFlatGenesStream};

mod io_gff;
pub use io_gff::{Reader as GffReader, GffError, GffTranscripts};

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        Model(err: ModelError) {
            description(err.description())
            display("{}", err)
            from()
            cause(err)
        }
        RefFlat(err: RefFlatError) {
            description(err.description())
            display("{}", err)
            from()
            cause(err)
        }
        Gff(err: GffError) {
            description(err.description())
            display("{}", err)
            from()
            cause(err)
        }
        Regex(err: RegexError) {
            description(err.description())
            from()
            cause(err)
        }
        Csv(err: CsvError) {
            description(err.description())
            from()
            cause(err)
        }
        ParseFloat(err: ParseFloatError) {
            description(err.description())
            from()
            cause(err)
        }
    }
}

pub type Result<T> = ::std::result::Result<T, Error>;

// Helper type for raw coordinates
type Coord<T> = (T, T);

// Helper type alias for raw transcript coordinate inputs
type RawTrxCoords = (Coord<u64>, Vec<Coord<u64>>, Option<Coord<u64>>);

// Crate-wide constants
mod consts {
    // Initial coordinate for features.
    pub(crate) const INIT_START: u64 = ::std::u64::MAX;
    pub(crate) const INIT_END: u64 = ::std::u64::MIN;
    pub(crate) const INIT_COORD: (u64, u64) = (INIT_START, INIT_END);

    // Various commonly-used feature column values
    pub(crate) const GENE_STR: &'static str = "gene";
    pub(crate) const TRANSCRIPT_STR: &'static str = "transcript";
    pub(crate) const EXON_STR: &'static str = "exon";
    pub(crate) const UTR_STR: &'static str = "UTR";
    pub(crate) const UTR5_STR: &'static str = "UTR5";
    pub(crate) const UTR3_STR: &'static str = "UTR3";
    pub(crate) const CDS_STR: &'static str = "CDS";
    pub(crate) const START_CODON_STR: &'static str = "start_codon";
    pub(crate) const STOP_CODON_STR: &'static str = "stop_codon";

    // Value for unknown columns.
    pub(crate) const UNK_STR: &'static str = ".";
    pub(crate) const UNK_CHAR: char = '.';

    // Commonly-used attribute keys.
    pub(crate) const GENE_ID_STR: &'static str = "gene_id";
    pub(crate) const TRANSCRIPT_ID_STR: &'static str = "transcript_id";

    // Value for optionally known strings.
    pub(crate) const DEF_ID: &'static str = "<unknown>";
}

// Generic utilities
mod utils {
    use std::ops::Deref;

    // taken from: https://stackoverflow.com/q/31233938/243058
    pub(crate) trait OptionDeref<T: Deref> {
        fn as_deref(&self) -> Option<&T::Target>;
    }

    impl<T: Deref> OptionDeref<T> for Option<T> {
        fn as_deref(&self) -> Option<&T::Target> {
            self.as_ref().map(Deref::deref)
        }
    }

    #[inline]
    pub(crate) fn update_contig<'a>(
        value: &'a mut String,
        prefix: Option<&'a str>,
        lstrip: Option<(&'a str, usize)>,
    ) {
        if let Some(ref pre) = prefix {
            value.insert_str(0, pre);
        }
        if let Some((ref lstr, lstr_len)) = lstrip {
            if value.starts_with(lstr) {
                let _ = value.drain(..lstr_len);
            }
        }
    }
}
<commit_msg>Remove unused ParseFloat error enum<commit_after>#![deny(
        trivial_casts, trivial_numeric_casts,
        unsafe_code,
        unstable_features,
        unused_extern_crates, unused_import_braces, unused_qualifications)]
#![warn(unused_results)]

extern crate bio;
extern crate csv;
extern crate itertools;
extern crate linked_hash_map;
extern crate multimap;
#[macro_use]
extern crate quick_error;
extern crate regex;

pub use bio::utils::Strand;
pub use bio::io::gff::GffType;
use csv::Error as CsvError;
use regex::Error as RegexError;

mod model;
pub use model::{Feature, ModelError, FeatureKind,
                EBuilder, Exon, ExonFeature, ExonFeatureKind,
                TBuilder, Transcript, TranscriptFeature, TranscriptFeatureKind,
                GBuilder, Gene, GeneFeature, GeneFeatureKind};

mod io_refflat;
pub use io_refflat::{Reader as RefFlatReader, Writer as RefFlatWriter,
                     RefFlatError, RefFlatRow, RefFlatRecord,
                     RefFlatRecordsStream, RefFlatTranscriptsStream, RefFlatGenesStream};

mod io_gff;
pub use io_gff::{Reader as GffReader, GffError, GffTranscripts};

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        Model(err: ModelError) {
            description(err.description())
            display("{}", err)
            from()
            cause(err)
        }
        RefFlat(err: RefFlatError) {
            description(err.description())
            display("{}", err)
            from()
            cause(err)
        }
        Gff(err: GffError) {
            description(err.description())
            display("{}", err)
            from()
            cause(err)
        }
        Regex(err: RegexError) {
            description(err.description())
            from()
            cause(err)
        }
        Csv(err: CsvError) {
            description(err.description())
            from()
            cause(err)
        }
    }
}

pub type Result<T> = ::std::result::Result<T, Error>;

// Helper type for raw coordinates
type Coord<T> = (T, T);

// Helper type alias for raw transcript coordinate inputs
type RawTrxCoords = (Coord<u64>, Vec<Coord<u64>>, Option<Coord<u64>>);

// Crate-wide constants
mod consts {
    // Initial coordinate for features.
    pub(crate) const INIT_START: u64 = ::std::u64::MAX;
    pub(crate) const INIT_END: u64 = ::std::u64::MIN;
    pub(crate) const INIT_COORD: (u64, u64) = (INIT_START, INIT_END);

    // Various commonly-used feature column values
    pub(crate) const GENE_STR: &'static str = "gene";
    pub(crate) const TRANSCRIPT_STR: &'static str = "transcript";
    pub(crate) const EXON_STR: &'static str = "exon";
    pub(crate) const UTR_STR: &'static str = "UTR";
    pub(crate) const UTR5_STR: &'static str = "UTR5";
    pub(crate) const UTR3_STR: &'static str = "UTR3";
    pub(crate) const CDS_STR: &'static str = "CDS";
    pub(crate) const START_CODON_STR: &'static str = "start_codon";
    pub(crate) const STOP_CODON_STR: &'static str = "stop_codon";

    // Value for unknown columns.
    pub(crate) const UNK_STR: &'static str = ".";
    pub(crate) const UNK_CHAR: char = '.';

    // Commonly-used attribute keys.
    pub(crate) const GENE_ID_STR: &'static str = "gene_id";
    pub(crate) const TRANSCRIPT_ID_STR: &'static str = "transcript_id";

    // Value for optionally known strings.
    pub(crate) const DEF_ID: &'static str = "<unknown>";
}

// Generic utilities
mod utils {
    use std::ops::Deref;

    // taken from: https://stackoverflow.com/q/31233938/243058
    pub(crate) trait OptionDeref<T: Deref> {
        fn as_deref(&self) -> Option<&T::Target>;
    }

    impl<T: Deref> OptionDeref<T> for Option<T> {
        fn as_deref(&self) -> Option<&T::Target> {
            self.as_ref().map(Deref::deref)
        }
    }

    #[inline]
    pub(crate) fn update_contig<'a>(
        value: &'a mut String,
        prefix: Option<&'a str>,
        lstrip: Option<(&'a str, usize)>,
    ) {
        if let Some(ref pre) = prefix {
            value.insert_str(0, pre);
        }
        if let Some((ref lstr, lstr_len)) = lstrip {
            if value.starts_with(lstr) {
                let _ = value.drain(..lstr_len);
            }
        }
    }
}
<|endoftext|>


<commit_before>// pp-exact

#[cfg(FALSE)]
fn simple_attr() {

    #[attr]
    if true { }

    #[allow_warnings]
    if true { }
}

#[cfg(FALSE)]
fn if_else_chain() {

    #[first_attr]
    if true { } else if false { } else { }
}

#[cfg(FALSE)]
fn if_let() {

    #[attr]
    if let Some(_) = Some(true) { }
}

fn main() { }
<commit_msg>Extent pretty-print test<commit_after>// pp-exact

#[cfg(FALSE)]
fn simple_attr() {

    #[attr]
    if true { }

    #[allow_warnings]
    if true { }
}

#[cfg(FALSE)]
fn if_else_chain() {

    #[first_attr]
    if true { } else if false { } else { }
}

#[cfg(FALSE)]
fn if_let() {

    #[attr]
    if let Some(_) = Some(true) { }
}

#[cfg(FALSE)]
fn let_attr_if() {
    let _ = #[attr] if let _ = 0 { };
    let _ = #[attr] if true { };

    let _ = #[attr] if let _ = 0 { } else { };
    let _ = #[attr] if true { } else { };
}

fn main() { }
<|endoftext|>


<commit_before>use cargo_registry::util::AppResponse;
use serde_json::Value;
use std::marker::PhantomData;

use conduit::{Body, HandlerResult};

use conduit::{header, StatusCode};

/// A type providing helper methods for working with responses
#[must_use]
pub struct Response<T> {
    response: AppResponse,
    return_type: PhantomData<T>,
}

impl<T> Response<T>
where
    for<'de> T: serde::Deserialize<'de>,
{
    /// Assert that the response is good and deserialize the message
    #[track_caller]
    pub fn good(mut self) -> T {
        if !self.status().is_success() {
            panic!("bad response: {:?}", self.status());
        }
        json(&mut self.response)
    }
}

impl<T> Response<T> {
    #[track_caller]
    pub(super) fn new(response: HandlerResult) -> Self {
        Self {
            response: assert_ok!(response),
            return_type: PhantomData,
        }
    }

    /// Consume the response body and convert it to a JSON value
    #[track_caller]
    // TODO: Rename to into_json()
    pub fn json(mut self) -> Value {
        json(&mut self.response)
    }

    pub fn status(&self) -> StatusCode {
        self.response.status()
    }

    #[track_caller]
    pub fn assert_redirect_ends_with(&self, target: &str) -> &Self {
        assert!(self
            .response
            .headers()
            .get(header::LOCATION)
            .unwrap()
            .to_str()
            .unwrap()
            .ends_with(target));
        self
    }
}

impl Response<()> {
    /// Assert that the status code is 404
    #[track_caller]
    pub fn assert_not_found(&self) {
        assert_eq!(StatusCode::NOT_FOUND, self.status());
    }

    /// Assert that the status code is 403
    #[track_caller]
    pub fn assert_forbidden(&self) {
        assert_eq!(StatusCode::FORBIDDEN, self.status());
    }
}

fn json<T>(r: &mut AppResponse) -> T
where
    for<'de> T: serde::Deserialize<'de>,
{
    use conduit::Body::*;

    let mut body = Body::empty();
    std::mem::swap(r.body_mut(), &mut body);
    let body: std::borrow::Cow<'static, [u8]> = match body {
        Static(slice) => slice.into(),
        Owned(vec) => vec.into(),
        File(_) => unimplemented!(),
    };

    assert_eq!(
        r.headers()
            .get(header::CONTENT_TYPE)
            .expect("Missing content-type header"),
        "application/json; charset=utf-8"
    );

    assert_eq!(
        r.headers()
            .get(header::CONTENT_LENGTH)
            .expect("Missing content-length header")
            .to_str()
            .unwrap()
            .parse(),
        Ok(body.len())
    );

    let s = std::str::from_utf8(&body).unwrap();
    match serde_json::from_str(s) {
        Ok(t) => t,
        Err(e) => panic!("failed to decode: {:?}\n{}", e, s),
    }
}
<commit_msg>Simplify json deserialization slightly<commit_after>use cargo_registry::util::AppResponse;
use serde_json::Value;
use std::marker::PhantomData;

use conduit::{Body, HandlerResult};

use conduit::{header, StatusCode};

/// A type providing helper methods for working with responses
#[must_use]
pub struct Response<T> {
    response: AppResponse,
    return_type: PhantomData<T>,
}

impl<T> Response<T>
where
    for<'de> T: serde::Deserialize<'de>,
{
    /// Assert that the response is good and deserialize the message
    #[track_caller]
    pub fn good(mut self) -> T {
        if !self.status().is_success() {
            panic!("bad response: {:?}", self.status());
        }
        json(&mut self.response)
    }
}

impl<T> Response<T> {
    #[track_caller]
    pub(super) fn new(response: HandlerResult) -> Self {
        Self {
            response: assert_ok!(response),
            return_type: PhantomData,
        }
    }

    /// Consume the response body and convert it to a JSON value
    #[track_caller]
    // TODO: Rename to into_json()
    pub fn json(mut self) -> Value {
        json(&mut self.response)
    }

    pub fn status(&self) -> StatusCode {
        self.response.status()
    }

    #[track_caller]
    pub fn assert_redirect_ends_with(&self, target: &str) -> &Self {
        assert!(self
            .response
            .headers()
            .get(header::LOCATION)
            .unwrap()
            .to_str()
            .unwrap()
            .ends_with(target));
        self
    }
}

impl Response<()> {
    /// Assert that the status code is 404
    #[track_caller]
    pub fn assert_not_found(&self) {
        assert_eq!(StatusCode::NOT_FOUND, self.status());
    }

    /// Assert that the status code is 403
    #[track_caller]
    pub fn assert_forbidden(&self) {
        assert_eq!(StatusCode::FORBIDDEN, self.status());
    }
}

fn json<T>(r: &mut AppResponse) -> T
where
    for<'de> T: serde::Deserialize<'de>,
{
    use conduit::Body::*;

    let mut body = Body::empty();
    std::mem::swap(r.body_mut(), &mut body);
    let body: std::borrow::Cow<'static, [u8]> = match body {
        Static(slice) => slice.into(),
        Owned(vec) => vec.into(),
        File(_) => unimplemented!(),
    };

    assert_eq!(
        r.headers()
            .get(header::CONTENT_TYPE)
            .expect("Missing content-type header"),
        "application/json; charset=utf-8"
    );

    assert_eq!(
        r.headers()
            .get(header::CONTENT_LENGTH)
            .expect("Missing content-length header")
            .to_str()
            .unwrap()
            .parse(),
        Ok(body.len())
    );

    match serde_json::from_slice(&*body) {
        Ok(t) => t,
        Err(e) => panic!("failed to decode: {:?}", e),
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::vec::Vec;
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
use std::cell::Cell;
use std::mem; // XXX what are you doing with your life?

use variable::{TVar, Address};
use res::{StmResult, StmError};

static GLOBAL_SEQ_LOCK: AtomicUsize = ATOMIC_USIZE_INIT;

// XXX what was the point of this besides acting tough?
struct Value(pub usize);

pub struct Transaction {
    snapshot : usize,
    write_set: HashMap<Address, Value>,
    read_set: Vec<(Address, Value)>,
}

impl Transaction {
    // XXX what is this ss??? wouldn't it make more sense to pull it from the global directly?
    fn new(ss: usize) -> Transaction {
        Transaction {
            snapshot: ss,
            write_set: HashMap::new(),
            read_set: Vec::new(),
        }
    }

    pub fn run<T, F>(f: F) -> T
    where F: Fn(&mut Transaction) -> StmResult<T>,
    {
        let mut ss = GLOBAL_SEQ_LOCK.load(Ordering::SeqCst);
        while (ss & 1) != 0 {
            ss = GLOBAL_SEQ_LOCK.load(Ordering::SeqCst);
        }
        let mut transaction = Transaction::new(ss);
        loop {
            match f(&mut transaction) {
                Ok(t) => {
                    if transaction.commit() {
                        return t;
                    }
                }
                Err(_) => { }
            }
            transaction.clear();
        }
    }

    pub fn read<T>(&mut self, var: &TVar<T>) -> StmResult<T> {
        match self.write_set.get(&var.get_addr()) {
            // XXX UHHHH something is very wrong; what was the point of keeping
            // PhantomData<T> around if we're just going to do this?
            // RELOOK
            // xref: variable.rs:6
            Some(&Value(val)) => { return Ok(mem::transmute(val)); }
            None => {}
        }
        let mut val = (*var).value;
        while self.snapshot != GLOBAL_SEQ_LOCK.load(Ordering::SeqCst) {
            match self.validate() {
                None => { return Err(StmError::Retry); }
                Some(ss) => {
                    self.snapshot = ss;
                    val = (*var).value;
                }
            }
        }
        self.read_set.push((var.get_addr(), Value(val)));
        // XXX same fucking comment
        Ok(mem::transmute(val))
    }

    pub fn write<T>(&mut self, var: &mut TVar<T>, value: T) -> StmResult<()> {
        self.write_set.insert(var.get_addr(), Value(value));
        Ok(())

    }

    // XXX what is this for?
    fn clear(&mut self) {
        self.read_set.clear();
        self.write_set.clear();
    }

    fn validate(&self) -> Option<usize> {
        loop {
            let time = GLOBAL_SEQ_LOCK.load(Ordering::SeqCst);
            if time & 1 != 0 {
                continue;
            }
            for (addr, val) in self.read_set {
                if (*addr).value != val {
                    // XXX this should handle aborts more... "gracefully"?
                    return None;
                }
            }
            if time == GLOBAL_SEQ_LOCK.load(Ordering::SeqCst) {
                return Some(time);
            }
        }
    }

    fn commit(&mut self) -> bool {
        if self.writeSet.is_empty() {
            return true;
        }
        while GLOBAL_SEQ_LOCK.compare_and_swap(self.snapshot, self.snapshot+1, Ordering::SeqCst) != self.snapshot {
            self.snapshot = self.validate();
            if self.snapshot < 0 {
                // XXX I'm sorry, why is this bailing?
                return false;
            }
        }
        for (addr, val) in self.writeSet.iter() {
            (*addr).value = val;
        }
        // XXX is this really just a plain store? seems sketchy
        GLOBAL_SEQ_LOCK.store(self.snapshot + 2, Ordering::SeqCst);
        return true;
    }
}

<commit_msg>fascinating, need to cast usize back to TVar now<commit_after>use std::collections::HashMap;
use std::vec::Vec;
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
use std::cell::Cell;
use std::mem; // XXX what are you doing with your life?

use variable::{TVar, Address};
use res::{StmResult, StmError};

static GLOBAL_SEQ_LOCK: AtomicUsize = ATOMIC_USIZE_INIT;

// XXX what was the point of this besides acting tough?
struct Value(pub usize);

pub struct Transaction {
    snapshot : usize,
    write_set: HashMap<Address, Value>,
    read_set: Vec<(Address, Value)>,
}

impl Transaction {
    // XXX what is this ss??? wouldn't it make more sense to pull it from the global directly?
    fn new(ss: usize) -> Transaction {
        Transaction {
            snapshot: ss,
            write_set: HashMap::new(),
            read_set: Vec::new(),
        }
    }

    pub fn run<T, F>(f: F) -> T
    where F: Fn(&mut Transaction) -> StmResult<T>,
    {
        let mut ss = GLOBAL_SEQ_LOCK.load(Ordering::SeqCst);
        while (ss & 1) != 0 {
            ss = GLOBAL_SEQ_LOCK.load(Ordering::SeqCst);
        }
        let mut transaction = Transaction::new(ss);
        loop {
            match f(&mut transaction) {
                Ok(t) => {
                    if transaction.commit() {
                        return t;
                    }
                }
                Err(_) => { }
            }
            transaction.clear();
        }
    }

    pub fn read<T>(&mut self, var: &TVar<T>) -> StmResult<T> {
        match self.write_set.get(&var.get_addr()) {
            // XXX UHHHH something is very wrong; what was the point of keeping
            // PhantomData<T> around if we're just going to do this?
            // RELOOK
            // xref: variable.rs:6
            Some(&Value(val)) => { return Ok(mem::transmute(val)); }
            None => {}
        }
        let mut val = (*var).value;
        while self.snapshot != GLOBAL_SEQ_LOCK.load(Ordering::SeqCst) {
            match self.validate() {
                None => { return Err(StmError::Retry); }
                Some(ss) => {
                    self.snapshot = ss;
                    val = (*var).value;
                }
            }
        }
        self.read_set.push((var.get_addr(), Value(val)));
        // XXX same fucking comment
        Ok(mem::transmute(val))
    }

    pub fn write<T>(&mut self, var: &mut TVar<T>, value: T) -> StmResult<()> {
        self.write_set.insert(var.get_addr(), Value(mem::transmute(value)));
        Ok(())

    }

    // XXX what is this for?
    fn clear(&mut self) {
        self.read_set.clear();
        self.write_set.clear();
    }

    fn validate(&self) -> Option<usize> {
        loop {
            let time = GLOBAL_SEQ_LOCK.load(Ordering::SeqCst);
            if time & 1 != 0 {
                continue;
            }
            for (Address(addr), Value(val)) in self.read_set {
                if addr != val {
                    // XXX this should handle aborts more... "gracefully"?
                    return None;
                }
            }
            if time == GLOBAL_SEQ_LOCK.load(Ordering::SeqCst) {
                return Some(time);
            }
        }
    }

    fn commit(&mut self) -> bool {
        if self.write_set.is_empty() {
            return true;
        }
        while GLOBAL_SEQ_LOCK.compare_and_swap(self.snapshot, self.snapshot+1, Ordering::SeqCst) != self.snapshot {
            match self.validate() {
                None => { return false; } // XXX why is this bailing?
                Some(ss) => { self.snapshot = ss; }
            }
        }
        for (addr, val) in self.write_set.iter() {
            (*addr).value = val;
        }
        // XXX is this really just a plain store? seems sketchy
        GLOBAL_SEQ_LOCK.store(self.snapshot + 2, Ordering::SeqCst);
        return true;
    }
}

<|endoftext|>


<commit_before>//! EGL-based surface and swapchain.

use crate::{conv, native, GlContainer, PhysicalDevice, Starc};
use glow::HasContext;
use hal::{image, window as w};
use std::{os::raw, ptr};

#[derive(Debug)]
pub struct Swapchain {
    framebuffer: glow::Framebuffer,
    renderbuffer: glow::Renderbuffer,
    /// Extent because the window lies
    extent: w::Extent2D,
    format: native::TextureFormat,
    channel: hal::format::ChannelType,
}

#[derive(Debug)]
pub struct Instance {
    egl: Starc<egl::DynamicInstance>,
    display: egl::Display,
    version: (i32, i32),
    config: egl::Config,
    context: egl::Context,
    supports_native_window: bool,
}

unsafe impl Send for Instance {}
unsafe impl Sync for Instance {}

fn get_x11_open_display() -> Option<ptr::NonNull<raw::c_void>> {
    type XOpenDisplayFun =
        unsafe extern "system" fn(display_name: *const raw::c_char) -> *mut raw::c_void;
    log::info!("Loading X11 library to get the current display");
    let library = libloading::Library::new("libX11.so").ok()?;
    let func: libloading::Symbol<XOpenDisplayFun> =
        unsafe { library.get(b"XOpenDisplay").unwrap() };
    ptr::NonNull::new(unsafe { func(ptr::null()) })
}

impl hal::Instance<crate::Backend> for Instance {
    fn create(_: &str, _: u32) -> Result<Self, hal::UnsupportedBackend> {
        let egl = match unsafe { egl::DynamicInstance::load() } {
            Ok(egl) => Starc::new(egl),
            Err(e) => {
                log::warn!("Unable to open libEGL.so: {:?}", e);
                return Err(hal::UnsupportedBackend);
            }
        };

        let client_extensions = egl
            .query_string(None, egl::EXTENSIONS)
            .map_err(|_| hal::UnsupportedBackend)?
            .to_string_lossy();
        log::info!("Client extensions: {:?}", client_extensions);
        let client_ext_list = client_extensions.split_whitespace().collect::<Vec<_>>();

        let mut is_default_display = false;
        let x11_display = if client_ext_list.contains(&"EGL_EXT_platform_x11") {
            get_x11_open_display()
        } else {
            None
        };
        let display = if let Some(x11_display) = x11_display {
            log::info!("Using X11 platform");
            const EGL_PLATFORM_X11_KHR: u32 = 0x31D5;
            let display_attributes = [egl::ATTRIB_NONE];
            egl.get_platform_display(
                EGL_PLATFORM_X11_KHR,
                x11_display.as_ptr(),
                &display_attributes,
            )
            .unwrap()
        } else {
            log::info!("Using default platform");
            is_default_display = true;
            egl.get_display(egl::DEFAULT_DISPLAY).unwrap()
        };

        let version = egl
            .initialize(display)
            .map_err(|_| hal::UnsupportedBackend)?;
        let vendor = egl.query_string(Some(display), egl::VENDOR).unwrap();
        let display_extensions = egl
            .query_string(Some(display), egl::EXTENSIONS)
            .unwrap()
            .to_string_lossy();
        log::info!(
            "Display vendor {:?}, version {:?}, extensions: {:?}",
            vendor,
            version,
            display_extensions
        );
        if version < (1, 4) {
            log::error!("EGL supported version is only {:?}", version);
            return Err(hal::UnsupportedBackend);
        }
        let display_ext_list = display_extensions.split_whitespace().collect::<Vec<_>>();
        let required_display_extensions = ["EGL_KHR_create_context", "EGL_KHR_surfaceless_context"];
        for required_ext in required_display_extensions.iter() {
            if !display_ext_list.contains(required_ext) {
                log::warn!("{} is not present", required_ext);
            }
        }

        if log::max_level() >= log::LevelFilter::Trace {
            log::trace!("Configurations:");
            let config_count = egl.get_config_count(display).unwrap();
            let mut configurations = Vec::with_capacity(config_count);
            egl.get_configs(display, &mut configurations).unwrap();
            for &config in configurations.iter() {
                log::trace!("\tCONFORMANT=0x{:X}, RENDERABLE=0x{:X}, NATIVE_RENDERABLE=0x{:X}, SURFACE_TYPE=0x{:X}",
                    egl.get_config_attrib(display, config, egl::CONFORMANT).unwrap(),
                    egl.get_config_attrib(display, config, egl::RENDERABLE_TYPE).unwrap(),
                    egl.get_config_attrib(display, config, egl::NATIVE_RENDERABLE).unwrap(),
                    egl.get_config_attrib(display, config, egl::SURFACE_TYPE).unwrap(),
                );
            }
        }

        //Note: only GLES is supported here.
        let mut supports_native_window = true;
        //TODO: EGL_SLOW_CONFIG
        let config_attributes = [
            egl::CONFORMANT,
            egl::OPENGL_ES2_BIT,
            egl::RENDERABLE_TYPE,
            egl::OPENGL_ES2_BIT,
            egl::NATIVE_RENDERABLE,
            egl::TRUE as _,
            egl::SURFACE_TYPE,
            egl::WINDOW_BIT,
            egl::NONE,
        ];
        let pre_config = if is_default_display {
            Ok(None)
        } else {
            egl.choose_first_config(display, &config_attributes)
        };
        let config = match pre_config {
            Ok(Some(config)) => config,
            Ok(None) => {
                log::warn!("no compatible EGL config found, trying off-screen");
                supports_native_window = false;
                let reduced_config_attributes =
                    [egl::RENDERABLE_TYPE, egl::OPENGL_ES2_BIT, egl::NONE];
                match egl.choose_first_config(display, &reduced_config_attributes) {
                    Ok(Some(config)) => config,
                    _ => return Err(hal::UnsupportedBackend),
                }
            }
            Err(e) => {
                log::error!("error in choose_first_config: {:?}", e);
                return Err(hal::UnsupportedBackend);
            }
        };

        egl.bind_api(egl::OPENGL_ES_API).unwrap();

        //TODO: make it so `Device` == EGL Context
        let mut context_attributes = vec![
            egl::CONTEXT_CLIENT_VERSION,
            3, // Request GLES 3.0 or higher
        ];
        if cfg!(debug_assertions) && !is_default_display {
            //TODO: figure out why this is needed
            context_attributes.push(egl::CONTEXT_OPENGL_DEBUG);
            context_attributes.push(egl::TRUE as _);
        }
        context_attributes.push(egl::NONE as _);
        let context = match egl.create_context(display, config, None, &context_attributes) {
            Ok(context) => context,
            Err(e) => {
                log::warn!("unable to create GLES 3.x context: {:?}", e);
                return Err(hal::UnsupportedBackend);
            }
        };

        Ok(Instance {
            egl,
            display,
            version,
            config,
            context,
            supports_native_window,
        })
    }

    fn enumerate_adapters(&self) -> Vec<hal::adapter::Adapter<crate::Backend>> {
        self.egl
            .make_current(self.display, None, None, Some(self.context))
            .unwrap();
        let context = unsafe {
            glow::Context::from_loader_function(|name| {
                self.egl.get_proc_address(name).unwrap() as *const _
            })
        };
        // Create physical device
        vec![PhysicalDevice::new_adapter(context)]
    }

    unsafe fn create_surface(
        &self,
        has_handle: &impl raw_window_handle::HasRawWindowHandle,
    ) -> Result<Surface, w::InitError> {
        use raw_window_handle::RawWindowHandle as Rwh;
        let mut native_window = match has_handle.raw_window_handle() {
            #[cfg(not(target_os = "android"))]
            Rwh::Xlib(handle) => handle.window,
            #[cfg(not(target_os = "android"))]
            Rwh::Xcb(handle) => handle.window as _,
            #[cfg(target_os = "android")]
            Rwh::Android(handle) => handle.a_native_window,
            other => panic!("Unsupported window: {:?}", other),
        };
        let attributes = [
            egl::RENDER_BUFFER as usize,
            egl::SINGLE_BUFFER as usize,
            // Always enable sRGB
            egl::GL_COLORSPACE as usize,
            egl::GL_COLORSPACE_SRGB as usize,
            egl::ATTRIB_NONE,
        ];
        match self.egl.create_platform_window_surface(
            self.display,
            self.config,
            &mut native_window as *mut _ as *mut _,
            &attributes,
        ) {
            Ok(raw) => Ok(Surface {
                egl: self.egl.clone(),
                raw,
                display: self.display,
                context: self.context,
                presentable: self.supports_native_window,
                swapchain: None,
            }),
            Err(e) => {
                log::warn!("Error in create_window_surface: {:?}", e);
                Err(w::InitError::UnsupportedWindowHandle)
            }
        }
    }

    unsafe fn destroy_surface(&self, surface: Surface) {
        self.egl.destroy_surface(self.display, surface.raw).unwrap();
    }
}

impl Drop for Instance {
    fn drop(&mut self) {
        if let Err(e) = self.egl.destroy_context(self.display, self.context) {
            log::warn!("Error in destroy_context: {:?}", e);
        }
        if let Err(e) = self.egl.terminate(self.display) {
            log::warn!("Error in terminate: {:?}", e);
        }
    }
}

#[derive(Debug)]
pub struct Surface {
    egl: Starc<egl::DynamicInstance>,
    raw: egl::Surface,
    display: egl::Display,
    context: egl::Context,
    presentable: bool,
    pub(crate) swapchain: Option<Swapchain>,
}

unsafe impl Send for Surface {}
unsafe impl Sync for Surface {}

impl w::PresentationSurface<crate::Backend> for Surface {
    type SwapchainImage = native::SwapchainImage;

    unsafe fn configure_swapchain(
        &mut self,
        device: &crate::Device,
        config: w::SwapchainConfig,
    ) -> Result<(), w::SwapchainError> {
        self.unconfigure_swapchain(device);

        let desc = conv::describe_format(config.format).unwrap();

        let gl = &device.share.context;
        let renderbuffer = gl.create_renderbuffer().unwrap();
        gl.bind_renderbuffer(glow::RENDERBUFFER, Some(renderbuffer));
        gl.renderbuffer_storage(
            glow::RENDERBUFFER,
            desc.tex_internal,
            config.extent.width as _,
            config.extent.height as _,
        );
        let framebuffer = gl.create_framebuffer().unwrap();
        gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(framebuffer));
        gl.framebuffer_renderbuffer(
            glow::READ_FRAMEBUFFER,
            glow::COLOR_ATTACHMENT0,
            glow::RENDERBUFFER,
            Some(renderbuffer),
        );
        gl.bind_renderbuffer(glow::RENDERBUFFER, None);
        gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None);

        self.swapchain = Some(Swapchain {
            renderbuffer,
            framebuffer,
            extent: config.extent,
            format: desc.tex_internal,
            channel: config.format.base_format().1,
        });

        Ok(())
    }

    unsafe fn unconfigure_swapchain(&mut self, device: &crate::Device) {
        let gl = &device.share.context;
        if let Some(sc) = self.swapchain.take() {
            gl.delete_renderbuffer(sc.renderbuffer);
            gl.delete_framebuffer(sc.framebuffer);
        }
    }

    unsafe fn acquire_image(
        &mut self,
        _timeout_ns: u64,
    ) -> Result<(Self::SwapchainImage, Option<w::Suboptimal>), w::AcquireError> {
        let sc = self.swapchain.as_ref().unwrap();
        let sc_image =
            native::SwapchainImage::new(sc.renderbuffer, sc.format, sc.extent, sc.channel);
        Ok((sc_image, None))
    }
}

impl w::Surface<crate::Backend> for Surface {
    fn supports_queue_family(&self, _: &crate::QueueFamily) -> bool {
        self.presentable
    }

    fn capabilities(&self, _physical_device: &PhysicalDevice) -> w::SurfaceCapabilities {
        w::SurfaceCapabilities {
            present_modes: w::PresentMode::FIFO,                  //TODO
            composite_alpha_modes: w::CompositeAlphaMode::OPAQUE, //TODO
            image_count: 2..=2,
            current_extent: None,
            extents: w::Extent2D {
                width: 4,
                height: 4,
            }..=w::Extent2D {
                width: 4096,
                height: 4096,
            },
            max_image_layers: 1,
            usage: image::Usage::COLOR_ATTACHMENT,
        }
    }

    fn supported_formats(
        &self,
        _physical_device: &PhysicalDevice,
    ) -> Option<Vec<hal::format::Format>> {
        use hal::format::Format;
        Some(vec![Format::Rgba8Srgb, Format::Bgra8Srgb])
    }
}

impl Surface {
    pub(crate) unsafe fn present(
        &mut self,
        _image: native::SwapchainImage,
        gl: &GlContainer,
    ) -> Result<Option<w::Suboptimal>, w::PresentError> {
        let sc = self.swapchain.as_ref().unwrap();

        self.egl
            .make_current(
                self.display,
                Some(self.raw),
                Some(self.raw),
                Some(self.context),
            )
            .unwrap();
        gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, None);
        gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(sc.framebuffer));
        gl.blit_framebuffer(
            0,
            0,
            sc.extent.width as _,
            sc.extent.height as _,
            0,
            0,
            sc.extent.width as _,
            sc.extent.height as _,
            glow::COLOR_BUFFER_BIT,
            glow::NEAREST,
        );
        gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None);

        self.egl.swap_buffers(self.display, self.raw).unwrap();
        self.egl
            .make_current(self.display, None, None, Some(self.context))
            .unwrap();

        Ok(None)
    }
}
<commit_msg>[gl] hold X11 library with the Instance<commit_after>//! EGL-based surface and swapchain.

use crate::{conv, native, GlContainer, PhysicalDevice, Starc};
use glow::HasContext;
use hal::{image, window as w};
use std::{os::raw, ptr};

#[derive(Debug)]
pub struct Swapchain {
    framebuffer: glow::Framebuffer,
    renderbuffer: glow::Renderbuffer,
    /// Extent because the window lies
    extent: w::Extent2D,
    format: native::TextureFormat,
    channel: hal::format::ChannelType,
}

#[derive(Debug)]
pub struct Instance {
    egl: Starc<egl::DynamicInstance>,
    display: egl::Display,
    version: (i32, i32),
    config: egl::Config,
    context: egl::Context,
    supports_native_window: bool,
    wsi_library: Option<libloading::Library>,
}

unsafe impl Send for Instance {}
unsafe impl Sync for Instance {}

type XOpenDisplayFun =
    unsafe extern "system" fn(display_name: *const raw::c_char) -> *mut raw::c_void;

impl hal::Instance<crate::Backend> for Instance {
    fn create(_: &str, _: u32) -> Result<Self, hal::UnsupportedBackend> {
        let egl = match unsafe { egl::DynamicInstance::load() } {
            Ok(egl) => Starc::new(egl),
            Err(e) => {
                log::warn!("Unable to open libEGL.so: {:?}", e);
                return Err(hal::UnsupportedBackend);
            }
        };

        let client_extensions = egl
            .query_string(None, egl::EXTENSIONS)
            .map_err(|_| hal::UnsupportedBackend)?
            .to_string_lossy();
        log::info!("Client extensions: {:?}", client_extensions);
        let client_ext_list = client_extensions.split_whitespace().collect::<Vec<_>>();

        let mut wsi_library = None;
        let x11_display = if client_ext_list.contains(&"EGL_EXT_platform_x11") {
            log::info!("Loading X11 library to get the current display");
            if let Ok(library) = libloading::Library::new("libX11.so") {
                let func: libloading::Symbol<XOpenDisplayFun> =
                    unsafe { library.get(b"XOpenDisplay").unwrap() };
                let result = unsafe { func(ptr::null()) };
                wsi_library = Some(library);
                ptr::NonNull::new(result)
            } else {
                None
            }
        } else {
            None
        };
        let display = if let Some(x11_display) = x11_display {
            log::info!("Using X11 platform");
            const EGL_PLATFORM_X11_KHR: u32 = 0x31D5;
            let display_attributes = [egl::ATTRIB_NONE];
            egl.get_platform_display(
                EGL_PLATFORM_X11_KHR,
                x11_display.as_ptr(),
                &display_attributes,
            )
            .unwrap()
        } else {
            log::info!("Using default platform");
            egl.get_display(egl::DEFAULT_DISPLAY).unwrap()
        };

        let version = egl
            .initialize(display)
            .map_err(|_| hal::UnsupportedBackend)?;
        let vendor = egl.query_string(Some(display), egl::VENDOR).unwrap();
        let display_extensions = egl
            .query_string(Some(display), egl::EXTENSIONS)
            .unwrap()
            .to_string_lossy();
        log::info!(
            "Display vendor {:?}, version {:?}, extensions: {:?}",
            vendor,
            version,
            display_extensions
        );
        if version < (1, 4) {
            log::error!("EGL supported version is only {:?}", version);
            return Err(hal::UnsupportedBackend);
        }
        let display_ext_list = display_extensions.split_whitespace().collect::<Vec<_>>();
        let required_display_extensions = ["EGL_KHR_create_context", "EGL_KHR_surfaceless_context"];
        for required_ext in required_display_extensions.iter() {
            if !display_ext_list.contains(required_ext) {
                log::warn!("{} is not present", required_ext);
            }
        }

        if log::max_level() >= log::LevelFilter::Trace {
            log::trace!("Configurations:");
            let config_count = egl.get_config_count(display).unwrap();
            let mut configurations = Vec::with_capacity(config_count);
            egl.get_configs(display, &mut configurations).unwrap();
            for &config in configurations.iter() {
                log::trace!("\tCONFORMANT=0x{:X}, RENDERABLE=0x{:X}, NATIVE_RENDERABLE=0x{:X}, SURFACE_TYPE=0x{:X}",
                    egl.get_config_attrib(display, config, egl::CONFORMANT).unwrap(),
                    egl.get_config_attrib(display, config, egl::RENDERABLE_TYPE).unwrap(),
                    egl.get_config_attrib(display, config, egl::NATIVE_RENDERABLE).unwrap(),
                    egl.get_config_attrib(display, config, egl::SURFACE_TYPE).unwrap(),
                );
            }
        }

        //Note: only GLES is supported here.
        let mut supports_native_window = true;
        //TODO: EGL_SLOW_CONFIG
        let config_attributes = [
            egl::CONFORMANT,
            egl::OPENGL_ES2_BIT,
            egl::RENDERABLE_TYPE,
            egl::OPENGL_ES2_BIT,
            egl::NATIVE_RENDERABLE,
            egl::TRUE as _,
            egl::SURFACE_TYPE,
            egl::WINDOW_BIT,
            egl::NONE,
        ];
        let pre_config = match wsi_library {
            Some(_) => egl.choose_first_config(display, &config_attributes),
            None => Ok(None),
        };
        let config = match pre_config {
            Ok(Some(config)) => config,
            Ok(None) => {
                log::warn!("no compatible EGL config found, trying off-screen");
                supports_native_window = false;
                let reduced_config_attributes =
                    [egl::RENDERABLE_TYPE, egl::OPENGL_ES2_BIT, egl::NONE];
                match egl.choose_first_config(display, &reduced_config_attributes) {
                    Ok(Some(config)) => config,
                    _ => return Err(hal::UnsupportedBackend),
                }
            }
            Err(e) => {
                log::error!("error in choose_first_config: {:?}", e);
                return Err(hal::UnsupportedBackend);
            }
        };

        egl.bind_api(egl::OPENGL_ES_API).unwrap();

        //TODO: make it so `Device` == EGL Context
        let mut context_attributes = vec![
            egl::CONTEXT_CLIENT_VERSION,
            3, // Request GLES 3.0 or higher
        ];
        if cfg!(debug_assertions) && wsi_library.is_none() {
            //TODO: figure out why this is needed
            context_attributes.push(egl::CONTEXT_OPENGL_DEBUG);
            context_attributes.push(egl::TRUE as _);
        }
        context_attributes.push(egl::NONE as _);
        let context = match egl.create_context(display, config, None, &context_attributes) {
            Ok(context) => context,
            Err(e) => {
                log::warn!("unable to create GLES 3.x context: {:?}", e);
                return Err(hal::UnsupportedBackend);
            }
        };

        Ok(Instance {
            egl,
            display,
            version,
            config,
            context,
            supports_native_window,
            wsi_library,
        })
    }

    fn enumerate_adapters(&self) -> Vec<hal::adapter::Adapter<crate::Backend>> {
        self.egl
            .make_current(self.display, None, None, Some(self.context))
            .unwrap();
        let context = unsafe {
            glow::Context::from_loader_function(|name| {
                self.egl.get_proc_address(name).unwrap() as *const _
            })
        };
        // Create physical device
        vec![PhysicalDevice::new_adapter(context)]
    }

    unsafe fn create_surface(
        &self,
        has_handle: &impl raw_window_handle::HasRawWindowHandle,
    ) -> Result<Surface, w::InitError> {
        use raw_window_handle::RawWindowHandle as Rwh;
        let mut native_window = match has_handle.raw_window_handle() {
            #[cfg(not(target_os = "android"))]
            Rwh::Xlib(handle) => handle.window,
            #[cfg(not(target_os = "android"))]
            Rwh::Xcb(handle) => handle.window as _,
            #[cfg(target_os = "android")]
            Rwh::Android(handle) => handle.a_native_window,
            other => panic!("Unsupported window: {:?}", other),
        };
        let attributes = [
            egl::RENDER_BUFFER as usize,
            egl::SINGLE_BUFFER as usize,
            // Always enable sRGB
            egl::GL_COLORSPACE as usize,
            egl::GL_COLORSPACE_SRGB as usize,
            egl::ATTRIB_NONE,
        ];
        match self.egl.create_platform_window_surface(
            self.display,
            self.config,
            &mut native_window as *mut _ as *mut _,
            &attributes,
        ) {
            Ok(raw) => Ok(Surface {
                egl: self.egl.clone(),
                raw,
                display: self.display,
                context: self.context,
                presentable: self.supports_native_window,
                swapchain: None,
            }),
            Err(e) => {
                log::warn!("Error in create_window_surface: {:?}", e);
                Err(w::InitError::UnsupportedWindowHandle)
            }
        }
    }

    unsafe fn destroy_surface(&self, surface: Surface) {
        self.egl.destroy_surface(self.display, surface.raw).unwrap();
    }
}

impl Drop for Instance {
    fn drop(&mut self) {
        if let Err(e) = self.egl.destroy_context(self.display, self.context) {
            log::warn!("Error in destroy_context: {:?}", e);
        }
        if let Err(e) = self.egl.terminate(self.display) {
            log::warn!("Error in terminate: {:?}", e);
        }
    }
}

#[derive(Debug)]
pub struct Surface {
    egl: Starc<egl::DynamicInstance>,
    raw: egl::Surface,
    display: egl::Display,
    context: egl::Context,
    presentable: bool,
    pub(crate) swapchain: Option<Swapchain>,
}

unsafe impl Send for Surface {}
unsafe impl Sync for Surface {}

impl w::PresentationSurface<crate::Backend> for Surface {
    type SwapchainImage = native::SwapchainImage;

    unsafe fn configure_swapchain(
        &mut self,
        device: &crate::Device,
        config: w::SwapchainConfig,
    ) -> Result<(), w::SwapchainError> {
        self.unconfigure_swapchain(device);

        let desc = conv::describe_format(config.format).unwrap();

        let gl = &device.share.context;
        let renderbuffer = gl.create_renderbuffer().unwrap();
        gl.bind_renderbuffer(glow::RENDERBUFFER, Some(renderbuffer));
        gl.renderbuffer_storage(
            glow::RENDERBUFFER,
            desc.tex_internal,
            config.extent.width as _,
            config.extent.height as _,
        );
        let framebuffer = gl.create_framebuffer().unwrap();
        gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(framebuffer));
        gl.framebuffer_renderbuffer(
            glow::READ_FRAMEBUFFER,
            glow::COLOR_ATTACHMENT0,
            glow::RENDERBUFFER,
            Some(renderbuffer),
        );
        gl.bind_renderbuffer(glow::RENDERBUFFER, None);
        gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None);

        self.swapchain = Some(Swapchain {
            renderbuffer,
            framebuffer,
            extent: config.extent,
            format: desc.tex_internal,
            channel: config.format.base_format().1,
        });

        Ok(())
    }

    unsafe fn unconfigure_swapchain(&mut self, device: &crate::Device) {
        let gl = &device.share.context;
        if let Some(sc) = self.swapchain.take() {
            gl.delete_renderbuffer(sc.renderbuffer);
            gl.delete_framebuffer(sc.framebuffer);
        }
    }

    unsafe fn acquire_image(
        &mut self,
        _timeout_ns: u64,
    ) -> Result<(Self::SwapchainImage, Option<w::Suboptimal>), w::AcquireError> {
        let sc = self.swapchain.as_ref().unwrap();
        let sc_image =
            native::SwapchainImage::new(sc.renderbuffer, sc.format, sc.extent, sc.channel);
        Ok((sc_image, None))
    }
}

impl w::Surface<crate::Backend> for Surface {
    fn supports_queue_family(&self, _: &crate::QueueFamily) -> bool {
        self.presentable
    }

    fn capabilities(&self, _physical_device: &PhysicalDevice) -> w::SurfaceCapabilities {
        w::SurfaceCapabilities {
            present_modes: w::PresentMode::FIFO,                  //TODO
            composite_alpha_modes: w::CompositeAlphaMode::OPAQUE, //TODO
            image_count: 2..=2,
            current_extent: None,
            extents: w::Extent2D {
                width: 4,
                height: 4,
            }..=w::Extent2D {
                width: 4096,
                height: 4096,
            },
            max_image_layers: 1,
            usage: image::Usage::COLOR_ATTACHMENT,
        }
    }

    fn supported_formats(
        &self,
        _physical_device: &PhysicalDevice,
    ) -> Option<Vec<hal::format::Format>> {
        use hal::format::Format;
        Some(vec![Format::Rgba8Srgb, Format::Bgra8Srgb])
    }
}

impl Surface {
    pub(crate) unsafe fn present(
        &mut self,
        _image: native::SwapchainImage,
        gl: &GlContainer,
    ) -> Result<Option<w::Suboptimal>, w::PresentError> {
        let sc = self.swapchain.as_ref().unwrap();

        self.egl
            .make_current(
                self.display,
                Some(self.raw),
                Some(self.raw),
                Some(self.context),
            )
            .unwrap();
        gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, None);
        gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(sc.framebuffer));
        gl.blit_framebuffer(
            0,
            0,
            sc.extent.width as _,
            sc.extent.height as _,
            0,
            0,
            sc.extent.width as _,
            sc.extent.height as _,
            glow::COLOR_BUFFER_BIT,
            glow::NEAREST,
        );
        gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None);

        self.egl.swap_buffers(self.display, self.raw).unwrap();
        self.egl
            .make_current(self.display, None, None, Some(self.context))
            .unwrap();

        Ok(None)
    }
}
<|endoftext|>