<commit_before>// riff-wave -- Basic support for reading and writing wave PCM files.
// Copyright (c) 2016 Kevin Brothaler and the riff-wave project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.
// 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 std::cmp;
use std::error;
use std::fmt;
use std::io;
use std::io::{Seek, SeekFrom, Write};
use std::result;

use byteorder::{LittleEndian, WriteBytesExt};

use super::PcmFormat;
use super::{FORMAT_UNCOMPRESSED_PCM, MAX_I24_VALUE, MIN_I24_VALUE};

// MARK: Error types

#[derive(Debug)]
pub enum WriteError {
    /// The file format is incorrect or unsupported.
    Format(WriteErrorKind),
    /// An IO error occurred.
    Io(io::Error),
}

/// Represents a result when reading a wave file.
pub type WriteResult<T> = result::Result<T, WriteError>;

impl fmt::Display for WriteError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            WriteError::Format(ref err_kind) => write!(f, "Format error: {}", err_kind),
            WriteError::Io(ref err) => write!(f, "IO error: {}", err),
        }
    }
}

/// Represents a file format error, when incorrect parameters have been specified.
#[derive(Debug)]
pub enum WriteErrorKind {
    /// The number of channels is zero, which is invalid.
    NumChannelsIsZero,
    /// The sample rate is zero, which is invalid.
    SampleRateIsZero,
    /// Only 8-bit, 16-bit, 24-bit and 32-bit PCM files are supported.
    UnsupportedBitsPerSample(u16),
}

impl WriteErrorKind {
    fn to_string(&self) -> &str {
        match *self {
            WriteErrorKind::NumChannelsIsZero => "Number of channels is zero",
            WriteErrorKind::SampleRateIsZero => "Sample rate is zero",
            WriteErrorKind::UnsupportedBitsPerSample(_) => "Unsupported bits per sample",
        }
    }
}

impl fmt::Display for WriteErrorKind {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.to_string())
    }
}

impl error::Error for WriteError {
    fn description(&self) -> &str {
        match *self {
            WriteError::Format(ref kind) => kind.to_string(),
            WriteError::Io(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            WriteError::Format(_) => None,
            WriteError::Io(ref err) => Some(err),
        }
    }
}

impl From<io::Error> for WriteError {
    fn from(err: io::Error) -> WriteError {
        WriteError::Io(err)
    }
}

// MARK: Writing functions

trait WriteWaveExt: Write + Seek {
    fn write_standard_wave_header(&mut self, pcm_format: &PcmFormat) -> WriteResult<()> {
        try!(self.write_riff_wave_chunk_header());
        try!(self.write_standard_fmt_subchunk(pcm_format.num_channels,
                                              pcm_format.sample_rate,
                                              pcm_format.bits_per_sample));
        try!(self.write_data_subchunk_header());

        Ok(())
    }

    fn write_riff_wave_chunk_header(&mut self) -> WriteResult<()> {
        try!(self.write_all(b"RIFF"));                      // Identifier
        try!(self.write_u32_l(36));                         // File size (header) minus eight bytes
        try!(self.write_all(b"WAVE"));                      // Identifier

        Ok(())
    }

    fn write_standard_fmt_subchunk(&mut self,
                                   num_channels: u16,
                                   sample_rate: u32,
                                   bits_per_sample: u16)
                                   -> WriteResult<()> {
        if num_channels == 0 {
            return Err(WriteError::Format(WriteErrorKind::NumChannelsIsZero));
        } else if sample_rate == 0 {
            return Err(WriteError::Format(WriteErrorKind::SampleRateIsZero));
        } else if bits_per_sample != 8 && bits_per_sample != 16 && bits_per_sample != 24 &&
           bits_per_sample != 32 {
            return Err(WriteError::Format(WriteErrorKind::UnsupportedBitsPerSample(bits_per_sample)));
        }

        try!(self.write_all(b"fmt "));                      // "fmt " chunk and size
        try!(self.write_u32_l(16));                         // Subchunk size
        try!(self.write_u16_l(FORMAT_UNCOMPRESSED_PCM));    // PCM Format
        try!(self.write_u16_l(num_channels));               // Number of channels
        try!(self.write_u32_l(sample_rate));                // Sample rate

        let bytes_per_sample = bits_per_sample / 8;
        let block_align = num_channels * bytes_per_sample;
        let byte_rate = block_align as u32 * sample_rate;

        try!(self.write_u32_l(byte_rate));                  // Byte rate
        try!(self.write_u16_l(block_align));                // Block align
        try!(self.write_u16_l(bits_per_sample));            // Bits per sample

        Ok(())
    }

    fn write_data_subchunk_header(&mut self) -> WriteResult<()> {
        try!(self.write_all(b"data"));                      // Start of "data" subchunk
        try!(self.write_u32_l(0));                          // Size of data subchunk.

        Ok(())
    }

    fn write_u16_l(&mut self, n: u16) -> io::Result<()> {
        self.write_u16::<LittleEndian>(n)
    }

    fn write_u32_l(&mut self, n: u32) -> io::Result<()> {
        self.write_u32::<LittleEndian>(n)
    }
}

impl<T> WriteWaveExt for T where T: Seek + Write {}

fn clamp(n: i32, min: i32, max: i32) -> i32 {
    cmp::min(cmp::max(n, min), max)
}

/// Helper struct that takes ownership of a writer and can be used to write data
/// to a PCM wave file.
#[derive(Debug)]
pub struct WaveWriter<T>
    where T: Seek + Write
{
    ///  Represents the PCM format for this wave file.
    pub pcm_format: PcmFormat,

    // How many samples have been written.
    written_samples: u32,

    // The underlying writer that we'll use to read data.
    writer: T,
}

// TODO what should we do if an incorrect write_* method is called? Return the error in the result?
impl<T> WaveWriter<T>
    where T: Seek + Write
{
    /// Returns a new wave writer for the given writer.
    pub fn new(num_channels: u16,
               sample_rate: u32,
               bits_per_sample: u16,
               mut writer: T)
               -> WriteResult<WaveWriter<T>> {
        let pcm_format = PcmFormat {
            num_channels: num_channels,
            sample_rate: sample_rate,
            bits_per_sample: bits_per_sample,
        };

        try!(writer.write_standard_wave_header(&pcm_format));

        Ok(WaveWriter {
            pcm_format: pcm_format,
            written_samples: 0,
            writer: writer,
        })
    }

    /// Writes a single sample as an unsigned 8-bit value.
    pub fn write_sample_u8(&mut self, sample: u8) -> io::Result<()> {
        self.write_sample(sample, |writer, sample| writer.write_u8(sample))
    }

    /// Writes a single sample as a signed 16-bit value.
    pub fn write_sample_i16(&mut self, sample: i16) -> io::Result<()> {
        self.write_sample(sample, |writer, sample| writer.write_i16::<LittleEndian>(sample))
    }

    /// Writes a single sample as a signed 24-bit value. The value will be truncated
    /// to fit in a 24-bit value.
    pub fn write_sample_i24(&mut self, sample: i32) -> io::Result<()> {
        self.write_sample(sample, |writer, sample| {
            writer.write_int::<LittleEndian>(clamp(sample, MIN_I24_VALUE, MAX_I24_VALUE) as i64, 3)
        })
    }

    /// Writes a single sample as a signed 32-bit value.
    pub fn write_sample_i32(&mut self, sample: i32) -> io::Result<()> {
        self.write_sample(sample, |writer, sample| writer.write_i32::<LittleEndian>(sample))
    }

    fn write_sample<F, S>(&mut self, sample: S, write_data: F) -> io::Result<()>
        where F: Fn(&mut T, S) -> io::Result<()>
    {
        try!(write_data(&mut self.writer, sample));
        self.written_samples = self.written_samples + 1;
        Ok(())
    }

    /// Updates the header at the beginning of the file with the new chunk sizes.
    pub fn sync_header(&mut self) -> io::Result<()> {
        let data_chunk_size = self.written_samples * self.pcm_format.bits_per_sample as u32 / 8;
        let riff_chunk_size = 36 + data_chunk_size;

        // File size minus eight bytes
        try!(self.writer.seek(SeekFrom::Start(4)));
        try!(self.writer.write_u32_l(riff_chunk_size));

        // Data size minus eight bytes
        try!(self.writer.seek(SeekFrom::Start(40)));
        try!(self.writer.write_u32_l(data_chunk_size));

        // Seek back to the end so we can continue writing
        try!(self.writer.seek(SeekFrom::End(0)));

        Ok(())
    }

    /// Consumes this writer, returning the underlying value.
    pub fn into_inner(self) -> T {
        self.writer
    }
}

// MARK: Tests

#[cfg(test)]
mod tests {
    use std::io::Cursor;

    use super::super::WaveReader;
    use super::super::{MIN_I24_VALUE, MAX_I24_VALUE};
    use super::{WriteError, WriteErrorKind, WaveWriter};
    use super::clamp;

    // Validation tests

    #[test]
    fn test_validate_doesnt_accept_zero_channels() {
        let wave_writer = WaveWriter::new(0, 44100, 16, Cursor::new(Vec::new()));
        assert_matches!(Err(WriteError::Format(WriteErrorKind::NumChannelsIsZero)),
                        wave_writer);
    }

    #[test]
    fn test_validate_doesnt_accept_zero_sample_rate() {
        let wave_writer = WaveWriter::new(1, 0, 16, Cursor::new(Vec::new()));
        assert_matches!(Err(WriteError::Format(WriteErrorKind::SampleRateIsZero)),
                        wave_writer);
    }

    #[test]
    fn test_validate_doesnt_accept_invalid_bitrate() {
        let wave_writer = WaveWriter::new(1, 44100, 12, Cursor::new(Vec::new()));
        assert_matches!(Err(WriteError::Format(WriteErrorKind::UnsupportedBitsPerSample(12))),
                        wave_writer);
    }

    #[test]
    fn test_validate_accepts_valid_combination() {
        let wave_writer = WaveWriter::new(1, 44100, 16, Cursor::new(Vec::new()));
        assert_matches!(Ok(_), wave_writer);
    }

    // Header validation tests

    #[test]
    fn test_header_is_acceptable() {
        let data = Vec::new();
        let mut cursor = Cursor::new(data);
        let wave_writer = WaveWriter::new(1, 44100, 16, cursor).unwrap();
        let mut cursor = wave_writer.into_inner();

        cursor.set_position(0);

        let wave_reader = WaveReader::new(cursor).unwrap();

        assert_eq!(1, wave_reader.pcm_format.num_channels);
        assert_eq!(44100, wave_reader.pcm_format.sample_rate);
        assert_eq!(16, wave_reader.pcm_format.bits_per_sample);
    }

    // Write validation tests

    #[test]
    fn test_clamp() {
        assert_eq!(-5, clamp(-10, -5, 5));
        assert_eq!(5, clamp(10, -5, 5));

        assert_eq!(MIN_I24_VALUE, clamp(i32::min_value(), MIN_I24_VALUE, MAX_I24_VALUE));
        assert_eq!(MAX_I24_VALUE, clamp(i32::max_value(), MIN_I24_VALUE, MAX_I24_VALUE));
    }

    #[test]
    fn test_24_bit_doesnt_panic_when_out_of_range() {
        let data = Vec::new();
        let mut cursor = Cursor::new(data);
        let mut wave_writer = WaveWriter::new(1, 44100, 24, cursor).unwrap();

        wave_writer.write_sample_i24(i32::min_value()).unwrap();
        wave_writer.write_sample_i24(i32::max_value()).unwrap();
    }

    #[test]
    fn test_header_sync_when_no_data_written() {
        let data = Vec::new();
        let mut cursor = Cursor::new(data);
        let mut wave_writer = WaveWriter::new(1, 44100, 16, cursor).unwrap();
        wave_writer.sync_header().unwrap();
        let mut cursor = wave_writer.into_inner();

        cursor.set_position(0);

        let wave_reader = WaveReader::new(cursor).unwrap();
        let cursor = wave_reader.into_inner();
        let data = cursor.into_inner();

        assert_eq!(44, data.len());
        // We're not currently surfacing the chunk/subchunk info in the reader
        // so just access the data directly.

        // Should match 36 in little-endian format.
        assert_eq!(b"\x24\x00\x00\x00", &data[4..8]);

        // Should match 0 in little-endian format.
        assert_eq!(b"\x00\x00\x00\x00", &data[40..44]);
    }

    #[test]
    fn test_header_sync_when_ten_samples_written() {
        let data = Vec::new();
        let mut cursor = Cursor::new(data);
        let mut wave_writer = WaveWriter::new(1, 44100, 16, cursor).unwrap();

        for i in 0..10 {
            wave_writer.write_sample_i16(i as i16).unwrap();
        }

        wave_writer.sync_header().unwrap();

        let mut cursor = wave_writer.into_inner();

        cursor.set_position(0);

        let wave_reader = WaveReader::new(cursor).unwrap();
        let cursor = wave_reader.into_inner();
        let data = cursor.into_inner();

        assert_eq!(64, data.len());
        // We're not currently surfacing the chunk/subchunk info in the reader
        // so just access the data directly.

        // Should match 56 in little-endian format.
        assert_eq!(b"\x38\x00\x00\x00", &data[4..8]);

        // Should match 20 in little-endian format.
        assert_eq!(b"\x14\x00\x00\x00", &data[40..44]);
    }

    // TODO test header
}
<commit_msg>It probably makes more sense to panic rather than return a result when the writer has been created with invalid parameters, as this would be a programmer error.<commit_after>// riff-wave -- Basic support for reading and writing wave PCM files.
// Copyright (c) 2016 Kevin Brothaler and the riff-wave project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.
// 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 std::cmp;
use std::error;
use std::fmt;
use std::io;
use std::io::{Seek, SeekFrom, Write};
use std::result;

use byteorder::{LittleEndian, WriteBytesExt};

use super::PcmFormat;
use super::{FORMAT_UNCOMPRESSED_PCM, MAX_I24_VALUE, MIN_I24_VALUE};

// MARK: Error types

#[derive(Debug)]
pub enum WriteError {
    /// The file format is incorrect or unsupported.
    Format(WriteErrorKind),
    /// An IO error occurred.
    Io(io::Error),
}

/// Represents a result when reading a wave file.
pub type WriteResult<T> = result::Result<T, WriteError>;

impl fmt::Display for WriteError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            WriteError::Format(ref err_kind) => write!(f, "Format error: {}", err_kind),
            WriteError::Io(ref err) => write!(f, "IO error: {}", err),
        }
    }
}

/// Represents a file format error, when incorrect parameters have been specified.
#[derive(Debug)]
pub enum WriteErrorKind {
    /// The number of channels is zero, which is invalid.
    NumChannelsIsZero,
    /// The sample rate is zero, which is invalid.
    SampleRateIsZero,
    /// Only 8-bit, 16-bit, 24-bit and 32-bit PCM files are supported.
    UnsupportedBitsPerSample(u16),
}

impl WriteErrorKind {
    fn to_string(&self) -> &str {
        match *self {
            WriteErrorKind::NumChannelsIsZero => "Number of channels is zero",
            WriteErrorKind::SampleRateIsZero => "Sample rate is zero",
            WriteErrorKind::UnsupportedBitsPerSample(_) => "Unsupported bits per sample",
        }
    }
}

impl fmt::Display for WriteErrorKind {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.to_string())
    }
}

impl error::Error for WriteError {
    fn description(&self) -> &str {
        match *self {
            WriteError::Format(ref kind) => kind.to_string(),
            WriteError::Io(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            WriteError::Format(_) => None,
            WriteError::Io(ref err) => Some(err),
        }
    }
}

impl From<io::Error> for WriteError {
    fn from(err: io::Error) -> WriteError {
        WriteError::Io(err)
    }
}

// MARK: Writing functions

trait WriteWaveExt: Write + Seek {
    fn write_standard_wave_header(&mut self, pcm_format: &PcmFormat) -> io::Result<()> {
        try!(self.write_riff_wave_chunk_header());
        try!(self.write_standard_fmt_subchunk(pcm_format.num_channels,
                                              pcm_format.sample_rate,
                                              pcm_format.bits_per_sample));
        try!(self.write_data_subchunk_header());

        Ok(())
    }

    fn write_riff_wave_chunk_header(&mut self) -> io::Result<()> {
        try!(self.write_all(b"RIFF"));                      // Identifier
        try!(self.write_u32_l(36));                         // File size (header) minus eight bytes
        try!(self.write_all(b"WAVE"));                      // Identifier

        Ok(())
    }

    fn write_standard_fmt_subchunk(&mut self,
                                   num_channels: u16,
                                   sample_rate: u32,
                                   bits_per_sample: u16)
                                   -> io::Result<()> {
        if num_channels == 0 {
            panic!("The number of channels should be greater than zero.");
        } else if sample_rate == 0 {
            panic!("The sample rate should be greater than zero.");
        } else if bits_per_sample != 8 && bits_per_sample != 16
               && bits_per_sample != 24 && bits_per_sample != 32 {
            panic!("The bits per sample needs to be either 8, 16, 24, or 32.");
        }

        try!(self.write_all(b"fmt "));                      // "fmt " chunk and size
        try!(self.write_u32_l(16));                         // Subchunk size
        try!(self.write_u16_l(FORMAT_UNCOMPRESSED_PCM));    // PCM Format
        try!(self.write_u16_l(num_channels));               // Number of channels
        try!(self.write_u32_l(sample_rate));                // Sample rate

        let bytes_per_sample = bits_per_sample / 8;
        let block_align = num_channels * bytes_per_sample;
        let byte_rate = block_align as u32 * sample_rate;

        try!(self.write_u32_l(byte_rate));                  // Byte rate
        try!(self.write_u16_l(block_align));                // Block align
        try!(self.write_u16_l(bits_per_sample));            // Bits per sample

        Ok(())
    }

    fn write_data_subchunk_header(&mut self) -> io::Result<()> {
        try!(self.write_all(b"data"));                      // Start of "data" subchunk
        try!(self.write_u32_l(0));                          // Size of data subchunk.

        Ok(())
    }

    fn write_u16_l(&mut self, n: u16) -> io::Result<()> {
        self.write_u16::<LittleEndian>(n)
    }

    fn write_u32_l(&mut self, n: u32) -> io::Result<()> {
        self.write_u32::<LittleEndian>(n)
    }
}

impl<T> WriteWaveExt for T where T: Seek + Write {}

fn clamp(n: i32, min: i32, max: i32) -> i32 {
    cmp::min(cmp::max(n, min), max)
}

/// Helper struct that takes ownership of a writer and can be used to write data
/// to a PCM wave file.
#[derive(Debug)]
pub struct WaveWriter<T>
    where T: Seek + Write
{
    ///  Represents the PCM format for this wave file.
    pub pcm_format: PcmFormat,

    // How many samples have been written.
    written_samples: u32,

    // The underlying writer that we'll use to read data.
    writer: T,
}

// TODO what should we do if an incorrect write_* method is called? Return the error in the result?
impl<T> WaveWriter<T>
    where T: Seek + Write
{
    /// Returns a new wave writer for the given writer.
    /// # Panics
    /// Panics if num_channels or sample_rate is zero, or if bits_per_sample doesn't match 8, 16, 24, or 32.
    pub fn new(num_channels: u16,
               sample_rate: u32,
               bits_per_sample: u16,
               mut writer: T)
               -> WriteResult<WaveWriter<T>> {
        let pcm_format = PcmFormat {
            num_channels: num_channels,
            sample_rate: sample_rate,
            bits_per_sample: bits_per_sample,
        };

        try!(writer.write_standard_wave_header(&pcm_format));

        Ok(WaveWriter {
            pcm_format: pcm_format,
            written_samples: 0,
            writer: writer,
        })
    }

    /// Writes a single sample as an unsigned 8-bit value.
    pub fn write_sample_u8(&mut self, sample: u8) -> io::Result<()> {
        self.write_sample(sample, |writer, sample| writer.write_u8(sample))
    }

    /// Writes a single sample as a signed 16-bit value.
    pub fn write_sample_i16(&mut self, sample: i16) -> io::Result<()> {
        self.write_sample(sample, |writer, sample| writer.write_i16::<LittleEndian>(sample))
    }

    /// Writes a single sample as a signed 24-bit value. The value will be truncated
    /// to fit in a 24-bit value.
    pub fn write_sample_i24(&mut self, sample: i32) -> io::Result<()> {
        self.write_sample(sample, |writer, sample| {
            writer.write_int::<LittleEndian>(clamp(sample, MIN_I24_VALUE, MAX_I24_VALUE) as i64, 3)
        })
    }

    /// Writes a single sample as a signed 32-bit value.
    pub fn write_sample_i32(&mut self, sample: i32) -> io::Result<()> {
        self.write_sample(sample, |writer, sample| writer.write_i32::<LittleEndian>(sample))
    }

    fn write_sample<F, S>(&mut self, sample: S, write_data: F) -> io::Result<()>
        where F: Fn(&mut T, S) -> io::Result<()>
    {
        try!(write_data(&mut self.writer, sample));
        self.written_samples = self.written_samples + 1;
        Ok(())
    }

    /// Updates the header at the beginning of the file with the new chunk sizes.
    pub fn sync_header(&mut self) -> io::Result<()> {
        let data_chunk_size = self.written_samples * self.pcm_format.bits_per_sample as u32 / 8;
        let riff_chunk_size = 36 + data_chunk_size;

        // File size minus eight bytes
        try!(self.writer.seek(SeekFrom::Start(4)));
        try!(self.writer.write_u32_l(riff_chunk_size));

        // Data size minus eight bytes
        try!(self.writer.seek(SeekFrom::Start(40)));
        try!(self.writer.write_u32_l(data_chunk_size));

        // Seek back to the end so we can continue writing
        try!(self.writer.seek(SeekFrom::End(0)));

        Ok(())
    }

    /// Consumes this writer, returning the underlying value.
    pub fn into_inner(self) -> T {
        self.writer
    }
}

// MARK: Tests

#[cfg(test)]
mod tests {
    use std::io::Cursor;

    use super::super::WaveReader;
    use super::super::{MIN_I24_VALUE, MAX_I24_VALUE};
    use super::{WriteError, WriteErrorKind, WaveWriter};
    use super::clamp;

    // Validation tests

    #[test]
    #[should_panic]
    fn test_validate_doesnt_accept_zero_channels() {
        let wave_writer = WaveWriter::new(0, 44100, 16, Cursor::new(Vec::new()));
    }

    #[test]
    #[should_panic]
    fn test_validate_doesnt_accept_zero_sample_rate() {
        let wave_writer = WaveWriter::new(1, 0, 16, Cursor::new(Vec::new()));
    }

    #[test]
    #[should_panic]
    fn test_validate_doesnt_accept_invalid_bitrate() {
        let wave_writer = WaveWriter::new(1, 44100, 12, Cursor::new(Vec::new()));
    }

    #[test]
    fn test_validate_accepts_valid_combination() {
        let wave_writer = WaveWriter::new(1, 44100, 16, Cursor::new(Vec::new()));
        assert_matches!(Ok(_), wave_writer);
    }

    // Header validation tests

    #[test]
    fn test_header_is_acceptable() {
        let data = Vec::new();
        let mut cursor = Cursor::new(data);
        let wave_writer = WaveWriter::new(1, 44100, 16, cursor).unwrap();
        let mut cursor = wave_writer.into_inner();

        cursor.set_position(0);

        let wave_reader = WaveReader::new(cursor).unwrap();

        assert_eq!(1, wave_reader.pcm_format.num_channels);
        assert_eq!(44100, wave_reader.pcm_format.sample_rate);
        assert_eq!(16, wave_reader.pcm_format.bits_per_sample);
    }

    // Write validation tests

    #[test]
    fn test_clamp() {
        assert_eq!(-5, clamp(-10, -5, 5));
        assert_eq!(5, clamp(10, -5, 5));

        assert_eq!(MIN_I24_VALUE, clamp(i32::min_value(), MIN_I24_VALUE, MAX_I24_VALUE));
        assert_eq!(MAX_I24_VALUE, clamp(i32::max_value(), MIN_I24_VALUE, MAX_I24_VALUE));
    }

    #[test]
    fn test_24_bit_doesnt_panic_when_out_of_range() {
        let data = Vec::new();
        let mut cursor = Cursor::new(data);
        let mut wave_writer = WaveWriter::new(1, 44100, 24, cursor).unwrap();

        wave_writer.write_sample_i24(i32::min_value()).unwrap();
        wave_writer.write_sample_i24(i32::max_value()).unwrap();
    }

    #[test]
    fn test_header_sync_when_no_data_written() {
        let data = Vec::new();
        let mut cursor = Cursor::new(data);
        let mut wave_writer = WaveWriter::new(1, 44100, 16, cursor).unwrap();
        wave_writer.sync_header().unwrap();
        let mut cursor = wave_writer.into_inner();

        cursor.set_position(0);

        let wave_reader = WaveReader::new(cursor).unwrap();
        let cursor = wave_reader.into_inner();
        let data = cursor.into_inner();

        assert_eq!(44, data.len());
        // We're not currently surfacing the chunk/subchunk info in the reader
        // so just access the data directly.

        // Should match 36 in little-endian format.
        assert_eq!(b"\x24\x00\x00\x00", &data[4..8]);

        // Should match 0 in little-endian format.
        assert_eq!(b"\x00\x00\x00\x00", &data[40..44]);
    }

    #[test]
    fn test_header_sync_when_ten_samples_written() {
        let data = Vec::new();
        let mut cursor = Cursor::new(data);
        let mut wave_writer = WaveWriter::new(1, 44100, 16, cursor).unwrap();

        for i in 0..10 {
            wave_writer.write_sample_i16(i as i16).unwrap();
        }

        wave_writer.sync_header().unwrap();

        let mut cursor = wave_writer.into_inner();

        cursor.set_position(0);

        let wave_reader = WaveReader::new(cursor).unwrap();
        let cursor = wave_reader.into_inner();
        let data = cursor.into_inner();

        assert_eq!(64, data.len());
        // We're not currently surfacing the chunk/subchunk info in the reader
        // so just access the data directly.

        // Should match 56 in little-endian format.
        assert_eq!(b"\x38\x00\x00\x00", &data[4..8]);

        // Should match 20 in little-endian format.
        assert_eq!(b"\x14\x00\x00\x00", &data[40..44]);
    }

    // TODO test header
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// 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.

//! # ICU number formatting support for rust
//!
//! Since 0.3.1

use {
    rust_icu_common as common, rust_icu_sys as sys,
    rust_icu_sys::versioned_function,
    rust_icu_sys::*,
    rust_icu_uloc as uloc, rust_icu_ustring as ustring,
    std::{convert::TryFrom, convert::TryInto, ptr},
};

#[derive(Debug)]
pub struct UNumberFormat {
    rep: ptr::NonNull<sys::UNumberFormat>,
}

impl Drop for UNumberFormat {
    /// Implements `unum_close`
    fn drop(&mut self) {
        unsafe { versioned_function!(unum_close)(self.rep.as_ptr()) };
    }
}

impl UNumberFormat {
    /// Implements `unum_open`, with a pattern.
    pub fn try_new_decimal_pattern_ustring(
        pattern: &ustring::UChar,
        locale: &uloc::ULoc,
    ) -> Result<UNumberFormat, common::Error> {
        UNumberFormat::try_new_style_pattern_ustring(
            sys::UNumberFormatStyle::UNUM_PATTERN_DECIMAL,
            pattern,
            locale,
        )
    }

    /// Implements `unum_open`, with rule-based formatting,
    pub fn try_new_decimal_rulebased_ustring(
        rule: &ustring::UChar,
        locale: &uloc::ULoc,
    ) -> Result<UNumberFormat, common::Error> {
        UNumberFormat::try_new_style_pattern_ustring(
            sys::UNumberFormatStyle::UNUM_PATTERN_RULEBASED,
            rule,
            locale,
        )
    }

    /// Implements `unum_open`, with style-based formatting.
    pub fn try_new_with_style(
        style: sys::UNumberFormatStyle,
        locale: &uloc::ULoc,
    ) -> Result<UNumberFormat, common::Error> {
        let rule = ustring::UChar::try_from("")?;
        assert_ne!(style, sys::UNumberFormatStyle::UNUM_PATTERN_RULEBASED);
        assert_ne!(style, sys::UNumberFormatStyle::UNUM_PATTERN_DECIMAL);
        UNumberFormat::try_new_style_pattern_ustring(style, &rule, locale)
    }

    /// Implements `unum_open`
    fn try_new_style_pattern_ustring(
        style: sys::UNumberFormatStyle,
        pattern: &ustring::UChar,
        locale: &uloc::ULoc,
    ) -> Result<UNumberFormat, common::Error> {
        let mut status = common::Error::OK_CODE;
        let mut parse = common::NO_PARSE_ERROR.clone();
        let loc = locale.as_c_str();

        // Unsafety note: all variables should be valid.
        let rep = unsafe {
            assert!(common::Error::is_ok(status));
            assert!(common::parse_ok(parse).is_ok());
            versioned_function!(unum_open)(
                style,
                pattern.as_c_ptr(),
                // Mostly OK...
                pattern.len() as i32,
                loc.as_ptr(),
                &mut parse,
                &mut status,
            )
        };
        common::Error::ok_or_warning(status)?;
        common::parse_ok(parse)?;
        assert_ne!(rep, 0 as *mut sys::UNumberFormat);
        Ok(UNumberFormat {
            rep: ptr::NonNull::new(rep).unwrap(),
        })
    }

    /// Implements `unum_clone`
    pub fn try_clone(&self) -> Result<UNumberFormat, common::Error> {
        let mut status = common::Error::OK_CODE;
        let rep = unsafe {
            assert!(common::Error::is_ok(status));
            versioned_function!(unum_clone)(self.rep.as_ptr(), &mut status)
        };
        common::Error::ok_or_warning(status)?;
        Ok(UNumberFormat {
            rep: ptr::NonNull::new(rep).unwrap(),
        })
    }

    /// Implements `unum_format`
    pub fn format(&self, number: i32) -> Result<String, common::Error> {
        let result = self.format_ustring(number)?;
        String::try_from(&result)
    }

    /// Implements `unum_format`
    // TODO: this method call is repetitive, and should probably be pulled out into a macro.
    pub fn format_ustring(&self, number: i32) -> Result<ustring::UChar, common::Error> {
        const CAPACITY: usize = 200;
        let mut status = common::Error::OK_CODE;
        let mut buf: Vec<sys::UChar> = vec![0; CAPACITY];

        let full_len: i32 = unsafe {
            assert!(common::Error::is_ok(status));
            versioned_function!(unum_format)(
                self.rep.as_ptr(),
                number,
                buf.as_mut_ptr(),
                buf.len() as i32,
                // Unsure what this field should be for.
                0 as *mut sys::UFieldPosition,
                &mut status,
            )
        };
        if status == sys::UErrorCode::U_BUFFER_OVERFLOW_ERROR
            || (common::Error::is_ok(status)
                && full_len > CAPACITY.try_into().map_err(|e| common::Error::wrapper(e))?)
        {
            assert!(full_len > 0);
            let full_len: usize = full_len.try_into().map_err(|e| common::Error::wrapper(e))?;
            buf.resize(full_len, 0);
            unsafe {
                assert!(common::Error::is_ok(status));
                versioned_function!(unum_format)(
                    self.rep.as_ptr(),
                    number,
                    buf.as_mut_ptr(),
                    buf.len() as i32,
                    0 as *mut sys::UFieldPosition,
                    &mut status,
                )
            };
        }
        common::Error::ok_or_warning(status)?;
        if full_len >= 0 {
            let full_len: usize = full_len.try_into().map_err(|e| common::Error::wrapper(e))?;
            buf.resize(full_len, 0);
        }
        Ok(ustring::UChar::from(buf))
    }
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn format_decimal_pattern_ustring() {
        struct TestCase {
            locale: &'static str,
            pattern: &'static str,
            expected: &'static str,
        };

        let tests = vec![TestCase {
            locale: "sr-RS",
            pattern: "",
            expected: "42",
        }];
        for test in tests {
            let locale = uloc::ULoc::try_from(test.locale).expect("locale exists");
            let pattern = ustring::UChar::try_from(test.pattern).expect("pattern is set");
            let fmt = crate::UNumberFormat::try_new_decimal_pattern_ustring(&pattern, &locale)
                .expect("formatter");

            let result = fmt
                .try_clone()
                .expect("clone")
                .format(42)
                .expect("format success");
            assert_eq!(test.expected, result);
        }
    }

    // TODO: find example rules.
    #[test]
    #[should_panic(expected = "U_MEMORY_ALLOCATION_ERROR")]
    fn format_decimal_rulebased_ustring() {
        struct TestCase {
            locale: &'static str,
            rule: &'static str,
            expected: &'static str,
        };

        let tests = vec![TestCase {
            locale: "sr-RS",
            rule: "",
            expected: "42",
        }];
        for test in tests {
            let locale = uloc::ULoc::try_from(test.locale).expect("locale exists");
            let pattern = ustring::UChar::try_from(test.rule).expect("pattern is set");
            let fmt = crate::UNumberFormat::try_new_decimal_rulebased_ustring(&pattern, &locale)
                .expect("formatter");

            let result = fmt
                .try_clone()
                .expect("clone")
                .format(42)
                .expect("format success");
            assert_eq!(test.expected, result);
        }
    }

    // TODO: add more, and relevant test cases.
    #[test]
    fn format_style_ustring() {
        struct TestCase {
            locale: &'static str,
            number: i32,
            style: sys::UNumberFormatStyle,
            expected: &'static str,
        };

        let tests = vec![
            TestCase {
                locale: "sr-RS",
                number: 42,
                style: sys::UNumberFormatStyle::UNUM_CURRENCY,
                expected: "42\u{a0}RSD",
            },
            TestCase {
                locale: "sr-RS",
                number: 42,
                style: sys::UNumberFormatStyle::UNUM_SPELLOUT,
                expected: "четрдесет и два",
            },
        ];
        for test in tests {
            let locale = uloc::ULoc::try_from(test.locale).expect("locale exists");
            let fmt =
                crate::UNumberFormat::try_new_with_style(test.style, &locale).expect("formatter");

            let result = fmt
                .try_clone()
                .expect("clone")
                .format(test.number)
                .expect("format success");
            assert_eq!(test.expected, result);
        }
    }
}
<commit_msg>Added `number` to all tests that had a fixed value<commit_after>// Copyright 2020 Google LLC
//
// 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.

//! # ICU number formatting support for rust
//!
//! Since 0.3.1

use {
    rust_icu_common as common, rust_icu_sys as sys,
    rust_icu_sys::versioned_function,
    rust_icu_sys::*,
    rust_icu_uloc as uloc, rust_icu_ustring as ustring,
    std::{convert::TryFrom, convert::TryInto, ptr},
};

#[derive(Debug)]
pub struct UNumberFormat {
    rep: ptr::NonNull<sys::UNumberFormat>,
}

impl Drop for UNumberFormat {
    /// Implements `unum_close`
    fn drop(&mut self) {
        unsafe { versioned_function!(unum_close)(self.rep.as_ptr()) };
    }
}

impl UNumberFormat {
    /// Implements `unum_open`, with a pattern.
    pub fn try_new_decimal_pattern_ustring(
        pattern: &ustring::UChar,
        locale: &uloc::ULoc,
    ) -> Result<UNumberFormat, common::Error> {
        UNumberFormat::try_new_style_pattern_ustring(
            sys::UNumberFormatStyle::UNUM_PATTERN_DECIMAL,
            pattern,
            locale,
        )
    }

    /// Implements `unum_open`, with rule-based formatting,
    pub fn try_new_decimal_rule_based_ustring(
        rule: &ustring::UChar,
        locale: &uloc::ULoc,
    ) -> Result<UNumberFormat, common::Error> {
        UNumberFormat::try_new_style_pattern_ustring(
            sys::UNumberFormatStyle::UNUM_PATTERN_RULEBASED,
            rule,
            locale,
        )
    }

    /// Implements `unum_open`, with style-based formatting.
    pub fn try_new_with_style(
        style: sys::UNumberFormatStyle,
        locale: &uloc::ULoc,
    ) -> Result<UNumberFormat, common::Error> {
        let rule = ustring::UChar::try_from("")?;
        assert_ne!(style, sys::UNumberFormatStyle::UNUM_PATTERN_RULEBASED);
        assert_ne!(style, sys::UNumberFormatStyle::UNUM_PATTERN_DECIMAL);
        UNumberFormat::try_new_style_pattern_ustring(style, &rule, locale)
    }

    /// Implements `unum_open`
    fn try_new_style_pattern_ustring(
        style: sys::UNumberFormatStyle,
        pattern: &ustring::UChar,
        locale: &uloc::ULoc,
    ) -> Result<UNumberFormat, common::Error> {
        let mut status = common::Error::OK_CODE;
        let mut parse = common::NO_PARSE_ERROR.clone();
        let loc = locale.as_c_str();

        // Unsafety note: all variables should be valid.
        let rep = unsafe {
            assert!(common::Error::is_ok(status));
            assert!(common::parse_ok(parse).is_ok());
            versioned_function!(unum_open)(
                style,
                pattern.as_c_ptr(),
                // Mostly OK...
                pattern.len() as i32,
                loc.as_ptr(),
                &mut parse,
                &mut status,
            )
        };
        common::Error::ok_or_warning(status)?;
        common::parse_ok(parse)?;
        assert_ne!(rep, 0 as *mut sys::UNumberFormat);
        Ok(UNumberFormat {
            rep: ptr::NonNull::new(rep).unwrap(),
        })
    }

    /// Implements `unum_clone`
    pub fn try_clone(&self) -> Result<UNumberFormat, common::Error> {
        let mut status = common::Error::OK_CODE;
        let rep = unsafe {
            assert!(common::Error::is_ok(status));
            versioned_function!(unum_clone)(self.rep.as_ptr(), &mut status)
        };
        common::Error::ok_or_warning(status)?;
        Ok(UNumberFormat {
            rep: ptr::NonNull::new(rep).unwrap(),
        })
    }

    /// Implements `unum_format`
    pub fn format(&self, number: i32) -> Result<String, common::Error> {
        let result = self.format_ustring(number)?;
        String::try_from(&result)
    }

    /// Implements `unum_format`
    // TODO: this method call is repetitive, and should probably be pulled out into a macro.
    pub fn format_ustring(&self, number: i32) -> Result<ustring::UChar, common::Error> {
        const CAPACITY: usize = 200;
        let mut status = common::Error::OK_CODE;
        let mut buf: Vec<sys::UChar> = vec![0; CAPACITY];

        let full_len: i32 = unsafe {
            assert!(common::Error::is_ok(status));
            versioned_function!(unum_format)(
                self.rep.as_ptr(),
                number,
                buf.as_mut_ptr(),
                buf.len() as i32,
                // Unsure what this field should be for.
                0 as *mut sys::UFieldPosition,
                &mut status,
            )
        };
        if status == sys::UErrorCode::U_BUFFER_OVERFLOW_ERROR
            || (common::Error::is_ok(status)
                && full_len > CAPACITY.try_into().map_err(|e| common::Error::wrapper(e))?)
        {
            assert!(full_len > 0);
            let full_len: usize = full_len.try_into().map_err(|e| common::Error::wrapper(e))?;
            buf.resize(full_len, 0);
            unsafe {
                assert!(common::Error::is_ok(status));
                versioned_function!(unum_format)(
                    self.rep.as_ptr(),
                    number,
                    buf.as_mut_ptr(),
                    buf.len() as i32,
                    0 as *mut sys::UFieldPosition,
                    &mut status,
                )
            };
        }
        common::Error::ok_or_warning(status)?;
        if full_len >= 0 {
            let full_len: usize = full_len.try_into().map_err(|e| common::Error::wrapper(e))?;
            buf.resize(full_len, 0);
        }
        Ok(ustring::UChar::from(buf))
    }
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn format_decimal_pattern_ustring() {
        struct TestCase {
            locale: &'static str,
            number: i32,
            pattern: &'static str,
            expected: &'static str,
        };

        let tests = vec![TestCase {
            locale: "sr-RS",
            number: 42,
            pattern: "",
            expected: "42",
        }];
        for test in tests {
            let locale = uloc::ULoc::try_from(test.locale).expect("locale exists");
            let pattern = ustring::UChar::try_from(test.pattern).expect("pattern is set");
            let fmt = crate::UNumberFormat::try_new_decimal_pattern_ustring(&pattern, &locale)
                .expect("formatter");

            let result = fmt
                .try_clone()
                .expect("clone")
                .format(test.number)
                .expect("format success");
            assert_eq!(test.expected, result);
        }
    }

    // TODO: find example rules.
    #[test]
    #[should_panic(expected = "U_MEMORY_ALLOCATION_ERROR")]
    fn format_decimal_rulebased_ustring() {
        struct TestCase {
            locale: &'static str,
            number: i32,
            rule: &'static str,
            expected: &'static str,
        };

        let tests = vec![TestCase {
            locale: "sr-RS",
            number: 42,
            rule: "",
            expected: "42",
        }];
        for test in tests {
            let locale = uloc::ULoc::try_from(test.locale).expect("locale exists");
            let pattern = ustring::UChar::try_from(test.rule).expect("pattern is set");
            let fmt = crate::UNumberFormat::try_new_decimal_rule_based_ustring(&pattern, &locale)
                .expect("formatter");

            let result = fmt
                .try_clone()
                .expect("clone")
                .format(test.number)
                .expect("format success");
            assert_eq!(test.expected, result);
        }
    }

    // TODO: add more, and relevant test cases.
    #[test]
    fn format_style_ustring() {
        struct TestCase {
            locale: &'static str,
            number: i32,
            style: sys::UNumberFormatStyle,
            expected: &'static str,
        };

        let tests = vec![
            TestCase {
                locale: "sr-RS",
                number: 42,
                style: sys::UNumberFormatStyle::UNUM_CURRENCY,
                expected: "42\u{a0}RSD",
            },
            TestCase {
                locale: "sr-RS",
                number: 42,
                style: sys::UNumberFormatStyle::UNUM_SPELLOUT,
                expected: "четрдесет и два",
            },
        ];
        for test in tests {
            let locale = uloc::ULoc::try_from(test.locale).expect("locale exists");
            let fmt =
                crate::UNumberFormat::try_new_with_style(test.style, &locale).expect("formatter");

            let result = fmt
                .try_clone()
                .expect("clone")
                .format(test.number)
                .expect("format success");
            assert_eq!(test.expected, result);
        }
    }
}
<|endoftext|>


<commit_before>mod pty;
mod err;

use std::ffi::CString;

use ::descriptor::Descriptor;

use self::pty::{Master, Slave};
pub use self::err::{ForkError, Result};

use ::libc;

const DEFAULT_PTMX: &'static str = "/dev/ptmx";

#[derive(Debug, Copy, Clone)]
pub enum Fork {
  // Father child's pid and master's pty.
  Father(libc::pid_t, Master),
  // Child pid 0.
  Child,
}

impl Fork {

  /// The constructor function `new` forks the program
  /// and returns the current pid.
  pub fn new (
    path: &'static str,
  ) -> Result<Self> {
    match Master::new(
      CString::new(path).ok().unwrap_or_default().as_ptr()
    ) {
      Err(cause) => Err(ForkError::BadMaster(cause)),
      Ok(master) => {
        if let Some(cause) = master.grantpt().err().or(
                             master.unlockpt().err()) {
          Err(ForkError::BadMaster(cause))
        }
        else {
          unsafe {
            match libc::fork() {
              -1 => Err(ForkError::Failure),
              0 => {
                match master.ptsname() {
                  Err(cause) => Err(ForkError::BadMaster(cause)),
                  Ok(name) => {
                    if let Some(cause) = master.close().err() {
                      Err(ForkError::BadDescriptorMaster(cause))
                    }
                    else {
                      Fork::from_pts(name)
                    }
                  },
                }
              },
              pid => Ok(Fork::Father(pid, master)),
            }
          }
        }
      },
    }
  }

  /// The constructor function `from_pts` is a private
  /// extention from the constructor function `new` who
  /// prepares and returns the child.
  fn from_pts (
    ptsname: *const ::libc::c_char,
  ) -> Result<Self> {
    unsafe {
      if libc::setsid() == -1 {
        Err(ForkError::SetsidFail)
      }
      else {
        match Slave::new(ptsname) {
          Err(cause) => Err(ForkError::BadSlave(cause)),
          Ok(slave) => {
            if let Some(cause) = slave.dup2(libc::STDIN_FILENO).err().or(
                                 slave.dup2(libc::STDOUT_FILENO).err().or(
                                 slave.dup2(libc::STDERR_FILENO).err())) {
              Err(ForkError::BadSlave(cause))
            }
            else if let Some(cause) = slave.close().err() {
              Err(ForkError::BadDescriptorSlave(cause))
            }
            else {
              Ok(Fork::Child)
            }
          },
        }
      }
    }
  }

  /// The constructor function `from_ptmx` forks the program
  /// and returns the current pid for a default PTMX's path.
  pub fn from_ptmx() -> Result<Self> {
    Fork::new(DEFAULT_PTMX)
  }

  /// Waits until it's terminated. Then closes its pty.
  pub fn wait(&self) -> Result<libc::pid_t> {
    match *self {
      Fork::Child => Err(ForkError::IsChild),
      Fork::Father(pid, _) => loop {
        unsafe {
          match libc::waitpid(pid, &mut 0, 0) {
            0 => continue ,
            -1 => return Err(ForkError::WaitpidFail),
            _ => return Ok(pid),
          }
        }
      },
    }
  }

  /// The function `is_father` returns the pid or father
  /// or none.
  pub fn is_father(&self) -> Result<Master> {
    match *self {
      Fork::Child => Err(ForkError::IsChild),
      Fork::Father(_, master) => Ok(master),
    }
  }

  /// The function `is_child` returns the pid or child
  /// or none.
  pub fn is_child(&self) -> Result<libc::pid_t> {
    match *self {
      Fork::Father(_, _) => Err(ForkError::IsFather),
      Fork::Child => Ok(0),
    }
  }
}
<commit_msg>Master type become public<commit_after>mod pty;
mod err;

use std::ffi::CString;

use ::descriptor::Descriptor;
pub use self::pty::{Master, MasterError};
use self::pty::Slave;
pub use self::err::{ForkError, Result};

use ::libc;

const DEFAULT_PTMX: &'static str = "/dev/ptmx";

#[derive(Debug, Copy, Clone)]
pub enum Fork {
  // Father child's pid and master's pty.
  Father(libc::pid_t, Master),
  // Child pid 0.
  Child,
}

impl Fork {

  /// The constructor function `new` forks the program
  /// and returns the current pid.
  pub fn new (
    path: &'static str,
  ) -> Result<Self> {
    match Master::new(
      CString::new(path).ok().unwrap_or_default().as_ptr()
    ) {
      Err(cause) => Err(ForkError::BadMaster(cause)),
      Ok(master) => {
        if let Some(cause) = master.grantpt().err().or(
                             master.unlockpt().err()) {
          Err(ForkError::BadMaster(cause))
        }
        else {
          unsafe {
            match libc::fork() {
              -1 => Err(ForkError::Failure),
              0 => {
                match master.ptsname() {
                  Err(cause) => Err(ForkError::BadMaster(cause)),
                  Ok(name) => {
                    if let Some(cause) = master.close().err() {
                      Err(ForkError::BadDescriptorMaster(cause))
                    }
                    else {
                      Fork::from_pts(name)
                    }
                  },
                }
              },
              pid => Ok(Fork::Father(pid, master)),
            }
          }
        }
      },
    }
  }

  /// The constructor function `from_pts` is a private
  /// extention from the constructor function `new` who
  /// prepares and returns the child.
  fn from_pts (
    ptsname: *const ::libc::c_char,
  ) -> Result<Self> {
    unsafe {
      if libc::setsid() == -1 {
        Err(ForkError::SetsidFail)
      }
      else {
        match Slave::new(ptsname) {
          Err(cause) => Err(ForkError::BadSlave(cause)),
          Ok(slave) => {
            if let Some(cause) = slave.dup2(libc::STDIN_FILENO).err().or(
                                 slave.dup2(libc::STDOUT_FILENO).err().or(
                                 slave.dup2(libc::STDERR_FILENO).err())) {
              Err(ForkError::BadSlave(cause))
            }
            else if let Some(cause) = slave.close().err() {
              Err(ForkError::BadDescriptorSlave(cause))
            }
            else {
              Ok(Fork::Child)
            }
          },
        }
      }
    }
  }

  /// The constructor function `from_ptmx` forks the program
  /// and returns the current pid for a default PTMX's path.
  pub fn from_ptmx() -> Result<Self> {
    Fork::new(DEFAULT_PTMX)
  }

  /// Waits until it's terminated. Then closes its pty.
  pub fn wait(&self) -> Result<libc::pid_t> {
    match *self {
      Fork::Child => Err(ForkError::IsChild),
      Fork::Father(pid, _) => loop {
        unsafe {
          match libc::waitpid(pid, &mut 0, 0) {
            0 => continue ,
            -1 => return Err(ForkError::WaitpidFail),
            _ => return Ok(pid),
          }
        }
      },
    }
  }

  /// The function `is_father` returns the pid or father
  /// or none.
  pub fn is_father(&self) -> Result<Master> {
    match *self {
      Fork::Child => Err(ForkError::IsChild),
      Fork::Father(_, master) => Ok(master),
    }
  }

  /// The function `is_child` returns the pid or child
  /// or none.
  pub fn is_child(&self) -> Result<libc::pid_t> {
    match *self {
      Fork::Father(_, _) => Err(ForkError::IsFather),
      Fork::Child => Ok(0),
    }
  }
}
<|endoftext|>


<commit_before>#[crate_id="cargo-read-manifest"];
#[allow(deprecated_owned_vector)];

extern crate cargo;
extern crate hammer;
extern crate serialize;
extern crate toml;

use hammer::{FlagDecoder,FlagConfig,FlagConfiguration};
use serialize::{Decoder,Decodable};
use serialize::json::Encoder;
use toml::from_toml;
use cargo::{Manifest,LibTarget,ExecTarget,Project,CargoResult,CargoError,ToCargoError};
use std::path::Path;

#[deriving(Decodable,Encodable,Eq,Clone,Ord)]
struct SerializedManifest {
    project: ~Project,
    lib: Option<~[SerializedLibTarget]>,
    bin: Option<~[SerializedExecTarget]>
}

#[deriving(Decodable,Encodable,Eq,Clone,Ord)]
pub struct SerializedTarget {
    name: ~str,
    path: Option<~str>
}

pub type SerializedLibTarget = SerializedTarget;
pub type SerializedExecTarget = SerializedTarget;

#[deriving(Decodable,Eq,Clone,Ord)]
struct ReadManifestFlags {
    manifest_path: ~str
}

impl FlagConfig for ReadManifestFlags {
    fn config(_: Option<ReadManifestFlags>, c: FlagConfiguration) -> FlagConfiguration {
        c
    }
}

fn main() {
    match execute() {
        Err(e) => {
            println!("{}", e.message);
            // TODO: Exit with error code
        },
        _ => return
    }
}

fn execute() -> CargoResult<()> {
    let mut decoder = FlagDecoder::new::<ReadManifestFlags>(std::os::args().tail());
    let flags: ReadManifestFlags = Decodable::decode(&mut decoder);

    if decoder.error.is_some() {
        return Err(CargoError::new(decoder.error.unwrap(), 1));
    }

    let manifest_path = flags.manifest_path;
    let root = try!(toml::parse_from_file(manifest_path.clone()).to_cargo_error(format!("Couldn't parse Toml file: {}", manifest_path), 1));

    let toml_manifest = from_toml::<SerializedManifest>(root.clone());

    let (lib, bin) = normalize(&toml_manifest.lib, &toml_manifest.bin);

    let manifest = Manifest{
        root: try!(Path::new(manifest_path.clone()).dirname_str().to_cargo_error(format!("Could not get dirname from {}", manifest_path), 1)).to_owned(),
        project: toml_manifest.project,
        lib: lib,
        bin: bin
    };

    let encoded: ~str = Encoder::str_encode(&manifest);

    println!("{}", encoded);

    Ok(())
}

fn normalize(lib: &Option<~[SerializedLibTarget]>, bin: &Option<~[SerializedExecTarget]>) -> (~[LibTarget], ~[ExecTarget]) {
    if lib.is_some() && bin.is_some() {
        let l = lib.clone().unwrap()[0];
        let mut path = l.path.clone();

        if path.is_none() {
            path = Some(format!("src/{}.rs", l.name));
        }

        let b = bin.get_ref().map(|b_ref| {
            let b = b_ref.clone();
            let mut path = b.path.clone();
            if path.is_none() {
                path = Some(format!("src/bin/{}.rs", b.name.clone()));
            }
            ExecTarget{ path: path.unwrap(), name: b.name }
        });
        (~[LibTarget{ path: path.unwrap(), name: l.name }], b)
    } else if lib.is_some() {
        let l = lib.clone().unwrap()[0];
        let mut path = l.path.clone();

        if path.is_none() {
            path = Some(format!("src/{}.rs", l.name));
        }

        (~[LibTarget{ path: path.unwrap(), name: l.name }], ~[])
    } else if bin.is_some() {
        let b = bin.get_ref().map(|b_ref| {
            let b = b_ref.clone();
            let mut path = b.path.clone();
            if path.is_none() {
                path = Some(format!("src/{}.rs", b.name.clone()));
            }
            ExecTarget{ path: path.unwrap(), name: b.name }
        });
        (~[], b)
    } else {
        (~[], ~[])
    }
}
<commit_msg>Clean up dynamic option checks<commit_after>#[crate_id="cargo-read-manifest"];
#[allow(deprecated_owned_vector)];

extern crate cargo;
extern crate hammer;
extern crate serialize;
extern crate toml;

use hammer::{FlagDecoder,FlagConfig,FlagConfiguration};
use serialize::{Decoder,Decodable};
use serialize::json::Encoder;
use toml::from_toml;
use cargo::{Manifest,LibTarget,ExecTarget,Project,CargoResult,CargoError,ToCargoError};
use std::path::Path;

#[deriving(Decodable,Encodable,Eq,Clone,Ord)]
struct SerializedManifest {
    project: ~Project,
    lib: Option<~[SerializedLibTarget]>,
    bin: Option<~[SerializedExecTarget]>
}

#[deriving(Decodable,Encodable,Eq,Clone,Ord)]
pub struct SerializedTarget {
    name: ~str,
    path: Option<~str>
}

pub type SerializedLibTarget = SerializedTarget;
pub type SerializedExecTarget = SerializedTarget;

#[deriving(Decodable,Eq,Clone,Ord)]
struct ReadManifestFlags {
    manifest_path: ~str
}

impl FlagConfig for ReadManifestFlags {
    fn config(_: Option<ReadManifestFlags>, c: FlagConfiguration) -> FlagConfiguration {
        c
    }
}

fn main() {
    match execute() {
        Err(e) => {
            println!("{}", e.message);
            // TODO: Exit with error code
        },
        _ => return
    }
}

fn execute() -> CargoResult<()> {
    let mut decoder = FlagDecoder::new::<ReadManifestFlags>(std::os::args().tail());
    let flags: ReadManifestFlags = Decodable::decode(&mut decoder);

    if decoder.error.is_some() {
        return Err(CargoError::new(decoder.error.unwrap(), 1));
    }

    let manifest_path = flags.manifest_path;
    let root = try!(toml::parse_from_file(manifest_path.clone()).to_cargo_error(format!("Couldn't parse Toml file: {}", manifest_path), 1));

    let toml_manifest = from_toml::<SerializedManifest>(root.clone());

    let (lib, bin) = normalize(&toml_manifest.lib, &toml_manifest.bin);

    let manifest = Manifest{
        root: try!(Path::new(manifest_path.clone()).dirname_str().to_cargo_error(format!("Could not get dirname from {}", manifest_path), 1)).to_owned(),
        project: toml_manifest.project,
        lib: lib,
        bin: bin
    };

    let encoded: ~str = Encoder::str_encode(&manifest);

    println!("{}", encoded);

    Ok(())
}

fn normalize(lib: &Option<~[SerializedLibTarget]>, bin: &Option<~[SerializedExecTarget]>) -> (~[LibTarget], ~[ExecTarget]) {
    fn lib_targets(libs: &[SerializedLibTarget]) -> ~[LibTarget] {
        let l = &lib[0];
        let path = l.path.clone().unwrap_or_else(|| format!("src/{}.rs", l.name));
        ~[LibTarget{ path: path, name: l.name.clone() }]
    }

    fn bin_targets(bins: &[SerializedExecTarget], default: |&SerializedExecTarget| -> ~str) -> ~[ExecTarget] {
        bins.map(|bin| {
            let path = bin.path.clone().unwrap_or_else(|| default(bin));
            ExecTarget{ path: path, name: bin.name.clone() }
        })
    }

    match (lib, bin) {
        (&Some(ref libs), &Some(ref bins)) => {
            (lib_targets(libs.as_slice()), bin_targets(bins.as_slice(), |bin| format!("src/bin/{}.rs", bin.name)))
        },
        (&Some(ref libs), &None) => {
            (lib_targets(libs.as_slice()), ~[])
        },
        (&None, &Some(ref bins)) => {
            (~[], bin_targets(bins.as_slice(), |bin| format!("src/{}.rs", bin.name)))
        },
        (&None, &None) => {
            (~[], ~[])
        }
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

//! Gecko's definition of a pseudo-element.
//!
//! Note that a few autogenerated bits of this live in
//! `pseudo_element_definition.mako.rs`. If you touch that file, you probably
//! need to update the checked-in files for Servo.

use crate::gecko_bindings::structs::{self, PseudoStyleType};
use crate::properties::longhands::display::computed_value::T as Display;
use crate::properties::{ComputedValues, PropertyFlags};
use crate::selector_parser::{PseudoElementCascadeType, SelectorImpl};
use crate::str::{starts_with_ignore_ascii_case, string_as_ascii_lowercase};
use crate::string_cache::Atom;
use crate::values::serialize_atom_identifier;
use cssparser::ToCss;
use std::fmt;
use thin_slice::ThinBoxedSlice;

include!(concat!(
    env!("OUT_DIR"),
    "/gecko/pseudo_element_definition.rs"
));

impl ::selectors::parser::PseudoElement for PseudoElement {
    type Impl = SelectorImpl;

    // ::slotted() should support all tree-abiding pseudo-elements, see
    // https://drafts.csswg.org/css-scoping/#slotted-pseudo
    // https://drafts.csswg.org/css-pseudo-4/#treelike
    #[inline]
    fn valid_after_slotted(&self) -> bool {
        matches!(
            *self,
            PseudoElement::Before |
                PseudoElement::After |
                PseudoElement::Marker |
                PseudoElement::Placeholder |
                PseudoElement::FileChooserButton
        )
    }

    #[inline]
    fn accepts_state_pseudo_classes(&self) -> bool {
        self.supports_user_action_state()
    }
}

impl PseudoElement {
    /// Returns the kind of cascade type that a given pseudo is going to use.
    ///
    /// In Gecko we only compute ::before and ::after eagerly. We save the rules
    /// for anonymous boxes separately, so we resolve them as precomputed
    /// pseudos.
    ///
    /// We resolve the others lazily, see `Servo_ResolvePseudoStyle`.
    pub fn cascade_type(&self) -> PseudoElementCascadeType {
        if self.is_eager() {
            debug_assert!(!self.is_anon_box());
            return PseudoElementCascadeType::Eager;
        }

        if self.is_precomputed() {
            return PseudoElementCascadeType::Precomputed;
        }

        PseudoElementCascadeType::Lazy
    }

    /// Whether the pseudo-element should inherit from the default computed
    /// values instead of from the parent element.
    ///
    /// This is not the common thing, but there are some pseudos (namely:
    /// ::backdrop), that shouldn't inherit from the parent element.
    pub fn inherits_from_default_values(&self) -> bool {
        matches!(*self, PseudoElement::Backdrop)
    }

    /// Gets the canonical index of this eagerly-cascaded pseudo-element.
    #[inline]
    pub fn eager_index(&self) -> usize {
        EAGER_PSEUDOS
            .iter()
            .position(|p| p == self)
            .expect("Not an eager pseudo")
    }

    /// Creates a pseudo-element from an eager index.
    #[inline]
    pub fn from_eager_index(i: usize) -> Self {
        EAGER_PSEUDOS[i].clone()
    }

    /// Whether the current pseudo element is animatable.
    #[inline]
    pub fn is_animatable(&self) -> bool {
        matches!(*self, Self::Before | Self::After | Self::Marker)
    }

    /// Whether the current pseudo element is ::before or ::after.
    #[inline]
    pub fn is_before_or_after(&self) -> bool {
        self.is_before() || self.is_after()
    }

    /// Whether this pseudo-element is the ::before pseudo.
    #[inline]
    pub fn is_before(&self) -> bool {
        *self == PseudoElement::Before
    }

    /// Whether this pseudo-element is the ::after pseudo.
    #[inline]
    pub fn is_after(&self) -> bool {
        *self == PseudoElement::After
    }

    /// Whether this pseudo-element is the ::marker pseudo.
    #[inline]
    pub fn is_marker(&self) -> bool {
        *self == PseudoElement::Marker
    }

    /// Whether this pseudo-element is the ::selection pseudo.
    #[inline]
    pub fn is_selection(&self) -> bool {
        *self == PseudoElement::Selection
    }

    /// Whether this pseudo-element is ::first-letter.
    #[inline]
    pub fn is_first_letter(&self) -> bool {
        *self == PseudoElement::FirstLetter
    }

    /// Whether this pseudo-element is ::first-line.
    #[inline]
    pub fn is_first_line(&self) -> bool {
        *self == PseudoElement::FirstLine
    }

    /// Whether this pseudo-element is the ::-moz-color-swatch pseudo.
    #[inline]
    pub fn is_color_swatch(&self) -> bool {
        *self == PseudoElement::MozColorSwatch
    }

    /// Whether this pseudo-element is lazily-cascaded.
    #[inline]
    pub fn is_lazy(&self) -> bool {
        !self.is_eager() && !self.is_precomputed()
    }

    /// Whether this pseudo-element supports user action selectors.
    pub fn supports_user_action_state(&self) -> bool {
        (self.flags() & structs::CSS_PSEUDO_ELEMENT_SUPPORTS_USER_ACTION_STATE) != 0
    }

    /// Whether this pseudo-element is enabled for all content.
    pub fn enabled_in_content(&self) -> bool {
        match *self {
            PseudoElement::MozFocusOuter => {
                static_prefs::pref!("layout.css.moz-focus-outer.enabled")
            },
            PseudoElement::FileChooserButton => {
                static_prefs::pref!("layout.css.file-chooser-button.enabled")
            },
            _ => (self.flags() & structs::CSS_PSEUDO_ELEMENT_ENABLED_IN_UA_SHEETS_AND_CHROME) == 0,
        }
    }

    /// Whether this pseudo is enabled explicitly in UA sheets.
    pub fn enabled_in_ua_sheets(&self) -> bool {
        (self.flags() & structs::CSS_PSEUDO_ELEMENT_ENABLED_IN_UA_SHEETS) != 0
    }

    /// Whether this pseudo is enabled explicitly in chrome sheets.
    pub fn enabled_in_chrome(&self) -> bool {
        (self.flags() & structs::CSS_PSEUDO_ELEMENT_ENABLED_IN_CHROME) != 0
    }

    /// Whether this pseudo-element skips flex/grid container display-based
    /// fixup.
    #[inline]
    pub fn skip_item_display_fixup(&self) -> bool {
        (self.flags() & structs::CSS_PSEUDO_ELEMENT_IS_FLEX_OR_GRID_ITEM) == 0
    }

    /// Whether this pseudo-element is precomputed.
    #[inline]
    pub fn is_precomputed(&self) -> bool {
        self.is_anon_box() && !self.is_tree_pseudo_element()
    }

    /// Property flag that properties must have to apply to this pseudo-element.
    #[inline]
    pub fn property_restriction(&self) -> Option<PropertyFlags> {
        Some(match *self {
            PseudoElement::FirstLetter => PropertyFlags::APPLIES_TO_FIRST_LETTER,
            PseudoElement::FirstLine => PropertyFlags::APPLIES_TO_FIRST_LINE,
            PseudoElement::Placeholder => PropertyFlags::APPLIES_TO_PLACEHOLDER,
            PseudoElement::Cue => PropertyFlags::APPLIES_TO_CUE,
            PseudoElement::Marker if static_prefs::pref!("layout.css.marker.restricted") => {
                PropertyFlags::APPLIES_TO_MARKER
            },
            _ => return None,
        })
    }

    /// Whether this pseudo-element should actually exist if it has
    /// the given styles.
    pub fn should_exist(&self, style: &ComputedValues) -> bool {
        debug_assert!(self.is_eager());

        if style.get_box().clone_display() == Display::None {
            return false;
        }

        if self.is_before_or_after() && style.ineffective_content_property() {
            return false;
        }

        true
    }
}
<commit_msg>style: Rename ::file-chooser-button to ::file-selector-button, and enable it in all channels.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

//! Gecko's definition of a pseudo-element.
//!
//! Note that a few autogenerated bits of this live in
//! `pseudo_element_definition.mako.rs`. If you touch that file, you probably
//! need to update the checked-in files for Servo.

use crate::gecko_bindings::structs::{self, PseudoStyleType};
use crate::properties::longhands::display::computed_value::T as Display;
use crate::properties::{ComputedValues, PropertyFlags};
use crate::selector_parser::{PseudoElementCascadeType, SelectorImpl};
use crate::str::{starts_with_ignore_ascii_case, string_as_ascii_lowercase};
use crate::string_cache::Atom;
use crate::values::serialize_atom_identifier;
use cssparser::ToCss;
use std::fmt;
use thin_slice::ThinBoxedSlice;

include!(concat!(
    env!("OUT_DIR"),
    "/gecko/pseudo_element_definition.rs"
));

impl ::selectors::parser::PseudoElement for PseudoElement {
    type Impl = SelectorImpl;

    // ::slotted() should support all tree-abiding pseudo-elements, see
    // https://drafts.csswg.org/css-scoping/#slotted-pseudo
    // https://drafts.csswg.org/css-pseudo-4/#treelike
    #[inline]
    fn valid_after_slotted(&self) -> bool {
        matches!(
            *self,
            PseudoElement::Before |
                PseudoElement::After |
                PseudoElement::Marker |
                PseudoElement::Placeholder |
                PseudoElement::FileSelectorButton
        )
    }

    #[inline]
    fn accepts_state_pseudo_classes(&self) -> bool {
        self.supports_user_action_state()
    }
}

impl PseudoElement {
    /// Returns the kind of cascade type that a given pseudo is going to use.
    ///
    /// In Gecko we only compute ::before and ::after eagerly. We save the rules
    /// for anonymous boxes separately, so we resolve them as precomputed
    /// pseudos.
    ///
    /// We resolve the others lazily, see `Servo_ResolvePseudoStyle`.
    pub fn cascade_type(&self) -> PseudoElementCascadeType {
        if self.is_eager() {
            debug_assert!(!self.is_anon_box());
            return PseudoElementCascadeType::Eager;
        }

        if self.is_precomputed() {
            return PseudoElementCascadeType::Precomputed;
        }

        PseudoElementCascadeType::Lazy
    }

    /// Whether the pseudo-element should inherit from the default computed
    /// values instead of from the parent element.
    ///
    /// This is not the common thing, but there are some pseudos (namely:
    /// ::backdrop), that shouldn't inherit from the parent element.
    pub fn inherits_from_default_values(&self) -> bool {
        matches!(*self, PseudoElement::Backdrop)
    }

    /// Gets the canonical index of this eagerly-cascaded pseudo-element.
    #[inline]
    pub fn eager_index(&self) -> usize {
        EAGER_PSEUDOS
            .iter()
            .position(|p| p == self)
            .expect("Not an eager pseudo")
    }

    /// Creates a pseudo-element from an eager index.
    #[inline]
    pub fn from_eager_index(i: usize) -> Self {
        EAGER_PSEUDOS[i].clone()
    }

    /// Whether the current pseudo element is animatable.
    #[inline]
    pub fn is_animatable(&self) -> bool {
        matches!(*self, Self::Before | Self::After | Self::Marker)
    }

    /// Whether the current pseudo element is ::before or ::after.
    #[inline]
    pub fn is_before_or_after(&self) -> bool {
        self.is_before() || self.is_after()
    }

    /// Whether this pseudo-element is the ::before pseudo.
    #[inline]
    pub fn is_before(&self) -> bool {
        *self == PseudoElement::Before
    }

    /// Whether this pseudo-element is the ::after pseudo.
    #[inline]
    pub fn is_after(&self) -> bool {
        *self == PseudoElement::After
    }

    /// Whether this pseudo-element is the ::marker pseudo.
    #[inline]
    pub fn is_marker(&self) -> bool {
        *self == PseudoElement::Marker
    }

    /// Whether this pseudo-element is the ::selection pseudo.
    #[inline]
    pub fn is_selection(&self) -> bool {
        *self == PseudoElement::Selection
    }

    /// Whether this pseudo-element is ::first-letter.
    #[inline]
    pub fn is_first_letter(&self) -> bool {
        *self == PseudoElement::FirstLetter
    }

    /// Whether this pseudo-element is ::first-line.
    #[inline]
    pub fn is_first_line(&self) -> bool {
        *self == PseudoElement::FirstLine
    }

    /// Whether this pseudo-element is the ::-moz-color-swatch pseudo.
    #[inline]
    pub fn is_color_swatch(&self) -> bool {
        *self == PseudoElement::MozColorSwatch
    }

    /// Whether this pseudo-element is lazily-cascaded.
    #[inline]
    pub fn is_lazy(&self) -> bool {
        !self.is_eager() && !self.is_precomputed()
    }

    /// Whether this pseudo-element supports user action selectors.
    pub fn supports_user_action_state(&self) -> bool {
        (self.flags() & structs::CSS_PSEUDO_ELEMENT_SUPPORTS_USER_ACTION_STATE) != 0
    }

    /// Whether this pseudo-element is enabled for all content.
    pub fn enabled_in_content(&self) -> bool {
        match *self {
            PseudoElement::MozFocusOuter => {
                static_prefs::pref!("layout.css.moz-focus-outer.enabled")
            },
            PseudoElement::FileSelectorButton => {
                static_prefs::pref!("layout.css.file-selector-button.enabled")
            },
            _ => (self.flags() & structs::CSS_PSEUDO_ELEMENT_ENABLED_IN_UA_SHEETS_AND_CHROME) == 0,
        }
    }

    /// Whether this pseudo is enabled explicitly in UA sheets.
    pub fn enabled_in_ua_sheets(&self) -> bool {
        (self.flags() & structs::CSS_PSEUDO_ELEMENT_ENABLED_IN_UA_SHEETS) != 0
    }

    /// Whether this pseudo is enabled explicitly in chrome sheets.
    pub fn enabled_in_chrome(&self) -> bool {
        (self.flags() & structs::CSS_PSEUDO_ELEMENT_ENABLED_IN_CHROME) != 0
    }

    /// Whether this pseudo-element skips flex/grid container display-based
    /// fixup.
    #[inline]
    pub fn skip_item_display_fixup(&self) -> bool {
        (self.flags() & structs::CSS_PSEUDO_ELEMENT_IS_FLEX_OR_GRID_ITEM) == 0
    }

    /// Whether this pseudo-element is precomputed.
    #[inline]
    pub fn is_precomputed(&self) -> bool {
        self.is_anon_box() && !self.is_tree_pseudo_element()
    }

    /// Property flag that properties must have to apply to this pseudo-element.
    #[inline]
    pub fn property_restriction(&self) -> Option<PropertyFlags> {
        Some(match *self {
            PseudoElement::FirstLetter => PropertyFlags::APPLIES_TO_FIRST_LETTER,
            PseudoElement::FirstLine => PropertyFlags::APPLIES_TO_FIRST_LINE,
            PseudoElement::Placeholder => PropertyFlags::APPLIES_TO_PLACEHOLDER,
            PseudoElement::Cue => PropertyFlags::APPLIES_TO_CUE,
            PseudoElement::Marker if static_prefs::pref!("layout.css.marker.restricted") => {
                PropertyFlags::APPLIES_TO_MARKER
            },
            _ => return None,
        })
    }

    /// Whether this pseudo-element should actually exist if it has
    /// the given styles.
    pub fn should_exist(&self, style: &ComputedValues) -> bool {
        debug_assert!(self.is_eager());

        if style.get_box().clone_display() == Display::None {
            return false;
        }

        if self.is_before_or_after() && style.ineffective_content_property() {
            return false;
        }

        true
    }
}
<|endoftext|>


<commit_before>extern crate crypto;

use std::fs::File;
use std::io::{BufReader, BufRead};

use crypto::aessafe::AesSafe128Encryptor;
use crypto::symmetriccipher::BlockEncryptor;

fn hex_to_u8(a: u8) -> u8 {
    match a {
        b'0'...b'9' => a - b'0',
        b'a'...b'h' => a - b'a' + 10,
        _           => 0
    }
}

fn vec_u8_from_hex_string(s: &String) -> Vec<u8> {
    s.as_bytes().chunks(2).map(|a| hex_to_u8(a[0]) * 16 + hex_to_u8(a[1])).collect()
}

fn u8_slice_inc(v: &mut [u8]) {
    let mut inc = 1;

    for i in (0..v.len()).rev() {
        if v[i] == 0xff && inc == 1 {
            v[i] = 0;
            inc = 1;
        } else {
            v[i] += inc;
            inc = 0;
        }
    }
}

fn ctr_decrypt(key: &Vec<u8>, msg: &Vec<u8>) -> Vec<u8> {
    let mut v = Vec::with_capacity(msg.len());
    let (iv, msg) = msg.split_at(16);
    // TODO: find better way to copy arrays
    let mut prev = &mut [0; 16];

    for i in 0..16 {
        prev[i] = iv[i];
    }

    let mut m_i = &mut [0; 16];
    let encryptor = AesSafe128Encryptor::new(&key[..]);

    for c_i in msg.chunks(16) {
        encryptor.encrypt_block(prev, &mut m_i[..]);

        for i in 0..c_i.len() {
            v.push(c_i[i] ^ m_i[i]);
        }

        u8_slice_inc(prev);
    }

    v
}

fn main() {
    let input_file = File::open("in.txt").unwrap();
    let input = BufReader::new(input_file);
    let input: Vec<_> = input.lines().filter_map(|res| res.ok())
        .filter(|s| s.len() > 0)
        .map(|s| vec_u8_from_hex_string(&s))
        .collect();
    let input: Vec<_> = input.chunks(2).collect();

    for v in input {
        println!("key: {:?}", v[0]);
        println!("cpt: {:?}", v[1]);

        let msg = ctr_decrypt(&v[0], &v[1]);
        println!("msg: {:?}", msg);

        let pt = String::from_utf8(msg).unwrap();
        println!("pt: {:?}", pt);

        println!("");
    }
}

<commit_msg>ctr mode encrypt<commit_after>extern crate crypto;

use std::fs::File;
use std::io::{BufReader, BufRead};

use crypto::aessafe::AesSafe128Encryptor;
use crypto::symmetriccipher::BlockEncryptor;

fn hex_to_u8(a: u8) -> u8 {
    match a {
        b'0'...b'9' => a - b'0',
        b'a'...b'h' => a - b'a' + 10,
        _           => 0
    }
}

fn u8_to_hex(a: u8) -> u8 {
    match a {
        0...9   => a + b'0',
        10...15 => a + b'a' - 10,
        _       => 0
    }
}

fn vec_u8_from_hex_string(s: &String) -> Vec<u8> {
    s.as_bytes().chunks(2).map(|a| hex_to_u8(a[0]) * 16 + hex_to_u8(a[1])).collect()
}

fn vec_u8_to_hex_string(v: &Vec<u8>) -> String {
    v.iter().map(|u| [u8_to_hex(u / 16), u8_to_hex(u % 16)])
        .fold(String::from(""), |mut acc, item| {acc.push(item[0] as char); acc.push(item[1] as char); acc})
}

fn u8_slice_inc(v: &mut [u8]) {
    let mut inc = 1;

    for i in (0..v.len()).rev() {
        if v[i] == 0xff && inc == 1 {
            v[i] = 0;
            inc = 1;
        } else {
            v[i] += inc;
            inc = 0;
        }
    }
}

fn ctr_crypt(key: &[u8], iv: &[u8], msg: &[u8]) -> Vec<u8> {
    let mut v = Vec::with_capacity(msg.len());
    // TODO: find better way to copy arrays
    let mut prev = &mut [0; 16];

    for i in 0..16 {
        prev[i] = iv[i];
    }

    let mut m_i = &mut [0; 16];
    let encryptor = AesSafe128Encryptor::new(key);

    for c_i in msg.chunks(16) {
        encryptor.encrypt_block(prev, &mut m_i[..]);

        for i in 0..c_i.len() {
            v.push(c_i[i] ^ m_i[i]);
        }

        u8_slice_inc(prev);
    }

    v
}

fn ctr_decrypt(key: &Vec<u8>, msg: &Vec<u8>) -> Vec<u8> {
    let (iv, msg) = msg.split_at(16);
    ctr_crypt(&key[..], iv, &msg[..])
}

fn ctr_encrypt(key: &Vec<u8>, iv: &Vec<u8>, msg: &Vec<u8>) -> Vec<u8> {
    let mut v = Vec::with_capacity(iv.len() + msg.len());
    v.extend(iv.iter().cloned());
    v.extend(ctr_crypt(&key[..], &iv[..], &msg[..]));
    v
}

fn main() {
    // decode
    let input_file = File::open("in.txt").unwrap();
    let input = BufReader::new(input_file);
    let input: Vec<_> = input.lines().filter_map(|res| res.ok())
        .filter(|s| s.len() > 0)
        .map(|s| vec_u8_from_hex_string(&s))
        .collect();
    let input: Vec<_> = input.chunks(2).collect();

    for v in input {
        println!("key: {:?}", v[0]);
        println!("cpt: {:?}", v[1]);

        let msg = ctr_decrypt(&v[0], &v[1]);
        println!("msg: {:?}", msg);

        let pt = String::from_utf8(msg).unwrap();
        println!("pt: {:?}", pt);

        println!("");
    }

    // encode
    let input_file = File::open("in_clear.txt").unwrap();
    let input = BufReader::new(input_file);
    let input: Vec<_> = input.lines().filter_map(|res| res.ok())
        .filter(|s| s.len() > 0)
        .collect();
    let input: Vec<_> = input.chunks(3).collect();

    for v in input {
        let key = vec_u8_from_hex_string(&v[0]);
        let iv = vec_u8_from_hex_string(&v[1]);
        let pt = &v[2];

        println!("key: {:?}", key);
        println!("IV: {:?}", iv);
        println!("pt: {:?}", pt);

        let ct = ctr_encrypt(&key, &iv, &pt.as_bytes().iter().cloned().collect());
        println!("msg: {:?}", ct);

        let hex = vec_u8_to_hex_string(&ct);
        println!("ct: {:?}", hex);

        println!("");
    }
}

<|endoftext|>