<commit_before>//! Work with spans of text.
//!
//! This module defines various structs describing a span of text from a
//! larger string.
use std::borrow::Cow;
use std::marker::PhantomData;

/// A string with associated spans.
///
/// Each span has an associated attribute `T`.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SpannedString<T> {
    source: String,
    spans: Vec<IndexedSpan<T>>,
}

/// The immutable, borrowed equivalent of `SpannedString`.
#[derive(Debug, PartialEq, Eq)]
pub struct SpannedStr<'a, T>
where
    T: 'a,
{
    source: &'a str,
    spans: &'a [IndexedSpan<T>],
}

/// Describes an object that appears like a `SpannedStr`.
pub trait SpannedText<T> {
    /// Returns the source text.
    fn source(&self) -> &str;

    /// Returns the spans for this text.
    fn spans(&self) -> &[IndexedSpan<T>];

    /// Returns a `SpannedText` by reference.
    fn as_ref<'a>(&'a self) -> SpannedTextRef<'a, T, Self> {
        SpannedTextRef {
            r: self,
            _phantom: PhantomData,
        }
    }
}

/// A reference to another `SpannedText`.
pub struct SpannedTextRef<'a, T, C>
where
    C: 'a + SpannedText<T> + ?Sized,
{
    r: &'a C,
    _phantom: PhantomData<T>,
}

impl<'a, T> SpannedText<T> for &'a SpannedString<T> {
    fn source(&self) -> &str {
        &self.source
    }

    fn spans(&self) -> &[IndexedSpan<T>] {
        &self.spans
    }
}

impl<'a, T, C> SpannedText<T> for SpannedTextRef<'a, T, C>
where
    C: 'a + SpannedText<T> + ?Sized,
{
    fn source(&self) -> &str {
        self.r.source()
    }

    fn spans(&self) -> &[IndexedSpan<T>] {
        self.r.spans()
    }
}

impl<'a, T> SpannedText<T> for SpannedStr<'a, T>
where
    T: 'a,
{
    fn source(&self) -> &str {
        self.source
    }

    fn spans(&self) -> &[IndexedSpan<T>] {
        self.spans
    }
}

impl<S, T> From<S> for SpannedString<T>
where
    S: Into<String>,
    T: Default,
{
    fn from(value: S) -> Self {
        Self::single_span(value.into(), T::default())
    }
}

impl<'a, T> SpannedStr<'a, T>
where
    T: 'a,
{
    /// Creates a new `SpannedStr` from the given references.
    pub fn new(source: &'a str, spans: &'a [IndexedSpan<T>]) -> Self {
        SpannedStr { source, spans }
    }

    /// Gives access to the parsed styled spans.
    #[cfg_attr(feature = "cargo-clippy", allow(needless_lifetimes))]
    pub fn spans<'b>(&self) -> Vec<Span<'a, T>> {
        self.spans
            .iter()
            .map(|span| span.resolve(self.source))
            .collect()
    }

    /// Returns a reference to the indexed spans.
    pub fn spans_raw(&self) -> &'a [IndexedSpan<T>] {
        self.spans
    }

    /// Returns a reference to the source (non-parsed) string.
    pub fn source(&self) -> &'a str {
        self.source
    }

    /// Returns `true` if `self` is empty.
    ///
    /// Can be caused by an empty source, or no span.
    pub fn is_empty(&self) -> bool {
        self.source.is_empty() || self.spans.is_empty()
    }
}

impl<'a, T> Clone for SpannedStr<'a, T> {
    fn clone(&self) -> Self {
        SpannedStr {
            source: self.source,
            spans: self.spans,
        }
    }
}

impl SpannedString<()> {
    /// Returns a simple spanned string without any attribute.
    pub fn plain<S>(content: S) -> Self
    where
        S: Into<String>,
    {
        Self::single_span(content, ())
    }
}

impl<T> SpannedString<T> {
    /// Returns an empty `SpannedString`.
    pub fn new() -> Self {
        Self::with_spans(String::new(), Vec::new())
    }

    /// Creates a new `SpannedString` manually.
    ///
    /// It is not recommended to use this directly.
    /// Instead, look for methods like `Markdown::parse`.
    pub fn with_spans<S>(source: S, spans: Vec<IndexedSpan<T>>) -> Self
    where
        S: Into<String>,
    {
        let source = source.into();

        // Make sure the spans are within bounds.
        // This should disapear when compiled in release mode.
        for span in &spans {
            if let IndexedCow::Borrowed { end, .. } = span.content {
                assert!(end <= source.len());
            }
        }

        SpannedString { source, spans }
    }

    /// Returns a new SpannedString with a single span.
    pub fn single_span<S>(source: S, attr: T) -> Self
    where
        S: Into<String>,
    {
        let source = source.into();

        let spans = vec![
            IndexedSpan {
                content: IndexedCow::Borrowed {
                    start: 0,
                    end: source.len(),
                },
                attr,
            },
        ];

        Self::with_spans(source, spans)
    }

    /// Appends the given `StyledString` to `self`.
    pub fn append<S>(&mut self, other: S)
    where
        S: Into<Self>,
    {
        let other = other.into();
        self.append_raw(&other.source, other.spans);
    }

    /// Appends `content` and its corresponding spans to the end.
    ///
    /// It is not recommended to use this directly;
    /// instead, look at the `append` method.
    pub fn append_raw(&mut self, source: &str, spans: Vec<IndexedSpan<T>>) {
        let offset = self.source.len();
        let mut spans = spans;

        for span in &mut spans {
            span.content.offset(offset);
        }

        self.source.push_str(source);
        self.spans.append(&mut spans);
    }

    /// Gives access to the parsed styled spans.
    #[cfg_attr(feature = "cargo-clippy", allow(needless_lifetimes))]
    pub fn spans<'a>(&'a self) -> Vec<Span<'a, T>> {
        self.spans
            .iter()
            .map(|span| span.resolve(&self.source))
            .collect()
    }

    /// Returns a reference to the indexed spans.
    pub fn spans_raw(&self) -> &[IndexedSpan<T>] {
        &self.spans
    }

    /// Returns a reference to the source string.
    ///
    /// This is the non-parsed string.
    pub fn source(&self) -> &str {
        &self.source
    }

    /// Returns `true` if self is empty.
    pub fn is_empty(&self) -> bool {
        self.source.is_empty() || self.spans.is_empty()
    }

    /// Returns a `SpannedStr` referencing `self`.
    pub fn as_spanned_str<'a>(&'a self) -> SpannedStr<'a, T> {
        SpannedStr::new(&self.source, &self.spans)
    }
}

/// An indexed span with an associated attribute.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IndexedSpan<T> {
    /// Content of the span.
    pub content: IndexedCow,

    /// Attribute applied to the span.
    pub attr: T,
}

/// A resolved span borrowing its source string.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Span<'a, T: 'a> {
    /// Content of this span.
    pub content: &'a str,

    /// Attribute associated to this span.
    pub attr: &'a T,
}

impl<T> IndexedSpan<T> {
    /// Resolve the span to a string slice and an attribute.
    pub fn resolve<'a>(&'a self, source: &'a str) -> Span<'a, T>
    where
        T: 'a,
    {
        Span {
            content: self.content.resolve(source),
            attr: &self.attr,
        }
    }

    /// Returns `true` if `self` is an empty span.
    pub fn is_empty(&self) -> bool {
        self.content.is_empty()
    }

    /// Returns a single span around the entire text.
    pub fn simple(content: &str, attr: T) -> Self {
        IndexedSpan {
            content: IndexedCow::Borrowed {
                start: 0,
                end: content.len(),
            },
            attr,
        }
    }
}

/// A span of text that can be either owned, or indexed in another String.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum IndexedCow {
    /// Indexes content in a separate string.
    Borrowed {
        /// Byte offset of the beginning of the span (inclusive)
        start: usize,

        /// Byte offset of the end of the span (exclusive)
        end: usize,
    },

    /// Owns its content.
    Owned(String),
}

impl IndexedCow {
    /// Resolve the span to a string slice.
    pub fn resolve<'a>(&'a self, source: &'a str) -> &'a str {
        match *self {
            IndexedCow::Borrowed { start, end } => &source[start..end],
            IndexedCow::Owned(ref content) => content,
        }
    }

    /// Returns an indexed view of the given item.
    ///
    /// **Note**: it is assumed `cow`, if borrowed, is a substring of `source`.
    pub fn from_cow(cow: Cow<str>, source: &str) -> Self {
        match cow {
            Cow::Owned(value) => IndexedCow::Owned(value),
            Cow::Borrowed(value) => {
                let source_pos = source.as_ptr() as usize;
                let value_pos = value.as_ptr() as usize;

                // Make sure `value` is indeed a substring of `source`
                assert!(value_pos >= source_pos);
                assert!(value_pos + value.len() <= source_pos + source.len());
                let start = value_pos - source_pos;
                let end = start + value.len();

                IndexedCow::Borrowed { start, end }
            }
        }
    }

    /// Returns `ŧrue` if this represents an empty span.
    pub fn is_empty(&self) -> bool {
        match *self {
            IndexedCow::Borrowed { start, end } => start == end,
            IndexedCow::Owned(ref content) => content.is_empty(),
        }
    }

    /// If `self` is borrowed, offset its indices by the given value.
    ///
    /// Useful to update spans when concatenating sources.
    pub fn offset(&mut self, offset: usize) {
        if let IndexedCow::Borrowed {
            ref mut start,
            ref mut end,
        } = *self
        {
            *start += offset;
            *end += offset;
        }
    }
}
<commit_msg>Remove attribute type from SpannedText<commit_after>//! Work with spans of text.
//!
//! This module defines various structs describing a span of text from a
//! larger string.
use std::borrow::Cow;

/// A string with associated spans.
///
/// Each span has an associated attribute `T`.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SpannedString<T> {
    source: String,
    spans: Vec<IndexedSpan<T>>,
}

/// The immutable, borrowed equivalent of `SpannedString`.
#[derive(Debug, PartialEq, Eq)]
pub struct SpannedStr<'a, T>
where
    T: 'a,
{
    source: &'a str,
    spans: &'a [IndexedSpan<T>],
}

/// Describes an object that appears like a `SpannedStr`.
pub trait SpannedText {
    /// Type of span returned by `SpannedText::spans()`.
    type S: AsRef<IndexedCow>;

    /// Returns the source text.
    fn source(&self) -> &str;

    /// Returns the spans for this text.
    fn spans(&self) -> &[Self::S];

    /// Returns a `SpannedText` by reference.
    fn as_ref<'a>(&'a self) -> SpannedTextRef<'a, Self> {
        SpannedTextRef { r: self }
    }
}

/// A reference to another `SpannedText`.
pub struct SpannedTextRef<'a, C>
where
    C: 'a + SpannedText + ?Sized,
{
    r: &'a C,
}

impl<'a, T> SpannedText for &'a SpannedString<T> {
    type S = IndexedSpan<T>;

    fn source(&self) -> &str {
        &self.source
    }

    fn spans(&self) -> &[IndexedSpan<T>] {
        &self.spans
    }
}

impl<'a, C> SpannedText for SpannedTextRef<'a, C>
where
    C: 'a + SpannedText + ?Sized,
{
    type S = C::S;

    fn source(&self) -> &str {
        self.r.source()
    }

    fn spans(&self) -> &[C::S] {
        self.r.spans()
    }
}

impl<'a, T> SpannedText for SpannedStr<'a, T>
where
    T: 'a,
{
    type S = IndexedSpan<T>;

    fn source(&self) -> &str {
        self.source
    }

    fn spans(&self) -> &[IndexedSpan<T>] {
        self.spans
    }
}

impl<S, T> From<S> for SpannedString<T>
where
    S: Into<String>,
    T: Default,
{
    fn from(value: S) -> Self {
        Self::single_span(value.into(), T::default())
    }
}

impl<'a, T> SpannedStr<'a, T>
where
    T: 'a,
{
    /// Creates a new `SpannedStr` from the given references.
    pub fn new(source: &'a str, spans: &'a [IndexedSpan<T>]) -> Self {
        SpannedStr { source, spans }
    }

    /// Gives access to the parsed styled spans.
    #[cfg_attr(feature = "cargo-clippy", allow(needless_lifetimes))]
    pub fn spans<'b>(&self) -> Vec<Span<'a, T>> {
        self.spans
            .iter()
            .map(|span| span.resolve(self.source))
            .collect()
    }

    /// Returns a reference to the indexed spans.
    pub fn spans_raw(&self) -> &'a [IndexedSpan<T>] {
        self.spans
    }

    /// Returns a reference to the source (non-parsed) string.
    pub fn source(&self) -> &'a str {
        self.source
    }

    /// Returns `true` if `self` is empty.
    ///
    /// Can be caused by an empty source, or no span.
    pub fn is_empty(&self) -> bool {
        self.source.is_empty() || self.spans.is_empty()
    }
}

impl<'a, T> Clone for SpannedStr<'a, T> {
    fn clone(&self) -> Self {
        SpannedStr {
            source: self.source,
            spans: self.spans,
        }
    }
}

impl SpannedString<()> {
    /// Returns a simple spanned string without any attribute.
    pub fn plain<S>(content: S) -> Self
    where
        S: Into<String>,
    {
        Self::single_span(content, ())
    }
}

impl<T> SpannedString<T> {
    /// Returns an empty `SpannedString`.
    pub fn new() -> Self {
        Self::with_spans(String::new(), Vec::new())
    }

    /// Creates a new `SpannedString` manually.
    ///
    /// It is not recommended to use this directly.
    /// Instead, look for methods like `Markdown::parse`.
    pub fn with_spans<S>(source: S, spans: Vec<IndexedSpan<T>>) -> Self
    where
        S: Into<String>,
    {
        let source = source.into();

        // Make sure the spans are within bounds.
        // This should disapear when compiled in release mode.
        for span in &spans {
            if let IndexedCow::Borrowed { end, .. } = span.content {
                assert!(end <= source.len());
            }
        }

        SpannedString { source, spans }
    }

    /// Returns a new SpannedString with a single span.
    pub fn single_span<S>(source: S, attr: T) -> Self
    where
        S: Into<String>,
    {
        let source = source.into();

        let spans = vec![
            IndexedSpan {
                content: IndexedCow::Borrowed {
                    start: 0,
                    end: source.len(),
                },
                attr,
            },
        ];

        Self::with_spans(source, spans)
    }

    /// Appends the given `StyledString` to `self`.
    pub fn append<S>(&mut self, other: S)
    where
        S: Into<Self>,
    {
        let other = other.into();
        self.append_raw(&other.source, other.spans);
    }

    /// Appends `content` and its corresponding spans to the end.
    ///
    /// It is not recommended to use this directly;
    /// instead, look at the `append` method.
    pub fn append_raw(&mut self, source: &str, spans: Vec<IndexedSpan<T>>) {
        let offset = self.source.len();
        let mut spans = spans;

        for span in &mut spans {
            span.content.offset(offset);
        }

        self.source.push_str(source);
        self.spans.append(&mut spans);
    }

    /// Gives access to the parsed styled spans.
    #[cfg_attr(feature = "cargo-clippy", allow(needless_lifetimes))]
    pub fn spans<'a>(&'a self) -> Vec<Span<'a, T>> {
        self.spans
            .iter()
            .map(|span| span.resolve(&self.source))
            .collect()
    }

    /// Returns a reference to the indexed spans.
    pub fn spans_raw(&self) -> &[IndexedSpan<T>] {
        &self.spans
    }

    /// Returns a reference to the source string.
    ///
    /// This is the non-parsed string.
    pub fn source(&self) -> &str {
        &self.source
    }

    /// Returns `true` if self is empty.
    pub fn is_empty(&self) -> bool {
        self.source.is_empty() || self.spans.is_empty()
    }

    /// Returns a `SpannedStr` referencing `self`.
    pub fn as_spanned_str<'a>(&'a self) -> SpannedStr<'a, T> {
        SpannedStr::new(&self.source, &self.spans)
    }
}

/// An indexed span with an associated attribute.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IndexedSpan<T> {
    /// Content of the span.
    pub content: IndexedCow,

    /// Attribute applied to the span.
    pub attr: T,
}

impl<T> AsRef<IndexedCow> for IndexedSpan<T> {
    fn as_ref(&self) -> &IndexedCow {
        &self.content
    }
}

/// A resolved span borrowing its source string.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Span<'a, T: 'a> {
    /// Content of this span.
    pub content: &'a str,

    /// Attribute associated to this span.
    pub attr: &'a T,
}

impl<T> IndexedSpan<T> {
    /// Resolve the span to a string slice and an attribute.
    pub fn resolve<'a>(&'a self, source: &'a str) -> Span<'a, T>
    where
        T: 'a,
    {
        Span {
            content: self.content.resolve(source),
            attr: &self.attr,
        }
    }

    /// Returns `true` if `self` is an empty span.
    pub fn is_empty(&self) -> bool {
        self.content.is_empty()
    }

    /// Returns a single span around the entire text.
    pub fn simple(content: &str, attr: T) -> Self {
        IndexedSpan {
            content: IndexedCow::Borrowed {
                start: 0,
                end: content.len(),
            },
            attr,
        }
    }
}

/// A span of text that can be either owned, or indexed in another String.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum IndexedCow {
    /// Indexes content in a separate string.
    Borrowed {
        /// Byte offset of the beginning of the span (inclusive)
        start: usize,

        /// Byte offset of the end of the span (exclusive)
        end: usize,
    },

    /// Owns its content.
    Owned(String),
}

impl IndexedCow {
    /// Resolve the span to a string slice.
    pub fn resolve<'a>(&'a self, source: &'a str) -> &'a str {
        match *self {
            IndexedCow::Borrowed { start, end } => &source[start..end],
            IndexedCow::Owned(ref content) => content,
        }
    }

    /// Returns an indexed view of the given item.
    ///
    /// **Note**: it is assumed `cow`, if borrowed, is a substring of `source`.
    pub fn from_cow(cow: Cow<str>, source: &str) -> Self {
        match cow {
            Cow::Owned(value) => IndexedCow::Owned(value),
            Cow::Borrowed(value) => {
                let source_pos = source.as_ptr() as usize;
                let value_pos = value.as_ptr() as usize;

                // Make sure `value` is indeed a substring of `source`
                assert!(value_pos >= source_pos);
                assert!(value_pos + value.len() <= source_pos + source.len());
                let start = value_pos - source_pos;
                let end = start + value.len();

                IndexedCow::Borrowed { start, end }
            }
        }
    }

    /// Returns `ŧrue` if this represents an empty span.
    pub fn is_empty(&self) -> bool {
        match *self {
            IndexedCow::Borrowed { start, end } => start == end,
            IndexedCow::Owned(ref content) => content.is_empty(),
        }
    }

    /// If `self` is borrowed, offset its indices by the given value.
    ///
    /// Useful to update spans when concatenating sources.
    pub fn offset(&mut self, offset: usize) {
        if let IndexedCow::Borrowed {
            ref mut start,
            ref mut end,
        } = *self
        {
            *start += offset;
            *end += offset;
        }
    }
}
<|endoftext|>


<commit_before>
use std::old_io::File;
use std::old_io::{Reader, Writer, Seek, SeekSet, SeekEnd};
use std::iter::range_inclusive;
use std::old_path::BytesContainer;
use error::ZipError;
use maybe_utf8::MaybeUTF8;
use flate;
use crc32;
use format;
use fileinfo::{CompressionMethod, FileInfo};

pub struct ZipReader<R> {
    reader: R,
    end_record: format::EndOfCentralDirectoryRecord,
}

pub struct RawFiles<'a, R:'a> {
    zip_reader: &'a mut ZipReader<R>,
    current_entry: u16,
    current_offset: u64,
}

impl<'a, R: Reader+Seek> Iterator for RawFiles<'a, R> {
    type Item = Result<FileInfo, ZipError>;
    fn next(&mut self) -> Option<Result<FileInfo, ZipError>> {
        if self.current_entry < self.zip_reader.end_record.total_entry_count {
            match self.zip_reader.reader.seek(self.current_offset as i64, SeekSet) {
                Ok(()) => {}
                Err(err) => { return Some(Err(ZipError::IoError(err))); }
            }
            let h = match format::CentralDirectoryHeader::read(&mut self.zip_reader.reader) {
                Ok(h) => h,
                Err(err) => { return Some(Err(err)); }
            };
            let info = FileInfo::from_cdh(&h);
            self.current_entry += 1;
            self.current_offset += h.total_size() as u64;
            Some(Ok(info))
        } else {
            None
        }
    }
}

pub struct Files<'a, R:'a> {
    base: RawFiles<'a, R>,
}

impl<'a, R: Reader+Seek> Iterator for Files<'a, R> {
    type Item = FileInfo;
    fn next(&mut self) -> Option<FileInfo> { self.base.next().map(|i| i.ok().unwrap()) }
    fn size_hint(&self) -> (usize, Option<usize>) { self.base.size_hint() }
}

pub struct FileNames<'a, R:'a> {
    base: RawFiles<'a, R>,
}

impl<'a, R: Reader+Seek> Iterator for FileNames<'a, R> {
    type Item = MaybeUTF8;
    fn next(&mut self) -> Option<MaybeUTF8> { self.base.next().map(|i| i.ok().unwrap().name) }
    fn size_hint(&self) -> (usize, Option<usize>) { self.base.size_hint() }
}

impl ZipReader<File> {
    pub fn open(path: &Path) -> Result<ZipReader<File>, ZipError> {
        ZipReader::new(try_io!(File::open(path)))
    }
}

impl<R:Reader+Seek> ZipReader<R> {
    pub fn new(reader: R) -> Result<ZipReader<R>, ZipError> {
        // find the End of Central Directory record, looking backwards from the end of the file
        let mut r = reader;
        try_io!(r.seek(0, SeekEnd));
        let file_size = try_io!(r.tell());
        let mut end_record_offset : Option<u64> = None;
        for i in range_inclusive(4, file_size) {
            let offset = file_size - i;
            try_io!(r.seek(offset as i64, SeekSet));

            let sig = try_io!(r.read_le_u32());

            // TODO: check for false positives here
            if sig == format::EOCDR_SIGNATURE {
                end_record_offset = Some(offset);
                break;
            }

        }

        match end_record_offset {
            Some(offset) => {
                try_io!(r.seek(offset as i64, SeekSet));
                let e = try!(format::EndOfCentralDirectoryRecord::read(&mut r));
                Ok(ZipReader {reader: r, end_record: e})
            },
            None => Err(ZipError::NotAZipFile)
        }
    }

    pub fn files_raw<'a>(&'a mut self) -> RawFiles<'a, R> {
        let cdr_offset = self.end_record.central_directory_offset;
        RawFiles {
            zip_reader: self,
            current_entry: 0,
            current_offset: cdr_offset as u64
        }
    }

    pub fn files<'a>(&'a mut self) -> Files<'a, R> {
        Files { base: self.files_raw() }
    }

    pub fn file_names<'a>(&'a mut self) -> FileNames<'a, R> {
        FileNames { base: self.files_raw() }
    }

    pub fn info<T: BytesContainer>(&mut self, name: T) -> Result<FileInfo, ZipError> {
        for i in self.files() {
            if i.name == name.container_as_bytes() {
                return Ok(i);
            }
        }
        Err(ZipError::FileNotFoundInArchive)
    }

    pub fn read(&mut self, f: &FileInfo) -> Result<Vec<u8>, ZipError> {

        try_io!(self.reader.seek(f.local_file_header_offset as i64, SeekSet));
        let header = try!(format::LocalFileHeader::read(&mut self.reader));

        let file_pos = f.local_file_header_offset as i64 + header.total_size() as i64;
        let file_len = header.compressed_size as usize;
        let data = try!(self.extract_block(file_pos, file_len, header.compression_method));

        if  crc32::crc32(&data[]) == header.crc32 {
            Ok(data)
        } else {
            Err(ZipError::CrcError)
        }
    }

    fn extract_block(&mut self, pos: i64, len: usize, method: u16) -> Result<Vec<u8>, ZipError> {
        try_io!(self.reader.seek(pos, SeekSet));
        let compressed_data = try_io!(self.reader.read_exact(len));
        match CompressionMethod::from_u16(method) {
                CompressionMethod::Store   => Ok(compressed_data),
                CompressionMethod::Deflate => self.decompress(compressed_data),
                _ => panic!("Usupported CompressionMethod")
        }
    }

    fn decompress(&mut self, data: Vec<u8>) -> Result<Vec<u8>, ZipError> {
        match flate::inflate_bytes(&data[]){
            Some(ok) => Ok(ok.to_vec()),
            None => return Err(ZipError::DecompressionFailure),
        }
    }

    // when we make read return a Reader, we will be able to loop here and copy
    // blocks of a fixed size from Reader to Writer
    pub fn extract<T:Writer>(&mut self, f: &FileInfo, writer: &mut T) -> Result<(), ZipError> {
        match self.read(f) {
            Ok(bytes) => { try_io!(writer.write_all(&bytes[])); Ok(()) },
            Err(x) => Err(x)
        }
    }

}

<commit_msg>refactoring<commit_after>
use std::old_io::File;
use std::old_io::{Reader, Writer, Seek, SeekSet, SeekEnd};
use std::iter::range_inclusive;
use std::old_path::BytesContainer;
use error::{ZipResult,ZipError};
use format::LocalFileHeader;
use maybe_utf8::MaybeUTF8;
use flate;
use crc32;
use format;
use fileinfo::{CompressionMethod, FileInfo};

pub struct ZipReader<R> {
    reader: R,
    end_record: format::EndOfCentralDirectoryRecord,
}

pub struct RawFiles<'a, R:'a> {
    zip_reader: &'a mut ZipReader<R>,
    current_entry: u16,
    current_offset: u64,
}

impl<'a, R: Reader+Seek> Iterator for RawFiles<'a, R> {
    type Item = Result<FileInfo, ZipError>;
    fn next(&mut self) -> Option<Result<FileInfo, ZipError>> {
        if self.current_entry < self.zip_reader.end_record.total_entry_count {
            match self.zip_reader.reader.seek(self.current_offset as i64, SeekSet) {
                Ok(()) => {}
                Err(err) => { return Some(Err(ZipError::IoError(err))); }
            }
            let h = match format::CentralDirectoryHeader::read(&mut self.zip_reader.reader) {
                Ok(h) => h,
                Err(err) => { return Some(Err(err)); }
            };
            let info = FileInfo::from_cdh(&h);
            self.current_entry += 1;
            self.current_offset += h.total_size() as u64;
            Some(Ok(info))
        } else {
            None
        }
    }
}

pub struct Files<'a, R:'a> {
    base: RawFiles<'a, R>,
}

impl<'a, R: Reader+Seek> Iterator for Files<'a, R> {
    type Item = FileInfo;
    fn next(&mut self) -> Option<FileInfo> { self.base.next().map(|i| i.ok().unwrap()) }
    fn size_hint(&self) -> (usize, Option<usize>) { self.base.size_hint() }
}

pub struct FileNames<'a, R:'a> {
    base: RawFiles<'a, R>,
}

impl<'a, R: Reader+Seek> Iterator for FileNames<'a, R> {
    type Item = MaybeUTF8;
    fn next(&mut self) -> Option<MaybeUTF8> { self.base.next().map(|i| i.ok().unwrap().name) }
    fn size_hint(&self) -> (usize, Option<usize>) { self.base.size_hint() }
}

impl ZipReader<File> {
    pub fn open(path: &Path) -> Result<ZipReader<File>, ZipError> {
        ZipReader::new(try_io!(File::open(path)))
    }
}

impl<R:Reader+Seek> ZipReader<R> {
    pub fn new(reader: R) -> Result<ZipReader<R>, ZipError> {
        // find the End of Central Directory record, looking backwards from the end of the file
        let mut r = reader;
        try_io!(r.seek(0, SeekEnd));
        let file_size = try_io!(r.tell());
        let mut end_record_offset : Option<u64> = None;
        for i in range_inclusive(4, file_size) {
            let offset = file_size - i;
            try_io!(r.seek(offset as i64, SeekSet));

            let sig = try_io!(r.read_le_u32());

            // TODO: check for false positives here
            if sig == format::EOCDR_SIGNATURE {
                end_record_offset = Some(offset);
                break;
            }

        }

        match end_record_offset {
            Some(offset) => {
                try_io!(r.seek(offset as i64, SeekSet));
                let e = try!(format::EndOfCentralDirectoryRecord::read(&mut r));
                Ok(ZipReader {reader: r, end_record: e})
            },
            None => Err(ZipError::NotAZipFile)
        }
    }

    pub fn files_raw<'a>(&'a mut self) -> RawFiles<'a, R> {
        let cdr_offset = self.end_record.central_directory_offset;
        RawFiles {
            zip_reader: self,
            current_entry: 0,
            current_offset: cdr_offset as u64
        }
    }

    pub fn files<'a>(&'a mut self) -> Files<'a, R> {
        Files { base: self.files_raw() }
    }

    pub fn file_names<'a>(&'a mut self) -> FileNames<'a, R> {
        FileNames { base: self.files_raw() }
    }

    pub fn info<T: BytesContainer>(&mut self, name: T) -> Result<FileInfo, ZipError> {
        for i in self.files() {
            if i.name == name.container_as_bytes() {
                return Ok(i);
            }
        }
        Err(ZipError::FileNotFoundInArchive)
    }

    fn read_header(&mut self, f: &FileInfo) -> ZipResult<LocalFileHeader> {
        try_io!(self.reader.seek(f.local_file_header_offset as i64, SeekSet));
        format::LocalFileHeader::read(&mut self.reader)
    }

    pub fn read(&mut self, f: &FileInfo) -> Result<Vec<u8>, ZipError> {
        let header = try!(self.read_header(f));
        header.print();

        let file_pos = f.local_file_header_offset as i64 + header.total_size() as i64;
        let file_len = header.compressed_size as usize;
        self.extract_block(file_pos, file_len, header.compression_method, header.crc32)
    }

    fn extract_block(&mut self, pos: i64, len: usize, method: u16, crc32: u32) -> Result<Vec<u8>, ZipError> {
        try_io!(self.reader.seek(pos, SeekSet));
        let compressed = try_io!(self.reader.read_exact(len));
        match CompressionMethod::from_u16(method) {
                CompressionMethod::Store   => Ok(compressed),
                CompressionMethod::Deflate => self.decompress(compressed, crc32),
                _ => panic!("Usupported CompressionMethod")
        }
    }

    fn decompress(&mut self, data: Vec<u8>, crc32: u32) -> Result<Vec<u8>, ZipError> {
        match flate::inflate_bytes(&data[]){
            Some(ok) => if crc32::crc32(&ok) == crc32 { Ok(ok.to_vec()) } else { Err(ZipError::CrcError) },
            None => return Err(ZipError::DecompressionFailure),
        }
    }

    // when we make read return a Reader, we will be able to loop here and copy
    // blocks of a fixed size from Reader to Writer
    pub fn extract<T:Writer>(&mut self, f: &FileInfo, writer: &mut T) -> Result<(), ZipError> {

        match self.read(f) {
            Ok(bytes) => { try_io!(writer.write_all(&bytes[])); Ok(()) },
            Err(x) => Err(x)
        }
    }

}

<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

//! Utilities for reading, writing, and transforming data for the LSP service
// We use two crates, lsp_types and lsp_server, for interacting with LSP. This module re-exports
// types from both so that we have a central source-of-truth for all LSP-related utilities.
use crate::lsp_process_error::LSPProcessResult;
use common::Location;
use crossbeam::{crossbeam_channel::Sender, SendError};
pub use lsp_server::{Connection, Message};
pub use lsp_server::{
    Notification as ServerNotification, ProtocolError, Request as ServerRequest,
    RequestId as ServerRequestId, Response as ServerResponse,
};
pub use lsp_types::{notification::*, request::*, *};
use serde::{Deserialize, Serialize};
use std::fs;
use std::path::PathBuf;

#[derive(Debug, Clone)]
pub enum LSPBridgeMessage {
    CompletionRequest {
        request_id: ServerRequestId,
        params: CompletionParams,
    },
    HoverRequest {
        request_id: ServerRequestId,
        text_document_position: TextDocumentPositionParams,
    },
    GotoDefinitionRequest {
        request_id: ServerRequestId,
        text_document_position: TextDocumentPositionParams,
    },
    ReferencesRequest {
        request_id: ServerRequestId,
        reference_params: ReferenceParams,
    },
    DidOpenTextDocument(DidOpenTextDocumentParams),
    DidChangeTextDocument(DidChangeTextDocumentParams),
    DidCloseTextDocument(DidCloseTextDocumentParams),
}

impl LSPBridgeMessage {
    pub(crate) fn get_message_type_for_logging(&self) -> &str {
        match self {
            LSPBridgeMessage::GotoDefinitionRequest { .. } => "GotoDefinitionRequest",
            LSPBridgeMessage::CompletionRequest { .. } => "CompletionRequest",
            LSPBridgeMessage::HoverRequest { .. } => "HoverRequest",
            LSPBridgeMessage::DidOpenTextDocument(_) => "DidOpenTextDocument",
            LSPBridgeMessage::DidChangeTextDocument(_) => "DidChangeTextDocument",
            LSPBridgeMessage::DidCloseTextDocument(_) => "DidCloseTextDocument",
        }
    }
}

/// Converts a Location to a Url pointing to the canonical path based on the root_dir provided.
/// Returns None if we are unable to do the conversion
pub fn url_from_location(location: Location, root_dir: &PathBuf) -> Option<Url> {
    let file_path = location.source_location().path();
    let canonical_path = fs::canonicalize(root_dir.join(file_path)).ok()?;
    Url::from_file_path(canonical_path).ok()
}

#[derive(Debug)]
pub enum ShowStatus {}

#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ShowStatusParams {
    #[serde(rename = "type")]
    pub typ: MessageType,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub progress: Option<Progress>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub uri: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub message: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub short_message: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub actions: Option<Vec<MessageActionItem>>,
}

#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
pub struct Progress {
    numerator: f32,
    denominator: Option<f32>,
}

impl Request for ShowStatus {
    type Params = ShowStatusParams;
    type Result = ();
    const METHOD: &'static str = "window/showStatus";
}

pub fn set_ready_status(sender: &Sender<Message>) {
    update_status(
        Some("Relay: ready".into()),
        Some("Relay: ready".into()),
        MessageType::Info,
        sender,
    );
}

pub fn set_initializing_status(sender: &Sender<Message>) {
    update_status(
        Some("Relay: initializing".into()),
        Some("Relay: initializing".into()),
        MessageType::Warning,
        sender,
    );
}

pub fn set_running_status(sender: &Sender<Message>) {
    update_status(
        Some("Relay: compiling".into()),
        Some("Relay: compiling".into()),
        MessageType::Warning,
        sender,
    );
}

fn update_status(
    short_message: Option<String>,
    message: Option<String>,
    typ: MessageType,
    sender: &Sender<Message>,
) {
    let request = ServerRequest::new(
        ShowStatus::METHOD.to_string().into(),
        ShowStatus::METHOD.into(),
        ShowStatusParams {
            typ,
            progress: None,
            uri: None,
            message,
            short_message,
            actions: None,
        },
    );
    sender.send(Message::Request(request)).unwrap();
}

/// Show a notification in the client
#[allow(dead_code)]
pub fn show_info_message(
    sender: &Sender<Message>,
    message: impl Into<String>,
) -> Result<(), SendError<Message>> {
    let notif = ServerNotification::new(
        ShowMessage::METHOD.into(),
        ShowMessageParams {
            typ: MessageType::Info,
            message: message.into(),
        },
    );

    sender.send(Message::Notification(notif))
}

/// Publish diagnostics to the client
pub fn publish_diagnostic(
    diagnostic_params: PublishDiagnosticsParams,
    sender: &Sender<Message>,
) -> LSPProcessResult<()> {
    let notif = ServerNotification::new(PublishDiagnostics::METHOD.into(), diagnostic_params);
    sender
        .send(Message::Notification(notif))
        .unwrap_or_else(|_| {
            // TODO(brandondail) log here
        });
    Ok(())
}
<commit_msg>Add ReferencesRequest to match statement<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

//! Utilities for reading, writing, and transforming data for the LSP service
// We use two crates, lsp_types and lsp_server, for interacting with LSP. This module re-exports
// types from both so that we have a central source-of-truth for all LSP-related utilities.
use crate::lsp_process_error::LSPProcessResult;
use common::Location;
use crossbeam::{crossbeam_channel::Sender, SendError};
pub use lsp_server::{Connection, Message};
pub use lsp_server::{
    Notification as ServerNotification, ProtocolError, Request as ServerRequest,
    RequestId as ServerRequestId, Response as ServerResponse,
};
pub use lsp_types::{notification::*, request::*, *};
use serde::{Deserialize, Serialize};
use std::fs;
use std::path::PathBuf;

#[derive(Debug, Clone)]
pub enum LSPBridgeMessage {
    CompletionRequest {
        request_id: ServerRequestId,
        params: CompletionParams,
    },
    HoverRequest {
        request_id: ServerRequestId,
        text_document_position: TextDocumentPositionParams,
    },
    GotoDefinitionRequest {
        request_id: ServerRequestId,
        text_document_position: TextDocumentPositionParams,
    },
    ReferencesRequest {
        request_id: ServerRequestId,
        reference_params: ReferenceParams,
    },
    DidOpenTextDocument(DidOpenTextDocumentParams),
    DidChangeTextDocument(DidChangeTextDocumentParams),
    DidCloseTextDocument(DidCloseTextDocumentParams),
}

impl LSPBridgeMessage {
    pub(crate) fn get_message_type_for_logging(&self) -> &str {
        match self {
            LSPBridgeMessage::GotoDefinitionRequest { .. } => "GotoDefinitionRequest",
            LSPBridgeMessage::CompletionRequest { .. } => "CompletionRequest",
            LSPBridgeMessage::HoverRequest { .. } => "HoverRequest",
            LSPBridgeMessage::ReferencesRequest { .. } => "ReferencesRequest",
            LSPBridgeMessage::DidOpenTextDocument(_) => "DidOpenTextDocument",
            LSPBridgeMessage::DidChangeTextDocument(_) => "DidChangeTextDocument",
            LSPBridgeMessage::DidCloseTextDocument(_) => "DidCloseTextDocument",
        }
    }
}

/// Converts a Location to a Url pointing to the canonical path based on the root_dir provided.
/// Returns None if we are unable to do the conversion
pub fn url_from_location(location: Location, root_dir: &PathBuf) -> Option<Url> {
    let file_path = location.source_location().path();
    let canonical_path = fs::canonicalize(root_dir.join(file_path)).ok()?;
    Url::from_file_path(canonical_path).ok()
}

#[derive(Debug)]
pub enum ShowStatus {}

#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ShowStatusParams {
    #[serde(rename = "type")]
    pub typ: MessageType,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub progress: Option<Progress>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub uri: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub message: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub short_message: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub actions: Option<Vec<MessageActionItem>>,
}

#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
pub struct Progress {
    numerator: f32,
    denominator: Option<f32>,
}

impl Request for ShowStatus {
    type Params = ShowStatusParams;
    type Result = ();
    const METHOD: &'static str = "window/showStatus";
}

pub fn set_ready_status(sender: &Sender<Message>) {
    update_status(
        Some("Relay: ready".into()),
        Some("Relay: ready".into()),
        MessageType::Info,
        sender,
    );
}

pub fn set_initializing_status(sender: &Sender<Message>) {
    update_status(
        Some("Relay: initializing".into()),
        Some("Relay: initializing".into()),
        MessageType::Warning,
        sender,
    );
}

pub fn set_running_status(sender: &Sender<Message>) {
    update_status(
        Some("Relay: compiling".into()),
        Some("Relay: compiling".into()),
        MessageType::Warning,
        sender,
    );
}

fn update_status(
    short_message: Option<String>,
    message: Option<String>,
    typ: MessageType,
    sender: &Sender<Message>,
) {
    let request = ServerRequest::new(
        ShowStatus::METHOD.to_string().into(),
        ShowStatus::METHOD.into(),
        ShowStatusParams {
            typ,
            progress: None,
            uri: None,
            message,
            short_message,
            actions: None,
        },
    );
    sender.send(Message::Request(request)).unwrap();
}

/// Show a notification in the client
#[allow(dead_code)]
pub fn show_info_message(
    sender: &Sender<Message>,
    message: impl Into<String>,
) -> Result<(), SendError<Message>> {
    let notif = ServerNotification::new(
        ShowMessage::METHOD.into(),
        ShowMessageParams {
            typ: MessageType::Info,
            message: message.into(),
        },
    );

    sender.send(Message::Notification(notif))
}

/// Publish diagnostics to the client
pub fn publish_diagnostic(
    diagnostic_params: PublishDiagnosticsParams,
    sender: &Sender<Message>,
) -> LSPProcessResult<()> {
    let notif = ServerNotification::new(PublishDiagnostics::METHOD.into(), diagnostic_params);
    sender
        .send(Message::Notification(notif))
        .unwrap_or_else(|_| {
            // TODO(brandondail) log here
        });
    Ok(())
}
<|endoftext|>


<commit_before>use crate::os::unix::prelude::*;

use crate::ffi::{OsString, OsStr, CString, CStr};
use crate::fmt;
use crate::io;
use crate::ptr;
use crate::sys::fd::FileDesc;
use crate::sys::fs::{File, OpenOptions};
use crate::sys::pipe::{self, AnonPipe};
use crate::sys_common::process::{CommandEnv, DefaultEnvKey};
use crate::collections::BTreeMap;

use libc::{c_int, gid_t, uid_t, c_char, EXIT_SUCCESS, EXIT_FAILURE};

////////////////////////////////////////////////////////////////////////////////
// Command
////////////////////////////////////////////////////////////////////////////////

pub struct Command {
    // Currently we try hard to ensure that the call to `.exec()` doesn't
    // actually allocate any memory. While many platforms try to ensure that
    // memory allocation works after a fork in a multithreaded process, it's
    // been observed to be buggy and somewhat unreliable, so we do our best to
    // just not do it at all!
    //
    // Along those lines, the `argv` and `envp` raw pointers here are exactly
    // what's gonna get passed to `execvp`. The `argv` array starts with the
    // `program` and ends with a NULL, and the `envp` pointer, if present, is
    // also null-terminated.
    //
    // Right now we don't support removing arguments, so there's no much fancy
    // support there, but we support adding and removing environment variables,
    // so a side table is used to track where in the `envp` array each key is
    // located. Whenever we add a key we update it in place if it's already
    // present, and whenever we remove a key we update the locations of all
    // other keys.
    program: CString,
    args: Vec<CString>,
    argv: Argv,
    env: CommandEnv<DefaultEnvKey>,

    cwd: Option<CString>,
    uid: Option<uid_t>,
    gid: Option<gid_t>,
    saw_nul: bool,
    closures: Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>>,
    stdin: Option<Stdio>,
    stdout: Option<Stdio>,
    stderr: Option<Stdio>,
}

// Create a new type for argv, so that we can make it `Send`
struct Argv(Vec<*const c_char>);

// It is safe to make Argv Send, because it contains pointers to memory owned by `Command.args`
unsafe impl Send for Argv {}

// passed back to std::process with the pipes connected to the child, if any
// were requested
pub struct StdioPipes {
    pub stdin: Option<AnonPipe>,
    pub stdout: Option<AnonPipe>,
    pub stderr: Option<AnonPipe>,
}

// passed to do_exec() with configuration of what the child stdio should look
// like
pub struct ChildPipes {
    pub stdin: ChildStdio,
    pub stdout: ChildStdio,
    pub stderr: ChildStdio,
}

pub enum ChildStdio {
    Inherit,
    Explicit(c_int),
    Owned(FileDesc),
}

pub enum Stdio {
    Inherit,
    Null,
    MakePipe,
    Fd(FileDesc),
}

impl Command {
    pub fn new(program: &OsStr) -> Command {
        let mut saw_nul = false;
        let program = os2c(program, &mut saw_nul);
        Command {
            argv: Argv(vec![program.as_ptr(), ptr::null()]),
            program,
            args: Vec::new(),
            env: Default::default(),
            cwd: None,
            uid: None,
            gid: None,
            saw_nul,
            closures: Vec::new(),
            stdin: None,
            stdout: None,
            stderr: None,
        }
    }

    pub fn arg(&mut self, arg: &OsStr) {
        // Overwrite the trailing NULL pointer in `argv` and then add a new null
        // pointer.
        let arg = os2c(arg, &mut self.saw_nul);
        self.argv.0[self.args.len() + 1] = arg.as_ptr();
        self.argv.0.push(ptr::null());

        // Also make sure we keep track of the owned value to schedule a
        // destructor for this memory.
        self.args.push(arg);
    }

    pub fn cwd(&mut self, dir: &OsStr) {
        self.cwd = Some(os2c(dir, &mut self.saw_nul));
    }
    pub fn uid(&mut self, id: uid_t) {
        self.uid = Some(id);
    }
    pub fn gid(&mut self, id: gid_t) {
        self.gid = Some(id);
    }

    pub fn saw_nul(&self) -> bool {
        self.saw_nul
    }
    pub fn get_argv(&self) -> &Vec<*const c_char> {
        &self.argv.0
    }

    #[allow(dead_code)]
    pub fn get_cwd(&self) -> &Option<CString> {
        &self.cwd
    }
    #[allow(dead_code)]
    pub fn get_uid(&self) -> Option<uid_t> {
        self.uid
    }
    #[allow(dead_code)]
    pub fn get_gid(&self) -> Option<gid_t> {
        self.gid
    }

    pub fn get_closures(&mut self) -> &mut Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>> {
        &mut self.closures
    }

    pub unsafe fn pre_exec(
        &mut self,
        _f: Box<dyn FnMut() -> io::Result<()> + Send + Sync>,
    ) {
        // Fork() is not supported in vxWorks so no way to run the closure in the new procecss.
        unimplemented!();;
    }

    pub fn stdin(&mut self, stdin: Stdio) {
        self.stdin = Some(stdin);
    }

    pub fn stdout(&mut self, stdout: Stdio) {
        self.stdout = Some(stdout);
    }

    pub fn stderr(&mut self, stderr: Stdio) {
        self.stderr = Some(stderr);
    }

    pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> {
        &mut self.env
    }

    pub fn capture_env(&mut self) -> Option<CStringArray> {
        let maybe_env = self.env.capture_if_changed();
        maybe_env.map(|env| construct_envp(env, &mut self.saw_nul))
    }
    #[allow(dead_code)]
    pub fn env_saw_path(&self) -> bool {
        self.env.have_changed_path()
    }

    pub fn setup_io(&self, default: Stdio, needs_stdin: bool)
                -> io::Result<(StdioPipes, ChildPipes)> {
        let null = Stdio::Null;
        let default_stdin = if needs_stdin {&default} else {&null};
        let stdin = self.stdin.as_ref().unwrap_or(default_stdin);
        let stdout = self.stdout.as_ref().unwrap_or(&default);
        let stderr = self.stderr.as_ref().unwrap_or(&default);
        let (their_stdin, our_stdin) = stdin.to_child_stdio(true)?;
        let (their_stdout, our_stdout) = stdout.to_child_stdio(false)?;
        let (their_stderr, our_stderr) = stderr.to_child_stdio(false)?;
        let ours = StdioPipes {
            stdin: our_stdin,
            stdout: our_stdout,
            stderr: our_stderr,
        };
        let theirs = ChildPipes {
            stdin: their_stdin,
            stdout: their_stdout,
            stderr: their_stderr,
        };
        Ok((ours, theirs))
    }
}

fn os2c(s: &OsStr, saw_nul: &mut bool) -> CString {
    CString::new(s.as_bytes()).unwrap_or_else(|_e| {
        *saw_nul = true;
        CString::new("<string-with-nul>").unwrap()
    })
}

// Helper type to manage ownership of the strings within a C-style array.
pub struct CStringArray {
    items: Vec<CString>,
    ptrs: Vec<*const c_char>
}

impl CStringArray {
    pub fn with_capacity(capacity: usize) -> Self {
        let mut result = CStringArray {
            items: Vec::with_capacity(capacity),
            ptrs: Vec::with_capacity(capacity+1)
        };
        result.ptrs.push(ptr::null());
        result
    }
    pub fn push(&mut self, item: CString) {
        let l = self.ptrs.len();
        self.ptrs[l-1] = item.as_ptr();
        self.ptrs.push(ptr::null());
        self.items.push(item);
    }
    pub fn as_ptr(&self) -> *const *const c_char {
        self.ptrs.as_ptr()
    }
}

fn construct_envp(env: BTreeMap<DefaultEnvKey, OsString>, saw_nul: &mut bool) -> CStringArray {
    let mut result = CStringArray::with_capacity(env.len());
    for (k, v) in env {
        let mut k: OsString = k.into();

        // Reserve additional space for '=' and null terminator
        k.reserve_exact(v.len() + 2);
        k.push("=");
        k.push(&v);

        // Add the new entry into the array
        if let Ok(item) = CString::new(k.into_vec()) {
            result.push(item);
        } else {
            *saw_nul = true;
        }
    }

    result
}

impl Stdio {
    pub fn to_child_stdio(&self, readable: bool)
                      -> io::Result<(ChildStdio, Option<AnonPipe>)> {
        match *self {
            Stdio::Inherit => {
                Ok((ChildStdio::Inherit, None))
            },

            // Make sure that the source descriptors are not an stdio
            // descriptor, otherwise the order which we set the child's
            // descriptors may blow away a descriptor which we are hoping to
            // save. For example, suppose we want the child's stderr to be the
            // parent's stdout, and the child's stdout to be the parent's
            // stderr. No matter which we dup first, the second will get
            // overwritten prematurely.
            Stdio::Fd(ref fd) => {
                if fd.raw() >= 0 && fd.raw() <= libc::STDERR_FILENO {
                    Ok((ChildStdio::Owned(fd.duplicate()?), None))
                } else {
                    Ok((ChildStdio::Explicit(fd.raw()), None))
                }
            }

            Stdio::MakePipe => {
                let (reader, writer) = pipe::anon_pipe()?;
                let (ours, theirs) = if readable {
                    (writer, reader)
                } else {
                    (reader, writer)
                };
                Ok((ChildStdio::Owned(theirs.into_fd()), Some(ours)))
            }

            Stdio::Null => {
                let mut opts = OpenOptions::new();
                opts.read(readable);
                opts.write(!readable);
                let path = unsafe {
                    CStr::from_ptr("/null\0".as_ptr() as *const _)
                };
                let fd = File::open_c(&path, &opts)?;
                Ok((ChildStdio::Owned(fd.into_fd()), None))
            }
        }
    }
}

impl From<AnonPipe> for Stdio {
    fn from(pipe: AnonPipe) -> Stdio {
        Stdio::Fd(pipe.into_fd())
    }
}

impl From<File> for Stdio {
    fn from(file: File) -> Stdio {
        Stdio::Fd(file.into_fd())
    }
}

impl ChildStdio {
    pub fn fd(&self) -> Option<c_int> {
        match *self {
            ChildStdio::Inherit => None,
            ChildStdio::Explicit(fd) => Some(fd),
            ChildStdio::Owned(ref fd) => Some(fd.raw()),
        }
    }
}

impl fmt::Debug for Command {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}", self.program)?;
        for arg in &self.args {
            write!(f, " {:?}", arg)?;
        }
        Ok(())
    }
}

/// Unix exit statuses
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct ExitStatus(c_int);

impl ExitStatus {
    pub fn new(status: c_int) -> ExitStatus {
        ExitStatus(status)
    }

    fn exited(&self) -> bool {
        /*unsafe*/ { libc::WIFEXITED(self.0) }
    }

    pub fn success(&self) -> bool {
        self.code() == Some(0)
    }

    pub fn code(&self) -> Option<i32> {
        if self.exited() {
            Some(/*unsafe*/ { libc::WEXITSTATUS(self.0) })
        } else {
            None
        }
    }

    pub fn signal(&self) -> Option<i32> {
        if !self.exited() {
            Some(/*unsafe*/ { libc::WTERMSIG(self.0) })
        } else {
            None
        }
    }
}

impl From<c_int> for ExitStatus {
    fn from(a: c_int) -> ExitStatus {
        ExitStatus(a)
    }
}

impl fmt::Display for ExitStatus {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if let Some(code) = self.code() {
            write!(f, "exit code: {}", code)
        } else {
            let signal = self.signal().unwrap();
            write!(f, "signal: {}", signal)
        }
    }
}

#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct ExitCode(u8);

impl ExitCode {
    pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _);
    pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _);

    #[inline]
    pub fn as_i32(&self) -> i32 {
        self.0 as i32
    }
}
<commit_msg>Fixed: error: unnecessary trailing semicolon<commit_after>use crate::os::unix::prelude::*;

use crate::ffi::{OsString, OsStr, CString, CStr};
use crate::fmt;
use crate::io;
use crate::ptr;
use crate::sys::fd::FileDesc;
use crate::sys::fs::{File, OpenOptions};
use crate::sys::pipe::{self, AnonPipe};
use crate::sys_common::process::{CommandEnv, DefaultEnvKey};
use crate::collections::BTreeMap;

use libc::{c_int, gid_t, uid_t, c_char, EXIT_SUCCESS, EXIT_FAILURE};

////////////////////////////////////////////////////////////////////////////////
// Command
////////////////////////////////////////////////////////////////////////////////

pub struct Command {
    // Currently we try hard to ensure that the call to `.exec()` doesn't
    // actually allocate any memory. While many platforms try to ensure that
    // memory allocation works after a fork in a multithreaded process, it's
    // been observed to be buggy and somewhat unreliable, so we do our best to
    // just not do it at all!
    //
    // Along those lines, the `argv` and `envp` raw pointers here are exactly
    // what's gonna get passed to `execvp`. The `argv` array starts with the
    // `program` and ends with a NULL, and the `envp` pointer, if present, is
    // also null-terminated.
    //
    // Right now we don't support removing arguments, so there's no much fancy
    // support there, but we support adding and removing environment variables,
    // so a side table is used to track where in the `envp` array each key is
    // located. Whenever we add a key we update it in place if it's already
    // present, and whenever we remove a key we update the locations of all
    // other keys.
    program: CString,
    args: Vec<CString>,
    argv: Argv,
    env: CommandEnv<DefaultEnvKey>,

    cwd: Option<CString>,
    uid: Option<uid_t>,
    gid: Option<gid_t>,
    saw_nul: bool,
    closures: Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>>,
    stdin: Option<Stdio>,
    stdout: Option<Stdio>,
    stderr: Option<Stdio>,
}

// Create a new type for argv, so that we can make it `Send`
struct Argv(Vec<*const c_char>);

// It is safe to make Argv Send, because it contains pointers to memory owned by `Command.args`
unsafe impl Send for Argv {}

// passed back to std::process with the pipes connected to the child, if any
// were requested
pub struct StdioPipes {
    pub stdin: Option<AnonPipe>,
    pub stdout: Option<AnonPipe>,
    pub stderr: Option<AnonPipe>,
}

// passed to do_exec() with configuration of what the child stdio should look
// like
pub struct ChildPipes {
    pub stdin: ChildStdio,
    pub stdout: ChildStdio,
    pub stderr: ChildStdio,
}

pub enum ChildStdio {
    Inherit,
    Explicit(c_int),
    Owned(FileDesc),
}

pub enum Stdio {
    Inherit,
    Null,
    MakePipe,
    Fd(FileDesc),
}

impl Command {
    pub fn new(program: &OsStr) -> Command {
        let mut saw_nul = false;
        let program = os2c(program, &mut saw_nul);
        Command {
            argv: Argv(vec![program.as_ptr(), ptr::null()]),
            program,
            args: Vec::new(),
            env: Default::default(),
            cwd: None,
            uid: None,
            gid: None,
            saw_nul,
            closures: Vec::new(),
            stdin: None,
            stdout: None,
            stderr: None,
        }
    }

    pub fn arg(&mut self, arg: &OsStr) {
        // Overwrite the trailing NULL pointer in `argv` and then add a new null
        // pointer.
        let arg = os2c(arg, &mut self.saw_nul);
        self.argv.0[self.args.len() + 1] = arg.as_ptr();
        self.argv.0.push(ptr::null());

        // Also make sure we keep track of the owned value to schedule a
        // destructor for this memory.
        self.args.push(arg);
    }

    pub fn cwd(&mut self, dir: &OsStr) {
        self.cwd = Some(os2c(dir, &mut self.saw_nul));
    }
    pub fn uid(&mut self, id: uid_t) {
        self.uid = Some(id);
    }
    pub fn gid(&mut self, id: gid_t) {
        self.gid = Some(id);
    }

    pub fn saw_nul(&self) -> bool {
        self.saw_nul
    }
    pub fn get_argv(&self) -> &Vec<*const c_char> {
        &self.argv.0
    }

    #[allow(dead_code)]
    pub fn get_cwd(&self) -> &Option<CString> {
        &self.cwd
    }
    #[allow(dead_code)]
    pub fn get_uid(&self) -> Option<uid_t> {
        self.uid
    }
    #[allow(dead_code)]
    pub fn get_gid(&self) -> Option<gid_t> {
        self.gid
    }

    pub fn get_closures(&mut self) -> &mut Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>> {
        &mut self.closures
    }

    pub unsafe fn pre_exec(
        &mut self,
        _f: Box<dyn FnMut() -> io::Result<()> + Send + Sync>,
    ) {
        // Fork() is not supported in vxWorks so no way to run the closure in the new procecss.
        unimplemented!();
    }

    pub fn stdin(&mut self, stdin: Stdio) {
        self.stdin = Some(stdin);
    }

    pub fn stdout(&mut self, stdout: Stdio) {
        self.stdout = Some(stdout);
    }

    pub fn stderr(&mut self, stderr: Stdio) {
        self.stderr = Some(stderr);
    }

    pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> {
        &mut self.env
    }

    pub fn capture_env(&mut self) -> Option<CStringArray> {
        let maybe_env = self.env.capture_if_changed();
        maybe_env.map(|env| construct_envp(env, &mut self.saw_nul))
    }
    #[allow(dead_code)]
    pub fn env_saw_path(&self) -> bool {
        self.env.have_changed_path()
    }

    pub fn setup_io(&self, default: Stdio, needs_stdin: bool)
                -> io::Result<(StdioPipes, ChildPipes)> {
        let null = Stdio::Null;
        let default_stdin = if needs_stdin {&default} else {&null};
        let stdin = self.stdin.as_ref().unwrap_or(default_stdin);
        let stdout = self.stdout.as_ref().unwrap_or(&default);
        let stderr = self.stderr.as_ref().unwrap_or(&default);
        let (their_stdin, our_stdin) = stdin.to_child_stdio(true)?;
        let (their_stdout, our_stdout) = stdout.to_child_stdio(false)?;
        let (their_stderr, our_stderr) = stderr.to_child_stdio(false)?;
        let ours = StdioPipes {
            stdin: our_stdin,
            stdout: our_stdout,
            stderr: our_stderr,
        };
        let theirs = ChildPipes {
            stdin: their_stdin,
            stdout: their_stdout,
            stderr: their_stderr,
        };
        Ok((ours, theirs))
    }
}

fn os2c(s: &OsStr, saw_nul: &mut bool) -> CString {
    CString::new(s.as_bytes()).unwrap_or_else(|_e| {
        *saw_nul = true;
        CString::new("<string-with-nul>").unwrap()
    })
}

// Helper type to manage ownership of the strings within a C-style array.
pub struct CStringArray {
    items: Vec<CString>,
    ptrs: Vec<*const c_char>
}

impl CStringArray {
    pub fn with_capacity(capacity: usize) -> Self {
        let mut result = CStringArray {
            items: Vec::with_capacity(capacity),
            ptrs: Vec::with_capacity(capacity+1)
        };
        result.ptrs.push(ptr::null());
        result
    }
    pub fn push(&mut self, item: CString) {
        let l = self.ptrs.len();
        self.ptrs[l-1] = item.as_ptr();
        self.ptrs.push(ptr::null());
        self.items.push(item);
    }
    pub fn as_ptr(&self) -> *const *const c_char {
        self.ptrs.as_ptr()
    }
}

fn construct_envp(env: BTreeMap<DefaultEnvKey, OsString>, saw_nul: &mut bool) -> CStringArray {
    let mut result = CStringArray::with_capacity(env.len());
    for (k, v) in env {
        let mut k: OsString = k.into();

        // Reserve additional space for '=' and null terminator
        k.reserve_exact(v.len() + 2);
        k.push("=");
        k.push(&v);

        // Add the new entry into the array
        if let Ok(item) = CString::new(k.into_vec()) {
            result.push(item);
        } else {
            *saw_nul = true;
        }
    }

    result
}

impl Stdio {
    pub fn to_child_stdio(&self, readable: bool)
                      -> io::Result<(ChildStdio, Option<AnonPipe>)> {
        match *self {
            Stdio::Inherit => {
                Ok((ChildStdio::Inherit, None))
            },

            // Make sure that the source descriptors are not an stdio
            // descriptor, otherwise the order which we set the child's
            // descriptors may blow away a descriptor which we are hoping to
            // save. For example, suppose we want the child's stderr to be the
            // parent's stdout, and the child's stdout to be the parent's
            // stderr. No matter which we dup first, the second will get
            // overwritten prematurely.
            Stdio::Fd(ref fd) => {
                if fd.raw() >= 0 && fd.raw() <= libc::STDERR_FILENO {
                    Ok((ChildStdio::Owned(fd.duplicate()?), None))
                } else {
                    Ok((ChildStdio::Explicit(fd.raw()), None))
                }
            }

            Stdio::MakePipe => {
                let (reader, writer) = pipe::anon_pipe()?;
                let (ours, theirs) = if readable {
                    (writer, reader)
                } else {
                    (reader, writer)
                };
                Ok((ChildStdio::Owned(theirs.into_fd()), Some(ours)))
            }

            Stdio::Null => {
                let mut opts = OpenOptions::new();
                opts.read(readable);
                opts.write(!readable);
                let path = unsafe {
                    CStr::from_ptr("/null\0".as_ptr() as *const _)
                };
                let fd = File::open_c(&path, &opts)?;
                Ok((ChildStdio::Owned(fd.into_fd()), None))
            }
        }
    }
}

impl From<AnonPipe> for Stdio {
    fn from(pipe: AnonPipe) -> Stdio {
        Stdio::Fd(pipe.into_fd())
    }
}

impl From<File> for Stdio {
    fn from(file: File) -> Stdio {
        Stdio::Fd(file.into_fd())
    }
}

impl ChildStdio {
    pub fn fd(&self) -> Option<c_int> {
        match *self {
            ChildStdio::Inherit => None,
            ChildStdio::Explicit(fd) => Some(fd),
            ChildStdio::Owned(ref fd) => Some(fd.raw()),
        }
    }
}

impl fmt::Debug for Command {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}", self.program)?;
        for arg in &self.args {
            write!(f, " {:?}", arg)?;
        }
        Ok(())
    }
}

/// Unix exit statuses
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct ExitStatus(c_int);

impl ExitStatus {
    pub fn new(status: c_int) -> ExitStatus {
        ExitStatus(status)
    }

    fn exited(&self) -> bool {
        /*unsafe*/ { libc::WIFEXITED(self.0) }
    }

    pub fn success(&self) -> bool {
        self.code() == Some(0)
    }

    pub fn code(&self) -> Option<i32> {
        if self.exited() {
            Some(/*unsafe*/ { libc::WEXITSTATUS(self.0) })
        } else {
            None
        }
    }

    pub fn signal(&self) -> Option<i32> {
        if !self.exited() {
            Some(/*unsafe*/ { libc::WTERMSIG(self.0) })
        } else {
            None
        }
    }
}

impl From<c_int> for ExitStatus {
    fn from(a: c_int) -> ExitStatus {
        ExitStatus(a)
    }
}

impl fmt::Display for ExitStatus {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if let Some(code) = self.code() {
            write!(f, "exit code: {}", code)
        } else {
            let signal = self.signal().unwrap();
            write!(f, "signal: {}", signal)
        }
    }
}

#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct ExitCode(u8);

impl ExitCode {
    pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _);
    pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _);

    #[inline]
    pub fn as_i32(&self) -> i32 {
        self.0 as i32
    }
}
<|endoftext|>


<commit_before>//
// Copyright 2019 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

use abitest_frontend::proto::abitest::{ABITestRequest, ABITestResponse};
use oak::grpc;
use oak::OakStatus;
use oak_tests::proto::manager::{
    ApplicationConfiguration, Channel, Channel_Endpoint, GrpcServerNode, Node, WebAssemblyNode,
};
use std::collections::HashMap;

// Constants for node and port names that should match those in the textproto config
// held in ../../client/config.h.
const GRPC_NODE_NAME: &str = "grpc_server";
const FRONTEND_NODE_NAME: &str = "frontend";
const FRONTEND_CODE_NAME: &str = "frontend-code";
const BACKEND_NODE_NAME_PATTERN: &str = "backend_";
const BACKEND_CODE_NAME: &str = "backend-code";
const GRPC_PORT_NAME: &str = "gRPC_input"; // deliberately non-default value
const FE_TO_BE_PORT_NAME_PATTERN: &str = "to_backend_";
const FE_FROM_BE_PORT_NAME_PATTERN: &str = "from_backend_";
const BE_FROM_FE_PORT_NAME: &str = "from_frontend";
const BE_TO_FE_PORT_NAME: &str = "to_frontend";

fn test_config() -> ApplicationConfiguration {
    let mut grpc = Node::new();
    grpc.set_node_name(GRPC_NODE_NAME.to_string());
    grpc.set_grpc_server_node(GrpcServerNode::new());
    let mut frontend = Node::new();
    frontend.set_node_name(FRONTEND_NODE_NAME.to_string());
    let mut wasm_node = WebAssemblyNode::new();
    wasm_node.set_wasm_contents_name(FRONTEND_CODE_NAME.to_string());
    frontend.set_web_assembly_node(wasm_node);
    let mut grpc_channel = Channel::new();
    {
        let mut src_endpoint = Channel_Endpoint::new();
        src_endpoint.set_node_name(GRPC_NODE_NAME.to_string());
        src_endpoint.set_port_name(oak::grpc::OUT_PORT_NAME.to_string());
        grpc_channel.set_source_endpoint(src_endpoint);
        let mut dest_endpoint = Channel_Endpoint::new();
        dest_endpoint.set_node_name(FRONTEND_NODE_NAME.to_string());
        dest_endpoint.set_port_name(GRPC_PORT_NAME.to_string());
        grpc_channel.set_destination_endpoint(dest_endpoint);
    }

    let mut nodes = vec![grpc, frontend];
    let mut channels = vec![grpc_channel];
    for i in 0..3 {
        let name = format!("{}{}", BACKEND_NODE_NAME_PATTERN, i);
        let mut backend = Node::new();
        backend.set_node_name(name.clone());
        let mut wasm_node = WebAssemblyNode::new();
        wasm_node.set_wasm_contents_name(BACKEND_CODE_NAME.to_string());
        backend.set_web_assembly_node(wasm_node);
        nodes.push(backend);

        {
            let mut channel = Channel::new();
            let mut src_endpoint = Channel_Endpoint::new();
            src_endpoint.set_node_name(FRONTEND_NODE_NAME.to_string());
            src_endpoint.set_port_name(format!("{}{}", FE_TO_BE_PORT_NAME_PATTERN, i));
            channel.set_source_endpoint(src_endpoint);
            let mut dest_endpoint = Channel_Endpoint::new();
            dest_endpoint.set_node_name(name.clone());
            dest_endpoint.set_port_name(BE_FROM_FE_PORT_NAME.to_string());
            channel.set_destination_endpoint(dest_endpoint);
            channels.push(channel);
        }
        {
            let mut channel = Channel::new();
            let mut src_endpoint = Channel_Endpoint::new();
            src_endpoint.set_node_name(name.clone());
            src_endpoint.set_port_name(BE_TO_FE_PORT_NAME.to_string());
            channel.set_source_endpoint(src_endpoint);
            let mut dest_endpoint = Channel_Endpoint::new();
            dest_endpoint.set_node_name(FRONTEND_NODE_NAME.to_string());
            dest_endpoint.set_port_name(format!("{}{}", FE_FROM_BE_PORT_NAME_PATTERN, i));
            channel.set_destination_endpoint(dest_endpoint);
            channels.push(channel);
        }
    }

    let mut config = ApplicationConfiguration::new();
    config.set_nodes(protobuf::RepeatedField::from_vec(nodes));
    config.set_channels(protobuf::RepeatedField::from_vec(channels));
    config
}

#[test]
#[serial(node_test)]
fn test_abi() {
    // Initialize the test logger first, so logging gets redirected to simple_logger.
    // (A subsequent attempt to use the oak_log crate will fail.)
    oak_tests::init_logging();
    let mut entrypoints = HashMap::new();
    let fe: oak_tests::NodeMain = abitest_frontend::main;
    let be: oak_tests::NodeMain = abitest_backend::main;
    entrypoints.insert("frontend-code".to_string(), fe);
    entrypoints.insert("backend-code".to_string(), be);
    oak_tests::start(test_config(), entrypoints);

    let mut req = ABITestRequest::new();
    // Skip raw tests (which use invalid memory addresses etc.).
    // TODO: reinstate Orphan tests when oak_tests tracks halves.
    req.exclude = "(Raw|Orphan)".to_string();
    let result: grpc::Result<ABITestResponse> =
        oak_tests::inject_grpc_request("/oak.examples.abitest.OakABITestService/RunTests", req);
    assert_matches!(result, Ok(_));

    assert_eq!(OakStatus::ERR_TERMINATED, oak_tests::stop());

    for result in result.unwrap().get_results() {
        info!(
            "[ {} ] {}",
            if result.success { " OK " } else { "FAIL" },
            result.name
        );
        if !result.success {
            error!("Failure details: {}", result.details);
        }
        assert_eq!(true, result.success);
    }
}
<commit_msg>abitest: enable orphaned channel tests<commit_after>//
// Copyright 2019 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

use abitest_frontend::proto::abitest::{ABITestRequest, ABITestResponse};
use oak::grpc;
use oak::OakStatus;
use oak_tests::proto::manager::{
    ApplicationConfiguration, Channel, Channel_Endpoint, GrpcServerNode, Node, WebAssemblyNode,
};
use std::collections::HashMap;

// Constants for node and port names that should match those in the textproto config
// held in ../../client/config.h.
const GRPC_NODE_NAME: &str = "grpc_server";
const FRONTEND_NODE_NAME: &str = "frontend";
const FRONTEND_CODE_NAME: &str = "frontend-code";
const BACKEND_NODE_NAME_PATTERN: &str = "backend_";
const BACKEND_CODE_NAME: &str = "backend-code";
const GRPC_PORT_NAME: &str = "gRPC_input"; // deliberately non-default value
const FE_TO_BE_PORT_NAME_PATTERN: &str = "to_backend_";
const FE_FROM_BE_PORT_NAME_PATTERN: &str = "from_backend_";
const BE_FROM_FE_PORT_NAME: &str = "from_frontend";
const BE_TO_FE_PORT_NAME: &str = "to_frontend";

fn test_config() -> ApplicationConfiguration {
    let mut grpc = Node::new();
    grpc.set_node_name(GRPC_NODE_NAME.to_string());
    grpc.set_grpc_server_node(GrpcServerNode::new());
    let mut frontend = Node::new();
    frontend.set_node_name(FRONTEND_NODE_NAME.to_string());
    let mut wasm_node = WebAssemblyNode::new();
    wasm_node.set_wasm_contents_name(FRONTEND_CODE_NAME.to_string());
    frontend.set_web_assembly_node(wasm_node);
    let mut grpc_channel = Channel::new();
    {
        let mut src_endpoint = Channel_Endpoint::new();
        src_endpoint.set_node_name(GRPC_NODE_NAME.to_string());
        src_endpoint.set_port_name(oak::grpc::OUT_PORT_NAME.to_string());
        grpc_channel.set_source_endpoint(src_endpoint);
        let mut dest_endpoint = Channel_Endpoint::new();
        dest_endpoint.set_node_name(FRONTEND_NODE_NAME.to_string());
        dest_endpoint.set_port_name(GRPC_PORT_NAME.to_string());
        grpc_channel.set_destination_endpoint(dest_endpoint);
    }

    let mut nodes = vec![grpc, frontend];
    let mut channels = vec![grpc_channel];
    for i in 0..3 {
        let name = format!("{}{}", BACKEND_NODE_NAME_PATTERN, i);
        let mut backend = Node::new();
        backend.set_node_name(name.clone());
        let mut wasm_node = WebAssemblyNode::new();
        wasm_node.set_wasm_contents_name(BACKEND_CODE_NAME.to_string());
        backend.set_web_assembly_node(wasm_node);
        nodes.push(backend);

        {
            let mut channel = Channel::new();
            let mut src_endpoint = Channel_Endpoint::new();
            src_endpoint.set_node_name(FRONTEND_NODE_NAME.to_string());
            src_endpoint.set_port_name(format!("{}{}", FE_TO_BE_PORT_NAME_PATTERN, i));
            channel.set_source_endpoint(src_endpoint);
            let mut dest_endpoint = Channel_Endpoint::new();
            dest_endpoint.set_node_name(name.clone());
            dest_endpoint.set_port_name(BE_FROM_FE_PORT_NAME.to_string());
            channel.set_destination_endpoint(dest_endpoint);
            channels.push(channel);
        }
        {
            let mut channel = Channel::new();
            let mut src_endpoint = Channel_Endpoint::new();
            src_endpoint.set_node_name(name.clone());
            src_endpoint.set_port_name(BE_TO_FE_PORT_NAME.to_string());
            channel.set_source_endpoint(src_endpoint);
            let mut dest_endpoint = Channel_Endpoint::new();
            dest_endpoint.set_node_name(FRONTEND_NODE_NAME.to_string());
            dest_endpoint.set_port_name(format!("{}{}", FE_FROM_BE_PORT_NAME_PATTERN, i));
            channel.set_destination_endpoint(dest_endpoint);
            channels.push(channel);
        }
    }

    let mut config = ApplicationConfiguration::new();
    config.set_nodes(protobuf::RepeatedField::from_vec(nodes));
    config.set_channels(protobuf::RepeatedField::from_vec(channels));
    config
}

#[test]
#[serial(node_test)]
fn test_abi() {
    // Initialize the test logger first, so logging gets redirected to simple_logger.
    // (A subsequent attempt to use the oak_log crate will fail.)
    oak_tests::init_logging();
    let mut entrypoints = HashMap::new();
    let fe: oak_tests::NodeMain = abitest_frontend::main;
    let be: oak_tests::NodeMain = abitest_backend::main;
    entrypoints.insert("frontend-code".to_string(), fe);
    entrypoints.insert("backend-code".to_string(), be);
    oak_tests::start(test_config(), entrypoints);

    let mut req = ABITestRequest::new();
    // Skip raw tests (which use invalid memory addresses etc.).
    req.exclude = "Raw".to_string();
    let result: grpc::Result<ABITestResponse> =
        oak_tests::inject_grpc_request("/oak.examples.abitest.OakABITestService/RunTests", req);
    assert_matches!(result, Ok(_));

    assert_eq!(OakStatus::ERR_TERMINATED, oak_tests::stop());

    for result in result.unwrap().get_results() {
        info!(
            "[ {} ] {}",
            if result.success { " OK " } else { "FAIL" },
            result.name
        );
        if !result.success {
            error!("Failure details: {}", result.details);
        }
        assert_eq!(true, result.success);
    }
}
<|endoftext|>


<commit_before>import std::time;
import std::time::tm;
import m2_request = mongrel2::request;

import router::router;
import request::request;
import response::response;
import middleware::middleware;

import to_bytes::to_bytes;

type mre<T> = {
    m2: mongrel2::connection,
    router: router::router<T>,
    middleware: middleware::middleware<T>,
    mk_data: fn@() -> T,
};

fn mre<T: copy>(m2: mongrel2::connection,
          middleware: middleware::middleware<T>,
          mk_data: fn@() -> T) -> mre<T> {
    {
        m2: m2,
        router: router::router(),
        middleware: middleware,
        mk_data: mk_data,
    }
}

impl mre<T: copy> for mre<T> {
    fn run() {
        loop {
            let m2_req = self.m2.recv();

            // Ignore close requests for now.
            if m2_req.is_disconnect() { cont; }

            let rep = response::response(self.m2, m2_req);

            let req = alt request::request(m2_req, rep, self.mk_data()) {
              none {
                // Ignore this request if it's malformed.
                cont;
              }
              some(req) { req }
            };

            self.middleware.wrap(req, rep);

            alt self.router.find(req.method, req.path()) {
              none { rep.http_404("") }
              some((handler, m)) { handler(req, rep, m) }
            };
        }
    }
}
<commit_msg>Add simple message on start.<commit_after>import std::time;
import std::time::tm;
import m2_request = mongrel2::request;

import router::router;
import request::request;
import response::response;
import middleware::middleware;

import to_bytes::to_bytes;

type mre<T> = {
    m2: mongrel2::connection,
    router: router::router<T>,
    middleware: middleware::middleware<T>,
    mk_data: fn@() -> T,
};

fn mre<T: copy>(m2: mongrel2::connection,
          middleware: middleware::middleware<T>,
          mk_data: fn@() -> T) -> mre<T> {
    {
        m2: m2,
        router: router::router(),
        middleware: middleware,
        mk_data: mk_data,
    }
}

impl mre<T: copy> for mre<T> {
    fn run() {
        io::println(#fmt("Starting up %? -> %?",
            self.m2.sub_addrs(),
            self.m2.pub_addrs()));

        loop {
            let m2_req = self.m2.recv();

            // Ignore close requests for now.
            if m2_req.is_disconnect() { cont; }

            let rep = response::response(self.m2, m2_req);

            let req = alt request::request(m2_req, rep, self.mk_data()) {
              none {
                // Ignore this request if it's malformed.
                cont;
              }
              some(req) { req }
            };

            self.middleware.wrap(req, rep);

            alt self.router.find(req.method, req.path()) {
              none { rep.http_404("") }
              some((handler, m)) { handler(req, rep, m) }
            };
        }
    }
}
<|endoftext|>


<commit_before>use agent::*;
use observer::*;

mod agent;
mod geometry;
mod observer;

fn main() {

    let cells=Crowd::new(10);
    io::println(cells.to_str());

    let mut obs = ScreenPrinter::new(10);
    let mut obs2 = DiskWriter::new(10, ~"cells");
    let dt=0.001;
    let mut t=0.0;
    for 100.times {
        cells.evolve(dt);
        if(obs.request_at(t)) {
            obs.see(t, &cells);
        }
        if(obs2.request_at(t)) {
            obs2.see(t, &cells);
        }
        t+=dt;
    }
}
<commit_msg>Sortie sur le disque<commit_after>use agent::*;
use observer::*;

mod agent;
mod geometry;
mod observer;

fn main() {

    let mut cells=Crowd::new(100);

    let mut obs = ProgressMeter::new(200);
    let mut obs2 = DiskWriter::new(200, ~"cells");
    let dt=0.001;
    let mut t=0.0;
    for 10000.times {
        cells.evolve(dt);
        if(obs.request_at(t)) {
            obs.see(t, &cells);
        }
        if(obs2.request_at(t)) {
            obs2.see(t, &cells);
        }
        t+=dt;
    }
}
<|endoftext|>


<commit_before>//! Mocks for testing

pub mod clitools;
pub mod dist;
pub mod topical_doc_data;

use std::fs::{self, File, OpenOptions};
use std::io::Write;
use std::path::Path;
use std::sync::Arc;

// Mock of the on-disk structure of rust-installer installers
#[derive(PartialEq, Eq, Hash, Clone)]
pub struct MockInstallerBuilder {
    pub components: Vec<MockComponentBuilder>,
}

#[derive(PartialEq, Eq, Hash, Clone)]
pub struct MockComponentBuilder {
    pub name: String,
    pub files: Vec<MockFile>,
}

#[derive(PartialEq, Eq, Hash, Clone)]
pub struct MockFile {
    path: String,
    contents: Contents,
}

#[derive(PartialEq, Eq, Hash, Clone)]
enum Contents {
    File(MockContents),
    Dir(Vec<(&'static str, MockContents)>),
}

#[derive(PartialEq, Eq, Hash, Clone)]
struct MockContents {
    contents: Arc<Vec<u8>>,
    executable: bool,
}

impl MockInstallerBuilder {
    pub fn build(&self, path: &Path) {
        for component in &self.components {
            // Update the components file
            let comp_file = path.join("components");
            let mut comp_file = OpenOptions::new()
                .write(true)
                .append(true)
                .create(true)
                .open(comp_file.clone())
                .unwrap();
            writeln!(comp_file, "{}", component.name).unwrap();

            // Create the component directory
            let component_dir = path.join(&component.name);
            if !component_dir.exists() {
                fs::create_dir(&component_dir).unwrap();
            }

            // Create the component files and manifest
            let mut manifest = File::create(component_dir.join("manifest.in")).unwrap();
            for file in component.files.iter() {
                match file.contents {
                    Contents::Dir(_) => {
                        writeln!(manifest, "dir:{}", file.path).unwrap();
                    }
                    Contents::File(_) => {
                        writeln!(manifest, "file:{}", file.path).unwrap();
                    }
                }
                file.build(&component_dir);
            }
        }

        let mut ver = File::create(path.join("rust-installer-version")).unwrap();
        writeln!(ver, "3").unwrap();
    }
}

impl MockFile {
    pub fn new<S: Into<String>>(path: S, contents: &[u8]) -> MockFile {
        MockFile::_new(path.into(), Arc::new(contents.to_vec()))
    }

    pub fn new_arc<S: Into<String>>(path: S, contents: Arc<Vec<u8>>) -> MockFile {
        MockFile::_new(path.into(), contents)
    }

    fn _new(path: String, contents: Arc<Vec<u8>>) -> MockFile {
        MockFile {
            path,
            contents: Contents::File(MockContents {
                contents,
                executable: false,
            }),
        }
    }

    pub fn new_dir(path: &str, files: &[(&'static str, &'static [u8], bool)]) -> MockFile {
        MockFile {
            path: path.to_string(),
            contents: Contents::Dir(
                files
                    .iter()
                    .map(|&(name, data, exe)| {
                        (
                            name,
                            MockContents {
                                contents: Arc::new(data.to_vec()),
                                executable: exe,
                            },
                        )
                    })
                    .collect(),
            ),
        }
    }

    pub fn executable(mut self, exe: bool) -> Self {
        if let Contents::File(c) = &mut self.contents {
            c.executable = exe;
        }
        self
    }

    pub fn build(&self, path: &Path) {
        let path = path.join(&self.path);
        match self.contents {
            Contents::Dir(ref files) => {
                for &(ref name, ref contents) in files {
                    let fname = path.join(name);
                    contents.build(&fname);
                }
            }
            Contents::File(ref contents) => contents.build(&path),
        }
    }
}

impl MockContents {
    fn build(&self, path: &Path) {
        let dir_path = path.parent().unwrap().to_owned();
        fs::create_dir_all(dir_path).unwrap();
        File::create(&path)
            .unwrap()
            .write_all(&self.contents)
            .unwrap();

        #[cfg(unix)]
        {
            use std::os::unix::fs::PermissionsExt;
            if self.executable {
                let mut perm = fs::metadata(path).unwrap().permissions();
                perm.set_mode(0o755);
                fs::set_permissions(path, perm).unwrap();
            }
        }
    }
}

#[cfg(windows)]
pub fn get_path() -> Option<String> {
    use winreg::enums::{HKEY_CURRENT_USER, KEY_READ, KEY_WRITE};
    use winreg::RegKey;

    let root = RegKey::predef(HKEY_CURRENT_USER);
    let environment = root
        .open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE)
        .unwrap();

    environment.get_value("PATH").ok()
}

#[cfg(windows)]
pub fn restore_path(p: Option<String>) {
    use winreg::enums::{RegType, HKEY_CURRENT_USER, KEY_READ, KEY_WRITE};
    use winreg::{RegKey, RegValue};

    let root = RegKey::predef(HKEY_CURRENT_USER);
    let environment = root
        .open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE)
        .unwrap();

    if let Some(p) = p.as_ref() {
        let reg_value = RegValue {
            bytes: string_to_winreg_bytes(&p),
            vtype: RegType::REG_EXPAND_SZ,
        };
        environment.set_raw_value("PATH", &reg_value).unwrap();
    } else {
        let _ = environment.delete_value("PATH");
    }

    fn string_to_winreg_bytes(s: &str) -> Vec<u8> {
        use std::ffi::OsStr;
        use std::os::windows::ffi::OsStrExt;
        let v: Vec<u16> = OsStr::new(s)
            .encode_wide()
            .chain(std::iter::once(0))
            .collect();
        let ptr = v.as_ptr().cast::<u8>();
        let len = v.len() * 2;
        unsafe { std::slice::from_raw_parts(ptr, len) }.to_vec()
    }
}

#[cfg(unix)]
pub fn get_path() -> Option<String> {
    None
}

#[cfg(unix)]
pub fn restore_path(_: Option<String>) {}
<commit_msg>De-duplicate `string_to_winreg_bytes` function<commit_after>//! Mocks for testing

pub mod clitools;
pub mod dist;
pub mod topical_doc_data;

#[cfg(windows)]
use rustup::utils::utils;
use std::fs::{self, File, OpenOptions};
use std::io::Write;
use std::path::Path;
use std::sync::Arc;

// Mock of the on-disk structure of rust-installer installers
#[derive(PartialEq, Eq, Hash, Clone)]
pub struct MockInstallerBuilder {
    pub components: Vec<MockComponentBuilder>,
}

#[derive(PartialEq, Eq, Hash, Clone)]
pub struct MockComponentBuilder {
    pub name: String,
    pub files: Vec<MockFile>,
}

#[derive(PartialEq, Eq, Hash, Clone)]
pub struct MockFile {
    path: String,
    contents: Contents,
}

#[derive(PartialEq, Eq, Hash, Clone)]
enum Contents {
    File(MockContents),
    Dir(Vec<(&'static str, MockContents)>),
}

#[derive(PartialEq, Eq, Hash, Clone)]
struct MockContents {
    contents: Arc<Vec<u8>>,
    executable: bool,
}

impl MockInstallerBuilder {
    pub fn build(&self, path: &Path) {
        for component in &self.components {
            // Update the components file
            let comp_file = path.join("components");
            let mut comp_file = OpenOptions::new()
                .write(true)
                .append(true)
                .create(true)
                .open(comp_file.clone())
                .unwrap();
            writeln!(comp_file, "{}", component.name).unwrap();

            // Create the component directory
            let component_dir = path.join(&component.name);
            if !component_dir.exists() {
                fs::create_dir(&component_dir).unwrap();
            }

            // Create the component files and manifest
            let mut manifest = File::create(component_dir.join("manifest.in")).unwrap();
            for file in component.files.iter() {
                match file.contents {
                    Contents::Dir(_) => {
                        writeln!(manifest, "dir:{}", file.path).unwrap();
                    }
                    Contents::File(_) => {
                        writeln!(manifest, "file:{}", file.path).unwrap();
                    }
                }
                file.build(&component_dir);
            }
        }

        let mut ver = File::create(path.join("rust-installer-version")).unwrap();
        writeln!(ver, "3").unwrap();
    }
}

impl MockFile {
    pub fn new<S: Into<String>>(path: S, contents: &[u8]) -> MockFile {
        MockFile::_new(path.into(), Arc::new(contents.to_vec()))
    }

    pub fn new_arc<S: Into<String>>(path: S, contents: Arc<Vec<u8>>) -> MockFile {
        MockFile::_new(path.into(), contents)
    }

    fn _new(path: String, contents: Arc<Vec<u8>>) -> MockFile {
        MockFile {
            path,
            contents: Contents::File(MockContents {
                contents,
                executable: false,
            }),
        }
    }

    pub fn new_dir(path: &str, files: &[(&'static str, &'static [u8], bool)]) -> MockFile {
        MockFile {
            path: path.to_string(),
            contents: Contents::Dir(
                files
                    .iter()
                    .map(|&(name, data, exe)| {
                        (
                            name,
                            MockContents {
                                contents: Arc::new(data.to_vec()),
                                executable: exe,
                            },
                        )
                    })
                    .collect(),
            ),
        }
    }

    pub fn executable(mut self, exe: bool) -> Self {
        if let Contents::File(c) = &mut self.contents {
            c.executable = exe;
        }
        self
    }

    pub fn build(&self, path: &Path) {
        let path = path.join(&self.path);
        match self.contents {
            Contents::Dir(ref files) => {
                for &(ref name, ref contents) in files {
                    let fname = path.join(name);
                    contents.build(&fname);
                }
            }
            Contents::File(ref contents) => contents.build(&path),
        }
    }
}

impl MockContents {
    fn build(&self, path: &Path) {
        let dir_path = path.parent().unwrap().to_owned();
        fs::create_dir_all(dir_path).unwrap();
        File::create(&path)
            .unwrap()
            .write_all(&self.contents)
            .unwrap();

        #[cfg(unix)]
        {
            use std::os::unix::fs::PermissionsExt;
            if self.executable {
                let mut perm = fs::metadata(path).unwrap().permissions();
                perm.set_mode(0o755);
                fs::set_permissions(path, perm).unwrap();
            }
        }
    }
}

#[cfg(windows)]
pub fn get_path() -> Option<String> {
    use winreg::enums::{HKEY_CURRENT_USER, KEY_READ, KEY_WRITE};
    use winreg::RegKey;

    let root = RegKey::predef(HKEY_CURRENT_USER);
    let environment = root
        .open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE)
        .unwrap();

    environment.get_value("PATH").ok()
}

#[cfg(windows)]
pub fn restore_path(p: Option<String>) {
    use winreg::enums::{RegType, HKEY_CURRENT_USER, KEY_READ, KEY_WRITE};
    use winreg::{RegKey, RegValue};

    let root = RegKey::predef(HKEY_CURRENT_USER);
    let environment = root
        .open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE)
        .unwrap();

    if let Some(p) = p.as_ref() {
        let reg_value = RegValue {
            bytes: utils::string_to_winreg_bytes(&p),
            vtype: RegType::REG_EXPAND_SZ,
        };
        environment.set_raw_value("PATH", &reg_value).unwrap();
    } else {
        let _ = environment.delete_value("PATH");
    }
}

#[cfg(unix)]
pub fn get_path() -> Option<String> {
    None
}

#[cfg(unix)]
pub fn restore_path(_: Option<String>) {}
<|endoftext|>