<commit_before>// Copyright (c) 2019, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

use std::sync::Arc;

use libfuzzer_sys::arbitrary::{Arbitrary, Error, Unstructured};

use crate::prelude::*;

// Adding new fuzz targets
//
// 1. Add a function to this file which looks like this:
//
//    pub fn fuzz_something(data: Data) {
//      // Invoke everything you need.
//      //
//      // Your function may accept a value of any type that implements
//      // Arbitrary [1]. This is how fuzzer affects the execution—by
//      // feeding in different bytes, which result in different
//      // arbitrary values being generated.
//      // [1]: https://docs.rs/arbitrary/0.3.3/arbitrary/trait.Arbitrary.html
//      //
//      // Derive Debug for the structures you create with arbitrary data.
//    }
//
// 2. cargo fuzz add something
// 3. Copy the contents of any other .rs file from fuzz/fuzz_targets/ into the
//    newly created fuzz/fuzz_targets/something.rs and change the function
//    being called to fuzz_something.
//
// Now you can fuzz the new target with cargo fuzz.

#[derive(Debug)]
pub struct ArbitraryConfig {
  config: Config,
}

impl Arbitrary for ArbitraryConfig {
  fn arbitrary(u: &mut Unstructured<'_>) -> Result<Self, Error> {
    let mut enc = EncoderConfig::with_speed_preset(Arbitrary::arbitrary(u)?);
    enc.width = Arbitrary::arbitrary(u)?;
    enc.height = Arbitrary::arbitrary(u)?;
    enc.bit_depth = u.int_in_range(0..=16)?;
    enc.still_picture = Arbitrary::arbitrary(u)?;
    enc.time_base =
      Rational::new(Arbitrary::arbitrary(u)?, Arbitrary::arbitrary(u)?);
    enc.min_key_frame_interval = Arbitrary::arbitrary(u)?;
    enc.max_key_frame_interval = Arbitrary::arbitrary(u)?;
    enc.reservoir_frame_delay = Arbitrary::arbitrary(u)?;
    enc.low_latency = Arbitrary::arbitrary(u)?;
    enc.quantizer = Arbitrary::arbitrary(u)?;
    enc.min_quantizer = Arbitrary::arbitrary(u)?;
    enc.bitrate = Arbitrary::arbitrary(u)?;
    enc.tile_cols = Arbitrary::arbitrary(u)?;
    enc.tile_rows = Arbitrary::arbitrary(u)?;
    enc.tiles = Arbitrary::arbitrary(u)?;
    enc.rdo_lookahead_frames = Arbitrary::arbitrary(u)?;
    let config = Config::new().with_encoder_config(enc).with_threads(1);
    Ok(Self { config })
  }
}

pub fn fuzz_construct_context(arbitrary: ArbitraryConfig) {
  let _: Result<Context<u16>, _> = arbitrary.config.new_context();
}

fn encode_frames(
  ctx: &mut Context<u8>, mut frames: impl Iterator<Item = Frame<u8>>,
) -> Result<(), EncoderStatus> {
  loop {
    let rv = ctx.receive_packet();
    debug!("ctx.receive_packet() = {:#?}", rv);

    match rv {
      Ok(_packet) => {}
      Err(EncoderStatus::Encoded) => {}
      Err(EncoderStatus::LimitReached) => {
        break;
      }
      Err(EncoderStatus::NeedMoreData) => {
        ctx.send_frame(frames.next().map(Arc::new))?;
      }
      Err(EncoderStatus::EnoughData) => {
        unreachable!();
      }
      Err(EncoderStatus::NotReady) => {
        unreachable!();
      }
      Err(EncoderStatus::Failure) => {
        return Err(EncoderStatus::Failure);
      }
    }
  }

  Ok(())
}

#[derive(Debug)]
pub struct ArbitraryEncoder {
  config: Config,
  frame_count: u8,
  pixels: Box<[u8]>,
}

impl Arbitrary for ArbitraryEncoder {
  fn arbitrary(u: &mut Unstructured<'_>) -> Result<Self, Error> {
    let mut enc = EncoderConfig::with_speed_preset(10);
    enc.width = u.int_in_range(1..=256)?;
    enc.height = u.int_in_range(1..=256)?;
    enc.still_picture = Arbitrary::arbitrary(u)?;
    enc.time_base =
      Rational::new(Arbitrary::arbitrary(u)?, Arbitrary::arbitrary(u)?);
    enc.min_key_frame_interval = u.int_in_range(0..=3)?;
    enc.max_key_frame_interval = u.int_in_range(1..=4)?;
    enc.low_latency = Arbitrary::arbitrary(u)?;
    enc.quantizer = Arbitrary::arbitrary(u)?;
    enc.min_quantizer = Arbitrary::arbitrary(u)?;
    enc.bitrate = Arbitrary::arbitrary(u)?;
    // enc.tile_cols = Arbitrary::arbitrary(u)?;
    // enc.tile_rows = Arbitrary::arbitrary(u)?;
    // enc.tiles = Arbitrary::arbitrary(u)?;
    enc.rdo_lookahead_frames = Arbitrary::arbitrary(u)?;
    let frame_count = u.int_in_range(1..=3)?;
    if u.is_empty() {
      return Err(Error::NotEnoughData);
    }
    let pixels = u.get_bytes(u.len())?.to_vec().into_boxed_slice();
    let config = Config::new().with_encoder_config(enc).with_threads(1);
    Ok(Self { config, frame_count, pixels })
  }
}

pub fn fuzz_encode(arbitrary: ArbitraryEncoder) {
  let res = arbitrary.config.new_context();
  if res.is_err() {
    return;
  }
  let mut context: Context<u8> = res.unwrap();

  let mut pixels = arbitrary.pixels.iter().cycle();
  let mut frame = context.new_frame();
  let frames = (0..arbitrary.frame_count).map(|_| {
    for plane in &mut frame.planes {
      let stride = plane.cfg.stride;
      for row in plane.data_origin_mut().chunks_mut(stride) {
        for pixel in row {
          *pixel = *pixels.next().unwrap();
        }
      }
    }

    frame.clone()
  });

  let _ = encode_frames(&mut context, frames);
}

#[derive(Debug)]
pub struct DecodeTestParameters {
  w: usize,
  h: usize,
  speed: usize,
  q: usize,
  limit: usize,
  bit_depth: usize,
  chroma_sampling: ChromaSampling,
  min_keyint: u64,
  max_keyint: u64,
  switch_frame_interval: u64,
  low_latency: bool,
  error_resilient: bool,
  bitrate: i32,
  tile_cols_log2: usize,
  tile_rows_log2: usize,
  still_picture: bool,
}

impl Arbitrary for DecodeTestParameters {
  fn arbitrary(u: &mut Unstructured<'_>) -> Result<Self, Error> {
    let mut p = Self {
      w: u.int_in_range(16..=16 + 255)?,
      h: u.int_in_range(16..=16 + 255)?,
      speed: u.int_in_range(0..=10)?,
      q: u8::arbitrary(u)?.into(),
      limit: u.int_in_range(1..=3)?,
      bit_depth: 8,
      chroma_sampling: *u.choose(&[
        ChromaSampling::Cs420,
        ChromaSampling::Cs422,
        ChromaSampling::Cs444,
        ChromaSampling::Cs400,
      ])?,
      min_keyint: u.int_in_range(0..=3)?,
      max_keyint: u.int_in_range(1..=4)?,
      switch_frame_interval: 0,
      low_latency: bool::arbitrary(u)?,
      error_resilient: bool::arbitrary(u)?,
      bitrate: u16::arbitrary(u)?.into(),
      tile_cols_log2: u.int_in_range(0..=2)?,
      tile_rows_log2: u.int_in_range(0..=2)?,
      still_picture: bool::arbitrary(u)?,
    };
    if p.still_picture {
      p.limit = 1
    }
    Ok(p)
  }
}

#[cfg(feature = "decode_test_dav1d")]
pub fn fuzz_encode_decode(p: DecodeTestParameters) {
  use crate::test_encode_decode::*;

  let mut dec = get_decoder::<u8>("dav1d", p.w, p.h);
  dec.encode_decode(
    p.w,
    p.h,
    p.speed,
    p.q,
    p.limit,
    p.bit_depth,
    p.chroma_sampling,
    p.min_keyint,
    p.max_keyint,
    p.switch_frame_interval,
    p.low_latency,
    p.error_resilient,
    p.bitrate,
    p.tile_cols_log2,
    p.tile_rows_log2,
    p.still_picture,
  );
}
<commit_msg>fuzz: Increase coverage of encode<commit_after>// Copyright (c) 2019, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

use std::sync::Arc;

use libfuzzer_sys::arbitrary::{Arbitrary, Error, Unstructured};

use crate::prelude::*;

// Adding new fuzz targets
//
// 1. Add a function to this file which looks like this:
//
//    pub fn fuzz_something(data: Data) {
//      // Invoke everything you need.
//      //
//      // Your function may accept a value of any type that implements
//      // Arbitrary [1]. This is how fuzzer affects the execution—by
//      // feeding in different bytes, which result in different
//      // arbitrary values being generated.
//      // [1]: https://docs.rs/arbitrary/0.3.3/arbitrary/trait.Arbitrary.html
//      //
//      // Derive Debug for the structures you create with arbitrary data.
//    }
//
// 2. cargo fuzz add something
// 3. Copy the contents of any other .rs file from fuzz/fuzz_targets/ into the
//    newly created fuzz/fuzz_targets/something.rs and change the function
//    being called to fuzz_something.
//
// Now you can fuzz the new target with cargo fuzz.

#[derive(Debug)]
pub struct ArbitraryConfig {
  config: Config,
}

#[inline]
fn arbitrary_rational(u: &mut Unstructured<'_>) -> Result<Rational, Error> {
  Ok(Rational::new(Arbitrary::arbitrary(u)?, Arbitrary::arbitrary(u)?))
}

impl Arbitrary for ArbitraryConfig {
  fn arbitrary(u: &mut Unstructured<'_>) -> Result<Self, Error> {
    let mut enc = EncoderConfig::with_speed_preset(Arbitrary::arbitrary(u)?);
    enc.width = Arbitrary::arbitrary(u)?;
    enc.height = Arbitrary::arbitrary(u)?;
    enc.bit_depth = u.int_in_range(0..=16)?;
    enc.still_picture = Arbitrary::arbitrary(u)?;
    enc.time_base = arbitrary_rational(u)?;
    enc.min_key_frame_interval = Arbitrary::arbitrary(u)?;
    enc.max_key_frame_interval = Arbitrary::arbitrary(u)?;
    enc.reservoir_frame_delay = Arbitrary::arbitrary(u)?;
    enc.low_latency = Arbitrary::arbitrary(u)?;
    enc.quantizer = Arbitrary::arbitrary(u)?;
    enc.min_quantizer = Arbitrary::arbitrary(u)?;
    enc.bitrate = Arbitrary::arbitrary(u)?;
    enc.tile_cols = Arbitrary::arbitrary(u)?;
    enc.tile_rows = Arbitrary::arbitrary(u)?;
    enc.tiles = Arbitrary::arbitrary(u)?;
    enc.rdo_lookahead_frames = Arbitrary::arbitrary(u)?;
    let config = Config::new().with_encoder_config(enc).with_threads(1);
    Ok(Self { config })
  }
}

pub fn fuzz_construct_context(arbitrary: ArbitraryConfig) {
  let _: Result<Context<u16>, _> = arbitrary.config.new_context();
}

fn encode_frames(
  ctx: &mut Context<u8>, mut frames: impl Iterator<Item = Frame<u8>>,
) -> Result<(), EncoderStatus> {
  loop {
    let rv = ctx.receive_packet();
    debug!("ctx.receive_packet() = {:#?}", rv);

    match rv {
      Ok(_packet) => {}
      Err(EncoderStatus::Encoded) => {}
      Err(EncoderStatus::LimitReached) => {
        break;
      }
      Err(EncoderStatus::NeedMoreData) => {
        ctx.send_frame(frames.next().map(Arc::new))?;
      }
      Err(EncoderStatus::EnoughData) => {
        unreachable!();
      }
      Err(EncoderStatus::NotReady) => {
        unreachable!();
      }
      Err(EncoderStatus::Failure) => {
        return Err(EncoderStatus::Failure);
      }
    }
  }

  Ok(())
}

#[derive(Debug)]
pub struct ArbitraryEncoder {
  config: Config,
  frame_count: u8,
  pixels: Box<[u8]>,
}

impl Arbitrary for ArbitraryEncoder {
  fn arbitrary(u: &mut Unstructured<'_>) -> Result<Self, Error> {
    let mut enc = EncoderConfig::with_speed_preset(u.int_in_range(0..=10)?);
    enc.width = u.int_in_range(1..=256)?;
    enc.height = u.int_in_range(1..=256)?;
    enc.still_picture = Arbitrary::arbitrary(u)?;
    enc.time_base = arbitrary_rational(u)?;
    enc.min_key_frame_interval = u.int_in_range(0..=3)?;
    enc.max_key_frame_interval = u.int_in_range(1..=4)?;
    enc.low_latency = Arbitrary::arbitrary(u)?;
    enc.quantizer = Arbitrary::arbitrary(u)?;
    enc.min_quantizer = Arbitrary::arbitrary(u)?;
    enc.bitrate = Arbitrary::arbitrary(u)?;
    enc.tile_cols = u.int_in_range(0..=2)?;
    enc.tile_rows = u.int_in_range(0..=2)?;
    enc.tiles = u.int_in_range(0..=16)?;
    enc.rdo_lookahead_frames = Arbitrary::arbitrary(u)?;

    enc.chroma_sampling = *u.choose(&[
      ChromaSampling::Cs420,
      ChromaSampling::Cs422,
      ChromaSampling::Cs444,
      ChromaSampling::Cs400,
    ])?;
    enc.chroma_sample_position = *u.choose(&[
      ChromaSamplePosition::Unknown,
      ChromaSamplePosition::Vertical,
      ChromaSamplePosition::Colocated,
    ])?;
    enc.pixel_range = *u.choose(&[PixelRange::Limited, PixelRange::Full])?;
    enc.error_resilient = Arbitrary::arbitrary(u)?;
    enc.reservoir_frame_delay = Arbitrary::arbitrary(u)?;

    let frame_count =
      if enc.still_picture { 1 } else { u.int_in_range(1..=3)? };
    if u.is_empty() {
      return Err(Error::NotEnoughData);
    }
    let pixels = u.get_bytes(u.len())?.to_vec().into_boxed_slice();
    let config = Config::new().with_encoder_config(enc).with_threads(1);
    Ok(Self { config, frame_count, pixels })
  }
}

pub fn fuzz_encode(arbitrary: ArbitraryEncoder) {
  let res = arbitrary.config.new_context();
  if res.is_err() {
    return;
  }
  let mut context: Context<u8> = res.unwrap();

  let mut pixels = arbitrary.pixels.iter().cycle();
  let mut frame = context.new_frame();
  let frames = (0..arbitrary.frame_count).map(|_| {
    for plane in &mut frame.planes {
      let stride = plane.cfg.stride;
      for row in plane.data_origin_mut().chunks_mut(stride) {
        for pixel in row {
          *pixel = *pixels.next().unwrap();
        }
      }
    }

    frame.clone()
  });

  let _ = encode_frames(&mut context, frames);
}

#[derive(Debug)]
pub struct DecodeTestParameters {
  w: usize,
  h: usize,
  speed: usize,
  q: usize,
  limit: usize,
  bit_depth: usize,
  chroma_sampling: ChromaSampling,
  min_keyint: u64,
  max_keyint: u64,
  switch_frame_interval: u64,
  low_latency: bool,
  error_resilient: bool,
  bitrate: i32,
  tile_cols_log2: usize,
  tile_rows_log2: usize,
  still_picture: bool,
}

impl Arbitrary for DecodeTestParameters {
  fn arbitrary(u: &mut Unstructured<'_>) -> Result<Self, Error> {
    let mut p = Self {
      w: u.int_in_range(16..=16 + 255)?,
      h: u.int_in_range(16..=16 + 255)?,
      speed: u.int_in_range(0..=10)?,
      q: u8::arbitrary(u)?.into(),
      limit: u.int_in_range(1..=3)?,
      bit_depth: 8,
      chroma_sampling: *u.choose(&[
        ChromaSampling::Cs420,
        ChromaSampling::Cs422,
        ChromaSampling::Cs444,
        ChromaSampling::Cs400,
      ])?,
      min_keyint: u.int_in_range(0..=3)?,
      max_keyint: u.int_in_range(1..=4)?,
      switch_frame_interval: 0,
      low_latency: bool::arbitrary(u)?,
      error_resilient: bool::arbitrary(u)?,
      bitrate: u16::arbitrary(u)?.into(),
      tile_cols_log2: u.int_in_range(0..=2)?,
      tile_rows_log2: u.int_in_range(0..=2)?,
      still_picture: bool::arbitrary(u)?,
    };
    if p.still_picture {
      p.limit = 1
    }
    Ok(p)
  }
}

#[cfg(feature = "decode_test_dav1d")]
pub fn fuzz_encode_decode(p: DecodeTestParameters) {
  use crate::test_encode_decode::*;

  let mut dec = get_decoder::<u8>("dav1d", p.w, p.h);
  dec.encode_decode(
    p.w,
    p.h,
    p.speed,
    p.q,
    p.limit,
    p.bit_depth,
    p.chroma_sampling,
    p.min_keyint,
    p.max_keyint,
    p.switch_frame_interval,
    p.low_latency,
    p.error_resilient,
    p.bitrate,
    p.tile_cols_log2,
    p.tile_rows_log2,
    p.still_picture,
  );
}
<|endoftext|>


<commit_before>extern crate av_data;
extern crate av_format;
extern crate circular;
extern crate matroska;
extern crate nom;
extern crate pretty_env_logger;

use circular::Buffer;
use nom::{Err, Offset};
use std::env;
use std::fs::File;
use std::io::Read;

use matroska::ebml::ebml_header;
use matroska::elements::{segment, segment_element, SegmentElement};
use matroska::serializer::ebml::EbmlSize;

fn main() {
    better_panic::install();
    pretty_env_logger::init();
    let mut args = env::args();
    let _ = args.next().expect("first arg is program path");
    let filename = args.next().expect("expected file path");

    //println!("filename: {}", filename);
    run(&filename).expect("should parse file correctly");
}

fn run(filename: &str) -> std::io::Result<()> {
    let mut file = File::open(filename)?;

    let capacity = 5242880;
    let mut b = Buffer::with_capacity(capacity);

    // we write into the `&mut[u8]` returned by `space()`
    let sz = file.read(b.space()).expect("should write");
    b.fill(sz);
    //eprintln!("write {:#?}", sz);

    let length = {
        let res = ebml_header(b.data());
        if let Ok((remaining, header)) = res {
            //eprintln!("parsed header: {:#?}", h);
            println!("+ EBML head");
            println!("|+ EBML version: {}", header.version);
            println!("|+ EBML read version: {}", header.read_version);
            println!("|+ EBML maximum ID length: {}", header.max_id_length);
            println!("|+ EBML maximum size length: {}", header.max_size_length);
            println!("|+ Doc type: {}", header.doc_type);
            println!("|+ Doc type read version: {}", header.doc_type_read_version);

            b.data().offset(remaining)
        } else {
            panic!("couldn't parse header");
        }
    };

    let mut _consumed = length;
    b.consume(length);

    let length = {
        let res = segment(b.data());
        if let Ok((remaining, segment)) = res {
            //eprintln!("parsed segment: {:#?}", h);
            println!("+ Segment, size {}", segment.1.unwrap_or(0));

            b.data().offset(remaining)
        } else {
            panic!("couldn't parse header");
        }
    };

    b.consume(length);

    // handle first elements
    let mut seek_head = None;
    let mut info = None;
    let mut tracks = None;

    loop {
        if seek_head.is_some() && info.is_some() && tracks.is_some() {
            break;
        }

        if b.available_space() == 0 {
            b.shift();
            if b.available_space() == 0 {
                println!("buffer is already full,  cannot refill");
                break;
            }
        }

        // refill the buffer
        let sz = file.read(b.space()).expect("should read");
        b.fill(sz);

        // if there's no more available data in the buffer after a write, that means we reached
        // the end of the file
        if b.available_data() == 0 {
            panic!("no more data to read or parse, stopping the reading loop");
        }

        let offset = {
            let (i, element) = match segment_element(b.data()) {
                Ok((i, o)) => (i, o),
                Err(Err::Error(e)) | Err(Err::Failure(e)) => panic!("failed parsing: {:?}", e),
                Err(Err::Incomplete(_i)) => continue,
            };

            match element {
                SegmentElement::SeekHead(s) => {
                    println!("|+ Seek head at {:#0x} size {}", 0x0, b.data().offset(i));
                    for seek in s.positions.iter() {
                        let id: u64 = ((seek.id[0] as u64) << 24)
                            | ((seek.id[1] as u64) << 16)
                            | ((seek.id[2] as u64) << 8)
                            | seek.id[3] as u64;

                        let element_size = seek.size(0x4DBB);
                        let id_size = seek.id.size(0x53AB);
                        let position_size = seek.position.size(0x53AC);

                        println!("| + Seek entry size {}", element_size);

                        print!("|  + Seek ID:");
                        for id in seek.id.iter() {
                            print!(" {:#0x}", id);
                        }

                        let name = match &seek.id[..] {
                            [0x11, 0x4D, 0x9B, 0x74] => " (KaxSeekHead)",
                            [0x12, 0x54, 0xC3, 0x67] => " (KaxTags)",
                            [0x15, 0x49, 0xA9, 0x66] => " (KaxInfo)",
                            [0x16, 0x54, 0xAE, 0x6B] => " (KaxTracks)",
                            [0x1C, 0x53, 0xBB, 0x6B] => " (KaxCues)",
                            [0x1F, 0x43, 0xB6, 0x75] => " (KaxCluster)",
                            _ => "",
                        };

                        println!("{} at {:#0x} size {}", name, 0x0, id_size);
                        println!(
                            "|  + Seek position: {} size {}",
                            seek.position, position_size
                        );
                    }

                    if seek_head.is_some() {
                        panic!("already got a SeekHead element");
                    } else {
                        seek_head = Some(s);
                    }
                }
                SegmentElement::Info(i) => {
                    println!("|+ Segment information");
                    println!("| + Timestamp scale: {}", i.timecode_scale);
                    println!("| + Multiplexing application: {}", i.muxing_app);
                    println!("| + Writing application: {}", i.writing_app);
                    println!(
                        "| + Segment UID: {:?}",
                        i.segment_uid.as_ref().unwrap_or(&Vec::new())
                    );
                    println!("| + Duration: {}s", i.duration.unwrap_or(0f64) / 1000f64);
                    if info.is_some() {
                        panic!("already got an Info element");
                    } else {
                        info = Some(i);
                    }
                }
                SegmentElement::Tracks(t) => {
                    //eprintln!("got tracks: {:#?}", t);
                    println!("|+ Segment tracks");
                    for tr in t.tracks.iter() {
                        println!("| + A track");
                        println!("|  + Track number: {}", tr.track_number);
                        println!("|  + Track UID: {}", tr.track_uid);
                        println!("|  + Track type: {}", tr.track_type);
                        println!("|  + Lacing flag: {}", tr.flag_lacing.unwrap_or(0));
                        println!("|  + Default flag: {}", tr.flag_default.unwrap_or(0));
                        println!(
                            "|  + Language: {}",
                            tr.language.as_ref().unwrap_or(&"".to_string())
                        );
                        println!("|  + Codec ID: {}", tr.codec_id);
                        println!(
                            "|  + Codec private: length {}",
                            tr.codec_private.as_ref().map(|v| v.len()).unwrap_or(0)
                        );

                        if let Some(ref v) = tr.video {
                            println!("|  + Video track");
                            println!("|    + Pixel width: {}", v.pixel_width);
                            println!("|    + Pixel height: {}", v.pixel_height);
                            if let Some(inter) = v.flag_interlaced {
                                println!("|    + Interlaced: {}", inter);
                            }
                            if let Some(width) = v.display_width {
                                println!("|    + Display width: {}", width);
                            }
                            if let Some(height) = v.display_height {
                                println!("|    + Display height: {}", height);
                            }
                            if let Some(unit) = v.display_unit {
                                println!("|    + Display unit: {}", unit);
                            }
                        }

                        if let Some(ref a) = tr.audio {
                            println!("|  + Audio track");
                            println!("|    + Sampling frequency: {}", a.sampling_frequency);
                            if let Some(frequency) = a.output_sampling_frequency {
                                println!("|    + Output sampling freqeuncy: {}", frequency);
                            }
                            println!("|    + Channels: {}", a.channels);
                            if let Some(ref channel_positions) = a.channel_positions {
                                println!("|    + Channel position: {:?}", channel_positions);
                            }
                            if let Some(bit_depth) = a.bit_depth {
                                println!("|    + Bit depth: {}", bit_depth);
                            }
                        }
                    }
                    if tracks.is_some() {
                        panic!("already got a Tracks element");
                    } else {
                        tracks = Some(t);
                    }
                }
                /*SegmentElement::Cluster(c) => {
                    println!("|+ Cluster");
                    eprintln!("got a cluster: {:#?}", c);
                },*/
                SegmentElement::Void(s) => {
                    println!("|+ EbmlVoid (size: {})", s);
                }
                el => {
                    panic!("got unexpected element: {:#?}", el);
                }
            }

            b.data().offset(i)
        };
        _consumed += offset;
        //eprintln!("consumed {} bytes", length);
        b.consume(offset);
    }

    loop {
        if b.available_space() == 0 {
            b.shift();
            if b.available_space() == 0 {
                println!("buffer is already full,  cannot refill");
                break;
            }
        }

        // refill the buffer
        let sz = file.read(b.space()).expect("should read");
        b.fill(sz);

        /*
        eprintln!(
            "refill: {} more bytes, available data: {} bytes, consumed: {} bytes",
            sz,
            b.available_data(),
            consumed
        );
        */

        // if there's no more available data in the buffer after a write, that means we reached
        // the end of the file
        if b.available_data() == 0 {
            //panic!("no more data to read or parse, stopping the reading loop");
            break;
        }

        let offset = {
            let (i, element) = match segment_element(b.data()) {
                Ok((i, o)) => (i, o),
                Err(Err::Error(e)) | Err(Err::Failure(e)) => panic!("failed parsing: {:?}", e),
                Err(Err::Incomplete(_)) => continue,
            };

            match element {
                SegmentElement::SeekHead(_)
                | SegmentElement::Info(_)
                | SegmentElement::Tracks(_) => {
                    panic!(
                        "unexpected seek head, info or tracks element: {:?}",
                        element
                    );
                }
                SegmentElement::Cluster(c) => {
                    println!("|+ Cluster");
                    println!("|+   Timecode: {}", c.timecode);
                    println!("|+   Silent_tracks: {:?}", c.silent_tracks);
                    println!("|+   Position: {:?}", c.position);
                    println!("|+   Prev size: {:?}", c.prev_size);
                    println!("|+   Simple block: {} elements", c.simple_block.len());
                    println!("|+   Block group: {} elements", c.block_group.len());
                    println!(
                        "|+   Encrypted block: {:?} bytes",
                        c.encrypted_block.as_ref().map(|s| s.len())
                    );
                    //eprintln!("got a cluster: {:#?}", c);
                }
                SegmentElement::Void(s) => {
                    println!("|+ EbmlVoid (size: {})", s);
                }
                SegmentElement::Tags(_) => {
                    println!("|+ Tags");
                }
                SegmentElement::Cues(_) => {
                    println!("|+ Cues");
                }
                SegmentElement::Unknown(id, data) => {
                    panic!(
                        "offset {:X?}: got unknown element: {:X?} {:#?}",
                        _consumed, id, data
                    );
                }
                el => {
                    panic!("got unexpected element: {:#?}", el);
                }
            }

            b.data().offset(i)
        };
        _consumed += offset;
        //eprintln!("consumed {} bytes", length);
        b.consume(offset);
    }

    Ok(())
}
<commit_msg>Remove a warning<commit_after>extern crate av_data;
extern crate av_format;
extern crate circular;
extern crate matroska;
extern crate nom;
extern crate pretty_env_logger;

use circular::Buffer;
use nom::{Err, Offset};
use std::env;
use std::fs::File;
use std::io::Read;

use matroska::ebml::ebml_header;
use matroska::elements::{segment, segment_element, SegmentElement};
use matroska::serializer::ebml::EbmlSize;

fn main() {
    better_panic::install();
    pretty_env_logger::init();
    let mut args = env::args();
    let _ = args.next().expect("first arg is program path");
    let filename = args.next().expect("expected file path");

    //println!("filename: {}", filename);
    run(&filename).expect("should parse file correctly");
}

fn run(filename: &str) -> std::io::Result<()> {
    let mut file = File::open(filename)?;

    let capacity = 5242880;
    let mut b = Buffer::with_capacity(capacity);

    // we write into the `&mut[u8]` returned by `space()`
    let sz = file.read(b.space()).expect("should write");
    b.fill(sz);
    //eprintln!("write {:#?}", sz);

    let length = {
        let res = ebml_header(b.data());
        if let Ok((remaining, header)) = res {
            //eprintln!("parsed header: {:#?}", h);
            println!("+ EBML head");
            println!("|+ EBML version: {}", header.version);
            println!("|+ EBML read version: {}", header.read_version);
            println!("|+ EBML maximum ID length: {}", header.max_id_length);
            println!("|+ EBML maximum size length: {}", header.max_size_length);
            println!("|+ Doc type: {}", header.doc_type);
            println!("|+ Doc type read version: {}", header.doc_type_read_version);

            b.data().offset(remaining)
        } else {
            panic!("couldn't parse header");
        }
    };

    let mut _consumed = length;
    b.consume(length);

    let length = {
        let res = segment(b.data());
        if let Ok((remaining, segment)) = res {
            //eprintln!("parsed segment: {:#?}", h);
            println!("+ Segment, size {}", segment.1.unwrap_or(0));

            b.data().offset(remaining)
        } else {
            panic!("couldn't parse header");
        }
    };

    b.consume(length);

    // handle first elements
    let mut seek_head = None;
    let mut info = None;
    let mut tracks = None;

    loop {
        if seek_head.is_some() && info.is_some() && tracks.is_some() {
            break;
        }

        if b.available_space() == 0 {
            b.shift();
            if b.available_space() == 0 {
                println!("buffer is already full,  cannot refill");
                break;
            }
        }

        // refill the buffer
        let sz = file.read(b.space()).expect("should read");
        b.fill(sz);

        // if there's no more available data in the buffer after a write, that means we reached
        // the end of the file
        if b.available_data() == 0 {
            panic!("no more data to read or parse, stopping the reading loop");
        }

        let offset = {
            let (i, element) = match segment_element(b.data()) {
                Ok((i, o)) => (i, o),
                Err(Err::Error(e)) | Err(Err::Failure(e)) => panic!("failed parsing: {:?}", e),
                Err(Err::Incomplete(_i)) => continue,
            };

            match element {
                SegmentElement::SeekHead(s) => {
                    println!("|+ Seek head at {:#0x} size {}", 0x0, b.data().offset(i));
                    for seek in s.positions.iter() {
                        let _id: u64 = ((seek.id[0] as u64) << 24)
                            | ((seek.id[1] as u64) << 16)
                            | ((seek.id[2] as u64) << 8)
                            | seek.id[3] as u64;

                        let element_size = seek.size(0x4DBB);
                        let id_size = seek.id.size(0x53AB);
                        let position_size = seek.position.size(0x53AC);

                        println!("| + Seek entry size {}", element_size);

                        print!("|  + Seek ID:");
                        for id in seek.id.iter() {
                            print!(" {:#0x}", id);
                        }

                        let name = match &seek.id[..] {
                            [0x11, 0x4D, 0x9B, 0x74] => " (KaxSeekHead)",
                            [0x12, 0x54, 0xC3, 0x67] => " (KaxTags)",
                            [0x15, 0x49, 0xA9, 0x66] => " (KaxInfo)",
                            [0x16, 0x54, 0xAE, 0x6B] => " (KaxTracks)",
                            [0x1C, 0x53, 0xBB, 0x6B] => " (KaxCues)",
                            [0x1F, 0x43, 0xB6, 0x75] => " (KaxCluster)",
                            _ => "",
                        };

                        println!("{} at {:#0x} size {}", name, 0x0, id_size);
                        println!(
                            "|  + Seek position: {} size {}",
                            seek.position, position_size
                        );
                    }

                    if seek_head.is_some() {
                        panic!("already got a SeekHead element");
                    } else {
                        seek_head = Some(s);
                    }
                }
                SegmentElement::Info(i) => {
                    println!("|+ Segment information");
                    println!("| + Timestamp scale: {}", i.timecode_scale);
                    println!("| + Multiplexing application: {}", i.muxing_app);
                    println!("| + Writing application: {}", i.writing_app);
                    println!(
                        "| + Segment UID: {:?}",
                        i.segment_uid.as_ref().unwrap_or(&Vec::new())
                    );
                    println!("| + Duration: {}s", i.duration.unwrap_or(0f64) / 1000f64);
                    if info.is_some() {
                        panic!("already got an Info element");
                    } else {
                        info = Some(i);
                    }
                }
                SegmentElement::Tracks(t) => {
                    //eprintln!("got tracks: {:#?}", t);
                    println!("|+ Segment tracks");
                    for tr in t.tracks.iter() {
                        println!("| + A track");
                        println!("|  + Track number: {}", tr.track_number);
                        println!("|  + Track UID: {}", tr.track_uid);
                        println!("|  + Track type: {}", tr.track_type);
                        println!("|  + Lacing flag: {}", tr.flag_lacing.unwrap_or(0));
                        println!("|  + Default flag: {}", tr.flag_default.unwrap_or(0));
                        println!(
                            "|  + Language: {}",
                            tr.language.as_ref().unwrap_or(&"".to_string())
                        );
                        println!("|  + Codec ID: {}", tr.codec_id);
                        println!(
                            "|  + Codec private: length {}",
                            tr.codec_private.as_ref().map(|v| v.len()).unwrap_or(0)
                        );

                        if let Some(ref v) = tr.video {
                            println!("|  + Video track");
                            println!("|    + Pixel width: {}", v.pixel_width);
                            println!("|    + Pixel height: {}", v.pixel_height);
                            if let Some(inter) = v.flag_interlaced {
                                println!("|    + Interlaced: {}", inter);
                            }
                            if let Some(width) = v.display_width {
                                println!("|    + Display width: {}", width);
                            }
                            if let Some(height) = v.display_height {
                                println!("|    + Display height: {}", height);
                            }
                            if let Some(unit) = v.display_unit {
                                println!("|    + Display unit: {}", unit);
                            }
                        }

                        if let Some(ref a) = tr.audio {
                            println!("|  + Audio track");
                            println!("|    + Sampling frequency: {}", a.sampling_frequency);
                            if let Some(frequency) = a.output_sampling_frequency {
                                println!("|    + Output sampling freqeuncy: {}", frequency);
                            }
                            println!("|    + Channels: {}", a.channels);
                            if let Some(ref channel_positions) = a.channel_positions {
                                println!("|    + Channel position: {:?}", channel_positions);
                            }
                            if let Some(bit_depth) = a.bit_depth {
                                println!("|    + Bit depth: {}", bit_depth);
                            }
                        }
                    }
                    if tracks.is_some() {
                        panic!("already got a Tracks element");
                    } else {
                        tracks = Some(t);
                    }
                }
                /*SegmentElement::Cluster(c) => {
                    println!("|+ Cluster");
                    eprintln!("got a cluster: {:#?}", c);
                },*/
                SegmentElement::Void(s) => {
                    println!("|+ EbmlVoid (size: {})", s);
                }
                el => {
                    panic!("got unexpected element: {:#?}", el);
                }
            }

            b.data().offset(i)
        };
        _consumed += offset;
        //eprintln!("consumed {} bytes", length);
        b.consume(offset);
    }

    loop {
        if b.available_space() == 0 {
            b.shift();
            if b.available_space() == 0 {
                println!("buffer is already full,  cannot refill");
                break;
            }
        }

        // refill the buffer
        let sz = file.read(b.space()).expect("should read");
        b.fill(sz);

        /*
        eprintln!(
            "refill: {} more bytes, available data: {} bytes, consumed: {} bytes",
            sz,
            b.available_data(),
            consumed
        );
        */

        // if there's no more available data in the buffer after a write, that means we reached
        // the end of the file
        if b.available_data() == 0 {
            //panic!("no more data to read or parse, stopping the reading loop");
            break;
        }

        let offset = {
            let (i, element) = match segment_element(b.data()) {
                Ok((i, o)) => (i, o),
                Err(Err::Error(e)) | Err(Err::Failure(e)) => panic!("failed parsing: {:?}", e),
                Err(Err::Incomplete(_)) => continue,
            };

            match element {
                SegmentElement::SeekHead(_)
                | SegmentElement::Info(_)
                | SegmentElement::Tracks(_) => {
                    panic!(
                        "unexpected seek head, info or tracks element: {:?}",
                        element
                    );
                }
                SegmentElement::Cluster(c) => {
                    println!("|+ Cluster");
                    println!("|+   Timecode: {}", c.timecode);
                    println!("|+   Silent_tracks: {:?}", c.silent_tracks);
                    println!("|+   Position: {:?}", c.position);
                    println!("|+   Prev size: {:?}", c.prev_size);
                    println!("|+   Simple block: {} elements", c.simple_block.len());
                    println!("|+   Block group: {} elements", c.block_group.len());
                    println!(
                        "|+   Encrypted block: {:?} bytes",
                        c.encrypted_block.as_ref().map(|s| s.len())
                    );
                    //eprintln!("got a cluster: {:#?}", c);
                }
                SegmentElement::Void(s) => {
                    println!("|+ EbmlVoid (size: {})", s);
                }
                SegmentElement::Tags(_) => {
                    println!("|+ Tags");
                }
                SegmentElement::Cues(_) => {
                    println!("|+ Cues");
                }
                SegmentElement::Unknown(id, data) => {
                    panic!(
                        "offset {:X?}: got unknown element: {:X?} {:#?}",
                        _consumed, id, data
                    );
                }
                el => {
                    panic!("got unexpected element: {:#?}", el);
                }
            }

            b.data().offset(i)
        };
        _consumed += offset;
        //eprintln!("consumed {} bytes", length);
        b.consume(offset);
    }

    Ok(())
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2016 Antoine Wacheux

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

pub struct LexicalUnit {
    name : String,
    regex : String,
}

pub struct ProductionRule {
    name: String,
    rule: Vec<RuleComponent>
}

pub enum RuleComponent {
    ProductionRule(String),
    LexicalUnit(String)
}

pub struct Grammar {
    lexical_units : Vec<LexicalUnit>,
    production_rules: Vec<ProductionRule>,
    axiom : String
}

impl Grammar {
    fn new() -> Grammar {
        Grammar {
            lexical_units: Vec::new(),
            production_rules: Vec::new(),
            axiom: String::new(),
        }
    }
}

//Methods
//get_rule(name: String&) -> Vec<ProductionRule>&

struct ParserContext {
    src: String,
    row: u32,
    col: u32,
    str_pos: usize,
}

impl ParserContext {
    fn new(src : String) -> ParserContext {
        ParserContext {
            src: src,
            row: 1,
            col: 0,
            str_pos: 0
        }
    }

    fn next_word(&mut self) -> Option<String> {
        let mut iter = self.src.chars();
        let mut ch = iter.nth(self.str_pos);
        let mut c : char;
        let mut read_word = String::new();

        match ch {
            None => { return None },
            Some(chr) => { c = chr}
        }

        macro_rules! next_char {
            ($err:stmt) => ({
                self.str_pos += 1;
                ch = iter.next();

                match ch {
                    None => { $err },
                    Some(chr) => { c = chr }
                }

                match c {
                    ' ' | '\t' => self.col += 1,
                    '\n' => self.row += 1,
                    _ => {}
                }
            });
        }

        while (c == ' ') || (c == '\n') || (c == '\t') { //We skip leading whitespaces
            next_char! { return None }
        }

        while !((c == ' ') || (c == '\n') || (c == '\t')) {
            read_word.push(c);
            next_char! { return Some(read_word) }
        }

        Some(read_word)
    }

    pub fn read_line(&mut self) -> Option<String> {
        let mut iter = self.src.chars();
        let mut ch = iter.nth(self.str_pos);
        let mut c : char;
        let mut read_word = String::new();

        match ch {
            None => { return None },
            Some(chr) => { c = chr}
        }

        macro_rules! next_char {
            ($err:stmt) => ({
                self.str_pos += 1;
                ch = iter.next();

                match ch {
                    None => { $err },
                    Some(chr) => { c = chr }
                }

                match c {
                    ' ' | '\t' => self.col += 1,
                    '\n' => self.row += 1,
                    _ => {}
                }
            });
        }

        while (c == ' ') || (c == '\n') || (c == '\t') { //We skip leading whitespaces
            next_char! { return None }
        }

        while c != '\n' {
            read_word.push(c);
            next_char! { return Some(read_word) }
        }

        Some(read_word)
    }
}

struct GrammarParser {
    ctx: ParserContext,
    grammar: Grammar
}

impl GrammarParser {
    fn new(src: String) -> GrammarParser {
        GrammarParser {
            ctx : ParserContext::new(src),
            grammar: Grammar::new(),
        }
    }

    fn get_resulting_grammar(self) -> Grammar {
        self.grammar
    }

    fn parse(&mut self) -> Result<(), String> {
        while let Some(str_word) = self.ctx.next_word() {
            match str_word.chars().next().unwrap() {
                'A'...'Z' => {
                    match self.parse_grammar_rule(str_word) {
                        Ok(()) => {},
                        Err(msg) => {return Err(msg)},
                    }
                },
                'a'...'z' => {
                    match self.parse_lexical_unit(str_word) {
                        Ok(()) => {},
                        Err(msg) => {return Err(msg)},
                    }
                }
                _ => { return Err(String::from("Unknown token : ") + str_word.as_str())}
            }
        }

        Ok(())
    }

    fn parse_grammar_rule(&mut self, name : String) -> Result<(), String> {
        match self.ctx.next_word() {
            None => {return Err(format!("line {} : Expected '->'", self.ctx.row))},
            Some(token) => {
                if token != "->" {
                    return Err(format!("line {} : Expected '->' found '{}'", self.ctx.row, token));
                }
            }
        }

        if let Some(rule_str) = self.ctx.read_line() {
            let mut production_rule = ProductionRule{
                name: name,
                rule: Vec::new()
            };

            for comp_str in rule_str.split_whitespace() {
                let component_str = String::from(comp_str);
                let component = match component_str.chars().next().unwrap() {
                    'a'...'z' => {RuleComponent::LexicalUnit(component_str.to_owned())},
                    'A'...'Z' => {RuleComponent::ProductionRule(component_str.to_owned())},
                    '\'' => {
                        let s = component_str.len();
                        if s < 3 {
                            return Err(format!("line {} : The regex in a production rule cannot be empty.", self.ctx.row));
                        }

                        let regex = unsafe {component_str.slice_unchecked(1, s-1) }; //TODO : Remove this unsafe
                        let name = format!("auto_{}", regex);

                        if self.grammar.lexical_units.iter().find(|rule| rule.name == name).is_none() {
                            self.grammar.lexical_units.push(LexicalUnit{name:name.clone(), regex:String::from(regex)});
                        }

                        RuleComponent::LexicalUnit(name)
                    },
                    _ => {return Err(format!("line {}: '{}' is unexpected", self.ctx.row, component_str))}
                };

                production_rule.rule.push(component);
            }
            self.grammar.production_rules.push(production_rule);
            Ok(())
        }
        else {
            Err(format!("A production rule cannot be empty"))
        }
    }

    fn parse_lexical_unit(&mut self, name : String) -> Result<(), String> {
        //Let's read the ':'
        match self.ctx.next_word() {
            None => {return Err(format!("line {} : Expected ':'", self.ctx.row))},
            Some(token) => {
                if token != ":" {
                    return Err(format!("line {} : Expected ':' found '{}'", self.ctx.row, token));
                }
            }
        }

        //Ok, now the regex
        if let Some(regex) = self.ctx.read_line() {
            let lexical_rule = LexicalUnit {
                name: name,
                regex: regex,
            };

            self.grammar.lexical_units.push(lexical_rule);
            Ok(())
        }
        else {
            Err(format!("line {} : The regex is expected after ':' but nothing was found", self.ctx.row))
        }
    }
}

pub fn parse_grammar(src : String) -> Result<Grammar, String> {
    let mut parser = GrammarParser::new(src);

    match parser.parse() {
        Ok(()) => Ok(parser.get_resulting_grammar()),
        Err(msg) => Err(msg)
    }
}

#[test]
fn test_next_word() {
    let mut ctx = ParserContext::new("test and run".to_owned());

    assert_eq!(ctx.next_word().unwrap(), "test");
    assert_eq!(ctx.next_word().unwrap(), "and");
    assert_eq!(ctx.next_word().unwrap(), "run");
}

#[test]
fn test_read_line() {
    let mut ctx = ParserContext::new("line 1\nline2\nline3\nline4".to_owned());
    ctx.next_word();

    assert_eq!(ctx.read_line().unwrap(), "1");
    assert_eq!(ctx.read_line().unwrap(), "line2");
    assert_eq!(ctx.read_line().unwrap(), "line3");
    assert_eq!(ctx.read_line().unwrap(), "line4");
}
<commit_msg>Check that we don't add twice the same lexical unit<commit_after>/*
Copyright (c) 2016 Antoine Wacheux

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

pub struct LexicalUnit {
    name : String,
    regex : String,
}

pub struct ProductionRule {
    name: String,
    rule: Vec<RuleComponent>
}

pub enum RuleComponent {
    ProductionRule(String),
    LexicalUnit(String)
}

pub struct Grammar {
    lexical_units : Vec<LexicalUnit>,
    production_rules: Vec<ProductionRule>,
    axiom : String
}

impl Grammar {
    fn new() -> Grammar {
        Grammar {
            lexical_units: Vec::new(),
            production_rules: Vec::new(),
            axiom: String::new(),
        }
    }
}

//Methods
//get_rule(name: String&) -> Vec<ProductionRule>&

struct ParserContext {
    src: String,
    row: u32,
    col: u32,
    str_pos: usize,
}

impl ParserContext {
    fn new(src : String) -> ParserContext {
        ParserContext {
            src: src,
            row: 1,
            col: 0,
            str_pos: 0
        }
    }

    fn next_word(&mut self) -> Option<String> {
        let mut iter = self.src.chars();
        let mut ch = iter.nth(self.str_pos);
        let mut c : char;
        let mut read_word = String::new();

        match ch {
            None => { return None },
            Some(chr) => { c = chr}
        }

        macro_rules! next_char {
            ($err:stmt) => ({
                self.str_pos += 1;
                ch = iter.next();

                match ch {
                    None => { $err },
                    Some(chr) => { c = chr }
                }

                match c {
                    ' ' | '\t' => self.col += 1,
                    '\n' => self.row += 1,
                    _ => {}
                }
            });
        }

        while (c == ' ') || (c == '\n') || (c == '\t') { //We skip leading whitespaces
            next_char! { return None }
        }

        while !((c == ' ') || (c == '\n') || (c == '\t')) {
            read_word.push(c);
            next_char! { return Some(read_word) }
        }

        Some(read_word)
    }

    pub fn read_line(&mut self) -> Option<String> {
        let mut iter = self.src.chars();
        let mut ch = iter.nth(self.str_pos);
        let mut c : char;
        let mut read_word = String::new();

        match ch {
            None => { return None },
            Some(chr) => { c = chr}
        }

        macro_rules! next_char {
            ($err:stmt) => ({
                self.str_pos += 1;
                ch = iter.next();

                match ch {
                    None => { $err },
                    Some(chr) => { c = chr }
                }

                match c {
                    ' ' | '\t' => self.col += 1,
                    '\n' => self.row += 1,
                    _ => {}
                }
            });
        }

        while (c == ' ') || (c == '\n') || (c == '\t') { //We skip leading whitespaces
            next_char! { return None }
        }

        while c != '\n' {
            read_word.push(c);
            next_char! { return Some(read_word) }
        }

        Some(read_word)
    }
}

struct GrammarParser {
    ctx: ParserContext,
    grammar: Grammar
}

impl GrammarParser {
    fn new(src: String) -> GrammarParser {
        GrammarParser {
            ctx : ParserContext::new(src),
            grammar: Grammar::new(),
        }
    }

    fn get_resulting_grammar(self) -> Grammar {
        self.grammar
    }

    fn parse(&mut self) -> Result<(), String> {
        while let Some(str_word) = self.ctx.next_word() {
            match str_word.chars().next().unwrap() {
                'A'...'Z' => {
                    match self.parse_grammar_rule(str_word) {
                        Ok(()) => {},
                        Err(msg) => {return Err(msg)},
                    }
                },
                'a'...'z' => {
                    match self.parse_lexical_unit(str_word) {
                        Ok(()) => {},
                        Err(msg) => {return Err(msg)},
                    }
                }
                _ => { return Err(String::from("Unknown token : ") + str_word.as_str())}
            }
        }

        Ok(())
    }

    fn parse_grammar_rule(&mut self, name : String) -> Result<(), String> {
        match self.ctx.next_word() {
            None => {return Err(format!("line {} : Expected '->'", self.ctx.row))},
            Some(token) => {
                if token != "->" {
                    return Err(format!("line {} : Expected '->' found '{}'", self.ctx.row, token));
                }
            }
        }

        if let Some(rule_str) = self.ctx.read_line() {
            let mut production_rule = ProductionRule{
                name: name,
                rule: Vec::new()
            };

            for comp_str in rule_str.split_whitespace() {
                let component_str = String::from(comp_str);
                let component = match component_str.chars().next().unwrap() {
                    'a'...'z' => {RuleComponent::LexicalUnit(component_str.to_owned())},
                    'A'...'Z' => {RuleComponent::ProductionRule(component_str.to_owned())},
                    '\'' => {
                        let s = component_str.len();
                        if s < 3 {
                            return Err(format!("line {} : The regex in a production rule cannot be empty.", self.ctx.row));
                        }

                        let regex = unsafe {component_str.slice_unchecked(1, s-1) }; //TODO : Remove this unsafe
                        let name = format!("auto_{}", regex);

                        if self.grammar.lexical_units.iter().find(|rule| rule.name == name).is_none() {
                            self.grammar.lexical_units.push(LexicalUnit{name:name.clone(), regex:String::from(regex)});
                        }

                        RuleComponent::LexicalUnit(name)
                    },
                    _ => {return Err(format!("line {}: '{}' is unexpected", self.ctx.row, component_str))}
                };

                production_rule.rule.push(component);
            }
            self.grammar.production_rules.push(production_rule);
            Ok(())
        }
        else {
            Err(format!("A production rule cannot be empty"))
        }
    }

    fn parse_lexical_unit(&mut self, name : String) -> Result<(), String> {
        //Let's read the ':'
        match self.ctx.next_word() {
            None => {return Err(format!("line {} : Expected ':'", self.ctx.row))},
            Some(token) => {
                if token != ":" {
                    return Err(format!("line {} : Expected ':' found '{}'", self.ctx.row, token));
                }
            }
        }

        //Ok, now the regex
        if let Some(regex) = self.ctx.read_line() {
            let lexical_rule = LexicalUnit {
                name: name,
                regex: regex,
            };

            if self.grammar.lexical_units.iter().find(|rule| rule.name == lexical_rule.name).is_some() {
                return Err(format!("line {} : the lexical unit {} has already been declared", self.ctx.row, lexical_rule.name));
            }
            self.grammar.lexical_units.push(lexical_rule);
            Ok(())
        }
        else {
            Err(format!("line {} : The regex is expected after ':' but nothing was found", self.ctx.row))
        }
    }
}

pub fn parse_grammar(src : String) -> Result<Grammar, String> {
    let mut parser = GrammarParser::new(src);

    match parser.parse() {
        Ok(()) => Ok(parser.get_resulting_grammar()),
        Err(msg) => Err(msg)
    }
}

#[test]
fn test_next_word() {
    let mut ctx = ParserContext::new("test and run".to_owned());

    assert_eq!(ctx.next_word().unwrap(), "test");
    assert_eq!(ctx.next_word().unwrap(), "and");
    assert_eq!(ctx.next_word().unwrap(), "run");
}

#[test]
fn test_read_line() {
    let mut ctx = ParserContext::new("line 1\nline2\nline3\nline4".to_owned());
    ctx.next_word();

    assert_eq!(ctx.read_line().unwrap(), "1");
    assert_eq!(ctx.read_line().unwrap(), "line2");
    assert_eq!(ctx.read_line().unwrap(), "line3");
    assert_eq!(ctx.read_line().unwrap(), "line4");
}
<|endoftext|>


<commit_before>//const _GRAMMAR: &'static str = include_str!("grammar.pest");

#[derive(Parser)]
#[grammar = "grammar.pest"]
pub struct HandlebarsParser;

#[cfg(test)]
use pest::Parser;

#[cfg(test)]
macro_rules! assert_rule {
    ($rule:expr, $in:expr) => {
        assert_eq!(
            HandlebarsParser::parse($rule, $in)
                .unwrap()
                .last()
                .unwrap()
                .into_span()
                .end(),
            $in.len()
        );
    };
}

#[cfg(test)]
macro_rules! assert_rule_match {
    ($rule:expr, $in:expr) => {
        assert!(HandlebarsParser::parse($rule, $in).is_ok());
    };
}

#[test]
fn test_raw_text() {
    let s = vec![
        "
 helloworld
    ",
        "hello\\{{world}}",
        "hello\\{{#if world}}nice\\{{/if}}",
        "hello \\{{{{raw}}}}hello\\{{{{/raw}}}}",
    ];
    for i in s.iter() {
        assert_rule!(Rule::raw_text, i);
    }
}

#[test]
fn test_raw_block_text() {
    let s = "
 {{hello}}
";
    assert_rule!(Rule::raw_block_text, s);
}

#[test]
fn test_reference() {
    let s = vec![
        "a",
        "abc",
        "../a",
        "a.b",
        "@abc",
        "a.[abc]",
        "aBc.[abc]",
        "abc.[0].[nice]",
        "some-name",
        "this.[0].ok",
    ];
    for i in s.iter() {
        assert_rule!(Rule::reference, i);
    }
}

#[test]
fn test_name() {
    let s = vec!["if", "(abc)"];
    for i in s.iter() {
        assert_rule!(Rule::name, i);
    }
}

#[test]
fn test_param() {
    let s = vec!["hello", "\"json literal\""];
    for i in s.iter() {
        assert_rule!(Rule::param, i);
    }
}

#[test]
fn test_hash() {
    let s = vec![
        "hello=world",
        "hello=\"world\"",
        "hello=(world)",
        "hello=(world 0)",
    ];
    for i in s.iter() {
        assert_rule!(Rule::hash, i);
    }
}

#[test]
fn test_json_literal() {
    let s = vec![
        "\"json string\"",
        "\"quot: \\\"\"",
        "[]",
        "[\"hello\"]",
        "[1,2,3,4,true]",
        "{\"hello\": \"world\"}",
        "{}",
        "{\"a\":1, \"b\":2 }",
    ];
    for i in s.iter() {
        assert_rule!(Rule::literal, i);
    }
}

#[test]
fn test_comment() {
    let s = vec!["{{!-- <hello {{ a-b c-d}} {{d-c}} ok --}}",
                 "{{!--

{{this.title}}

                --}}"];
    for i in s.iter() {
        assert_rule!(Rule::hbs_comment, i);
    }
    let s2 = vec!["{{! hello }}", "{{! test me }}"];
    for i in s2.iter() {
        assert_rule!(Rule::hbs_comment_compact, i);
    }
}

#[test]
fn test_subexpression() {
    let s = vec!["(sub)", "(sub 0)", "(sub a=1)"];
    for i in s.iter() {
        assert_rule!(Rule::subexpression, i);
    }
}

#[test]
fn test_expression() {
    let s = vec!["{{exp}}", "{{(exp)}}", "{{this.name}}", "{{this.[0].name}}"];
    for i in s.iter() {
        assert_rule!(Rule::expression, i);
    }
}

#[test]
fn test_helper_expression() {
    let s = vec![
        "{{exp 1}}",
        "{{exp \"literal\"}}",
        "{{exp ref}}",
        "{{exp (sub)}}",
        "{{exp (sub 123)}}",
        "{{exp []}}",
        "{{exp {}}}",
        "{{exp key=1}}",
        "{{exp key=ref}}",
        "{{exp key=(sub)}}",
        "{{exp key=(sub 0)}}",
    ];
    for i in s.iter() {
        assert_rule!(Rule::helper_expression, i);
    }
}

#[test]
fn test_identifier_with_dash() {
    let s = vec!["{{exp-foo}}"];
    for i in s.iter() {
        assert_rule!(Rule::expression, i);
    }
}

#[test]
fn test_html_expression() {
    let s = vec!["{{{html}}}", "{{{(html)}}}", "{{{(html)}}}"];
    for i in s.iter() {
        assert_rule!(Rule::html_expression, i);
    }
}

#[test]
fn test_helper_start() {
    let s = vec![
        "{{#if hello}}",
        "{{#if (hello)}}",
        "{{#if hello=world}}",
        "{{#if hello hello=world}}",
        "{{#if []}}",
        "{{#if {}}}",
        "{{#if}}",
        "{{~#if hello~}}",
        "{{#each people as |person|}}",
        "{{#each-obj obj as |key val|}}",
        "{{#each assets}}",
    ];
    for i in s.iter() {
        assert_rule!(Rule::helper_block_start, i);
    }
}

#[test]
fn test_helper_end() {
    let s = vec!["{{/if}}", "{{~/if}}", "{{~/if ~}}", "{{/if   ~}}"];
    for i in s.iter() {
        assert_rule!(Rule::helper_block_end, i);
    }
}

#[test]
fn test_helper_block() {
    let s = vec![
        "{{#if hello}}hello{{/if}}",
        "{{#if true}}hello{{/if}}",
        "{{#if nice ok=1}}hello{{/if}}",
        "{{#if}}hello{{else}}world{{/if}}",
        "{{#if}}hello{{^}}world{{/if}}",
        "{{#if}}{{#if}}hello{{/if}}{{/if}}",
        "{{#if}}hello{{~else}}world{{/if}}",
        "{{#if}}hello{{else~}}world{{/if}}",
        "{{#if}}hello{{~^~}}world{{/if}}",
        "{{#if}}{{/if}}",
    ];
    for i in s.iter() {
        assert_rule!(Rule::helper_block, i);
    }
}

#[test]
fn test_raw_block() {
    let s = vec![
        "{{{{if hello}}}}good {{hello}}{{{{/if}}}}",
        "{{{{if hello}}}}{{#if nice}}{{/if}}{{{{/if}}}}",
    ];
    for i in s.iter() {
        assert_rule!(Rule::raw_block, i);
    }
}

#[test]
fn test_block_param() {
    let s = vec!["as |person|", "as |key val|"];
    for i in s.iter() {
        assert_rule!(Rule::block_param, i);
    }
}

#[test]
fn test_path() {
    let s = vec![
        "a",
        "a.b.c.d",
        "a.[0].[1].[2]",
        "a.[abc]",
        "a/v/c.d.s",
        "a.[0]/b/c/../d",
        "a.[bb c]/b/c/../d",
        "a.[0].[#hello]",
        "../a/b.[0].[1]",
        "./this.[0]/[1]/this/../a",
        "./this_name",
        "./goo/[/bar]",
        "a.[你好]",
        "a.[10].[#comment]",
        "a.[]", // empty key
        "././[/foo]",
        "[foo]",
    ];
    for i in s.iter() {
        assert_rule_match!(Rule::path, i);
    }
}

#[test]
fn test_directive_expression() {
    let s = vec!["{{* ssh}}", "{{~* ssh}}"];
    for i in s.iter() {
        assert_rule!(Rule::directive_expression, i);
    }
}

#[test]
fn test_directive_block() {
    let s = vec![
        "{{#* inline}}something{{/inline}}",
        "{{~#* inline}}hello{{/inline}}",
        "{{#* inline \"partialname\"}}something{{/inline}}",
    ];
    for i in s.iter() {
        assert_rule!(Rule::directive_block, i);
    }
}

#[test]
fn test_partial_expression() {
    let s = vec![
        "{{> hello}}",
        "{{> (hello)}}",
        "{{~> hello a}}",
        "{{> hello a=1}}",
    ];
    for i in s.iter() {
        assert_rule!(Rule::partial_expression, i);
    }
}

#[test]
fn test_partial_block() {
    let s = vec!["{{#> hello}}nice{{/hello}}"];
    for i in s.iter() {
        assert_rule!(Rule::partial_block, i);
    }
}
<commit_msg>(test) provided failing test for #216<commit_after>//const _GRAMMAR: &'static str = include_str!("grammar.pest");

#[derive(Parser)]
#[grammar = "grammar.pest"]
pub struct HandlebarsParser;

#[cfg(test)]
use pest::Parser;

#[cfg(test)]
macro_rules! assert_rule {
    ($rule:expr, $in:expr) => {
        assert_eq!(
            HandlebarsParser::parse($rule, $in)
                .unwrap()
                .last()
                .unwrap()
                .into_span()
                .end(),
            $in.len()
        );
    };
}

#[cfg(test)]
macro_rules! assert_not_rule {
    ($rule:expr, $in:expr) => {
        assert!(!
            HandlebarsParser::parse($rule, $in)
                .unwrap()
                .last()
                .unwrap()
                .into_span()
                .end() ==
            $in.len()
        );
    };
}

#[cfg(test)]
macro_rules! assert_rule_match {
    ($rule:expr, $in:expr) => {
        assert!(HandlebarsParser::parse($rule, $in).is_ok());
    };
}

#[test]
fn test_raw_text() {
    let s = vec![
        "
 helloworld
    ",
        r"hello\{{world}}",
        r"hello\{{#if world}}nice\{{/if}}",
        r"hello \{{{{raw}}}}hello\{{{{/raw}}}}",
    ];
    for i in s.iter() {
        assert_rule!(Rule::raw_text, i);
    }

    let s_not_escape = vec![
        r"\\{{hello}}"
    ];
    for i in s_not_escape.iter() {
        assert_not_rule!(Rule::raw_text, i);
    }
}

#[test]
fn test_raw_block_text() {
    let s = "
 {{hello}}
";
    assert_rule!(Rule::raw_block_text, s);
}

#[test]
fn test_reference() {
    let s = vec![
        "a",
        "abc",
        "../a",
        "a.b",
        "@abc",
        "a.[abc]",
        "aBc.[abc]",
        "abc.[0].[nice]",
        "some-name",
        "this.[0].ok",
    ];
    for i in s.iter() {
        assert_rule!(Rule::reference, i);
    }
}

#[test]
fn test_name() {
    let s = vec!["if", "(abc)"];
    for i in s.iter() {
        assert_rule!(Rule::name, i);
    }
}

#[test]
fn test_param() {
    let s = vec!["hello", "\"json literal\""];
    for i in s.iter() {
        assert_rule!(Rule::param, i);
    }
}

#[test]
fn test_hash() {
    let s = vec![
        "hello=world",
        "hello=\"world\"",
        "hello=(world)",
        "hello=(world 0)",
    ];
    for i in s.iter() {
        assert_rule!(Rule::hash, i);
    }
}

#[test]
fn test_json_literal() {
    let s = vec![
        "\"json string\"",
        "\"quot: \\\"\"",
        "[]",
        "[\"hello\"]",
        "[1,2,3,4,true]",
        "{\"hello\": \"world\"}",
        "{}",
        "{\"a\":1, \"b\":2 }",
    ];
    for i in s.iter() {
        assert_rule!(Rule::literal, i);
    }
}

#[test]
fn test_comment() {
    let s = vec!["{{!-- <hello {{ a-b c-d}} {{d-c}} ok --}}",
                 "{{!--

{{this.title}}

                --}}"];
    for i in s.iter() {
        assert_rule!(Rule::hbs_comment, i);
    }
    let s2 = vec!["{{! hello }}", "{{! test me }}"];
    for i in s2.iter() {
        assert_rule!(Rule::hbs_comment_compact, i);
    }
}

#[test]
fn test_subexpression() {
    let s = vec!["(sub)", "(sub 0)", "(sub a=1)"];
    for i in s.iter() {
        assert_rule!(Rule::subexpression, i);
    }
}

#[test]
fn test_expression() {
    let s = vec!["{{exp}}", "{{(exp)}}", "{{this.name}}", "{{this.[0].name}}"];
    for i in s.iter() {
        assert_rule!(Rule::expression, i);
    }
}

#[test]
fn test_helper_expression() {
    let s = vec![
        "{{exp 1}}",
        "{{exp \"literal\"}}",
        "{{exp ref}}",
        "{{exp (sub)}}",
        "{{exp (sub 123)}}",
        "{{exp []}}",
        "{{exp {}}}",
        "{{exp key=1}}",
        "{{exp key=ref}}",
        "{{exp key=(sub)}}",
        "{{exp key=(sub 0)}}",
    ];
    for i in s.iter() {
        assert_rule!(Rule::helper_expression, i);
    }
}

#[test]
fn test_identifier_with_dash() {
    let s = vec!["{{exp-foo}}"];
    for i in s.iter() {
        assert_rule!(Rule::expression, i);
    }
}

#[test]
fn test_html_expression() {
    let s = vec!["{{{html}}}", "{{{(html)}}}", "{{{(html)}}}"];
    for i in s.iter() {
        assert_rule!(Rule::html_expression, i);
    }
}

#[test]
fn test_helper_start() {
    let s = vec![
        "{{#if hello}}",
        "{{#if (hello)}}",
        "{{#if hello=world}}",
        "{{#if hello hello=world}}",
        "{{#if []}}",
        "{{#if {}}}",
        "{{#if}}",
        "{{~#if hello~}}",
        "{{#each people as |person|}}",
        "{{#each-obj obj as |key val|}}",
        "{{#each assets}}",
    ];
    for i in s.iter() {
        assert_rule!(Rule::helper_block_start, i);
    }
}

#[test]
fn test_helper_end() {
    let s = vec!["{{/if}}", "{{~/if}}", "{{~/if ~}}", "{{/if   ~}}"];
    for i in s.iter() {
        assert_rule!(Rule::helper_block_end, i);
    }
}

#[test]
fn test_helper_block() {
    let s = vec![
        "{{#if hello}}hello{{/if}}",
        "{{#if true}}hello{{/if}}",
        "{{#if nice ok=1}}hello{{/if}}",
        "{{#if}}hello{{else}}world{{/if}}",
        "{{#if}}hello{{^}}world{{/if}}",
        "{{#if}}{{#if}}hello{{/if}}{{/if}}",
        "{{#if}}hello{{~else}}world{{/if}}",
        "{{#if}}hello{{else~}}world{{/if}}",
        "{{#if}}hello{{~^~}}world{{/if}}",
        "{{#if}}{{/if}}",
    ];
    for i in s.iter() {
        assert_rule!(Rule::helper_block, i);
    }
}

#[test]
fn test_raw_block() {
    let s = vec![
        "{{{{if hello}}}}good {{hello}}{{{{/if}}}}",
        "{{{{if hello}}}}{{#if nice}}{{/if}}{{{{/if}}}}",
    ];
    for i in s.iter() {
        assert_rule!(Rule::raw_block, i);
    }
}

#[test]
fn test_block_param() {
    let s = vec!["as |person|", "as |key val|"];
    for i in s.iter() {
        assert_rule!(Rule::block_param, i);
    }
}

#[test]
fn test_path() {
    let s = vec![
        "a",
        "a.b.c.d",
        "a.[0].[1].[2]",
        "a.[abc]",
        "a/v/c.d.s",
        "a.[0]/b/c/../d",
        "a.[bb c]/b/c/../d",
        "a.[0].[#hello]",
        "../a/b.[0].[1]",
        "./this.[0]/[1]/this/../a",
        "./this_name",
        "./goo/[/bar]",
        "a.[你好]",
        "a.[10].[#comment]",
        "a.[]", // empty key
        "././[/foo]",
        "[foo]",
    ];
    for i in s.iter() {
        assert_rule_match!(Rule::path, i);
    }
}

#[test]
fn test_directive_expression() {
    let s = vec!["{{* ssh}}", "{{~* ssh}}"];
    for i in s.iter() {
        assert_rule!(Rule::directive_expression, i);
    }
}

#[test]
fn test_directive_block() {
    let s = vec![
        "{{#* inline}}something{{/inline}}",
        "{{~#* inline}}hello{{/inline}}",
        "{{#* inline \"partialname\"}}something{{/inline}}",
    ];
    for i in s.iter() {
        assert_rule!(Rule::directive_block, i);
    }
}

#[test]
fn test_partial_expression() {
    let s = vec![
        "{{> hello}}",
        "{{> (hello)}}",
        "{{~> hello a}}",
        "{{> hello a=1}}",
    ];
    for i in s.iter() {
        assert_rule!(Rule::partial_expression, i);
    }
}

#[test]
fn test_partial_block() {
    let s = vec!["{{#> hello}}nice{{/hello}}"];
    for i in s.iter() {
        assert_rule!(Rule::partial_block, i);
    }
}
<|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/. */

use euclid::Size2D;
use servo_media::player::context::{GlApi, GlContext, NativeDisplay, PlayerGLContext};

/// Helper function that creates a GLPlayer channel (GLPlayerSender,
/// GLPlayerReceiver) to be used in GLPlayerMsg.
pub use crate::media_channel::glplayer_channel;
/// Entry point channel type used for sending GLPlayerMsg messages to
/// the GLPlayer thread.
pub use crate::media_channel::GLPlayerChan;
/// Entry point type used in a Script Pipeline to get the GLPlayerChan
/// to be used in that thread.
pub use crate::media_channel::GLPlayerPipeline;
/// Receiver type used in GLPlayerMsg.
pub use crate::media_channel::GLPlayerReceiver;
/// Result type for send()/recv() calls in in GLPlayerMsg.
pub use crate::media_channel::GLPlayerSendResult;
/// Sender type used in GLPlayerMsg.
pub use crate::media_channel::GLPlayerSender;

/// GLPlayer thread Message API
///
/// These are the message that the thread will receive from the
/// constellation, the webrender::ExternalImageHandle multiplexor
/// implementation, or a htmlmediaelement
#[derive(Debug, Deserialize, Serialize)]
pub enum GLPlayerMsg {
    /// Registers an instantiated player in DOM
    RegisterPlayer(GLPlayerSender<u64>),
    /// Unregisters a player's ID
    UnregisterPlayer(u64),
    /// Locks a specific texture from a player. Lock messages are used
    /// for a correct synchronization with WebRender external image
    /// API.
    ///
    /// WR locks a external texture when it wants to use the shared
    /// texture contents.
    ///
    /// The WR client should not change the shared texture content
    /// until the Unlock call.
    ///
    /// Currently OpenGL Sync Objects are used to implement the
    /// synchronization mechanism.
    Lock(u64, GLPlayerSender<(u32, Size2D<i32>, usize)>),
    /// Unlocks a specific texture from a player. Unlock messages are
    /// used for a correct synchronization with WebRender external
    /// image API.
    ///
    /// The WR unlocks a context when it finished reading the shared
    /// texture contents.
    ///
    /// Unlock messages are always sent after a Lock message.
    Unlock(u64),
    /// Frees all resources and closes the thread.
    Exit,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct WindowGLContext {
    /// Application's GL Context
    pub gl_context: GlContext,
    /// Application's GL Api
    pub gl_api: GlApi,
    /// Application's native display
    pub native_display: NativeDisplay,
    /// A channel to the GLPlayer thread.
    pub glplayer_chan: Option<GLPlayerPipeline>,
}

impl PlayerGLContext for WindowGLContext {
    fn get_gl_context(&self) -> GlContext {
        self.gl_context.clone()
    }

    fn get_native_display(&self) -> NativeDisplay {
        self.native_display.clone()
    }

    fn get_gl_api(&self) -> GlApi {
        self.gl_api.clone()
    }
}
<commit_msg>Add GLPlayerMsgForward enum<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/. */

use euclid::Size2D;
use servo_media::player::context::{GlApi, GlContext, NativeDisplay, PlayerGLContext};

/// Helper function that creates a GLPlayer channel (GLPlayerSender,
/// GLPlayerReceiver) to be used in GLPlayerMsg.
pub use crate::media_channel::glplayer_channel;
/// Entry point channel type used for sending GLPlayerMsg messages to
/// the GLPlayer thread.
pub use crate::media_channel::GLPlayerChan;
/// Entry point type used in a Script Pipeline to get the GLPlayerChan
/// to be used in that thread.
pub use crate::media_channel::GLPlayerPipeline;
/// Receiver type used in GLPlayerMsg.
pub use crate::media_channel::GLPlayerReceiver;
/// Result type for send()/recv() calls in in GLPlayerMsg.
pub use crate::media_channel::GLPlayerSendResult;
/// Sender type used in GLPlayerMsg.
pub use crate::media_channel::GLPlayerSender;

/// These are the messages that the GLPlayer thread will forward to
/// the video player which lives in htmlmediaelement
#[derive(Debug, Deserialize, Serialize)]
pub enum GLPlayerMsgForward {
    PlayerId(u64),
    Lock(GLPlayerSender<(u32, Size2D<i32>, usize)>),
    Unlock(),
}

/// GLPlayer thread Message API
///
/// These are the message that the thread will receive from the
/// constellation, the webrender::ExternalImageHandle multiplexor
/// implementation, or a htmlmediaelement
#[derive(Debug, Deserialize, Serialize)]
pub enum GLPlayerMsg {
    /// Registers an instantiated player in DOM
    RegisterPlayer(GLPlayerSender<GLPlayerMsgForward>),
    /// Unregisters a player's ID
    UnregisterPlayer(u64),
    /// Locks a specific texture from a player. Lock messages are used
    /// for a correct synchronization with WebRender external image
    /// API.
    ///
    /// WR locks a external texture when it wants to use the shared
    /// texture contents.
    ///
    /// The WR client should not change the shared texture content
    /// until the Unlock call.
    ///
    /// Currently OpenGL Sync Objects are used to implement the
    /// synchronization mechanism.
    Lock(u64, GLPlayerSender<(u32, Size2D<i32>, usize)>),
    /// Unlocks a specific texture from a player. Unlock messages are
    /// used for a correct synchronization with WebRender external
    /// image API.
    ///
    /// The WR unlocks a context when it finished reading the shared
    /// texture contents.
    ///
    /// Unlock messages are always sent after a Lock message.
    Unlock(u64),
    /// Frees all resources and closes the thread.
    Exit,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct WindowGLContext {
    /// Application's GL Context
    pub gl_context: GlContext,
    /// Application's GL Api
    pub gl_api: GlApi,
    /// Application's native display
    pub native_display: NativeDisplay,
    /// A channel to the GLPlayer thread.
    pub glplayer_chan: Option<GLPlayerPipeline>,
}

impl PlayerGLContext for WindowGLContext {
    fn get_gl_context(&self) -> GlContext {
        self.gl_context.clone()
    }

    fn get_native_display(&self) -> NativeDisplay {
        self.native_display.clone()
    }

    fn get_gl_api(&self) -> GlApi {
        self.gl_api.clone()
    }
}
<|endoftext|>


<commit_before>use rustc_index::vec::{Idx, IndexVec};
use std::mem;
use std::ptr;

pub trait IdFunctor: Sized {
    type Inner;

    #[inline]
    fn map_id<F>(self, mut f: F) -> Self
    where
        F: FnMut(Self::Inner) -> Self::Inner,
    {
        self.try_map_id::<_, !>(|value| Ok(f(value))).into_ok()
    }

    fn try_map_id<F, E>(self, f: F) -> Result<Self, E>
    where
        F: FnMut(Self::Inner) -> Result<Self::Inner, E>;
}

impl<T> IdFunctor for Box<T> {
    type Inner = T;

    #[inline]
    fn try_map_id<F, E>(self, mut f: F) -> Result<Self, E>
    where
        F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
    {
        let raw = Box::into_raw(self);
        Ok(unsafe {
            // SAFETY: The raw pointer points to a valid value of type `T`.
            let value = ptr::read(raw);
            // SAFETY: Converts `Box<T>` to `Box<MaybeUninit<T>>` which is the
            // inverse of `Box::assume_init()` and should be safe.
            let mut raw: Box<mem::MaybeUninit<T>> = Box::from_raw(raw.cast());
            // SAFETY: Write the mapped value back into the `Box`.
            ptr::write(raw.as_mut_ptr(), f(value)?);
            // SAFETY: We just initialized `raw`.
            raw.assume_init()
        })
    }
}

impl<T> IdFunctor for Vec<T> {
    type Inner = T;

    #[inline]
    fn try_map_id<F, E>(mut self, mut f: F) -> Result<Self, E>
    where
        F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
    {
        // FIXME: We don't really care about panics here and leak
        // far more than we should, but that should be fine for now.
        let len = self.len();
        unsafe {
            self.set_len(0);
            let start = self.as_mut_ptr();
            for i in 0..len {
                let p = start.add(i);
                match f(ptr::read(p)) {
                    Ok(value) => ptr::write(p, value),
                    Err(err) => {
                        // drop all other elements in self
                        // (current element was "moved" into the call to f)
                        for j in (0..i).chain(i + 1..len) {
                            let p = start.add(j);
                            ptr::drop_in_place(p);
                        }

                        // returning will drop self, releasing the allocation
                        // (len is 0 so elements will not be re-dropped)
                        return Err(err);
                    }
                }
            }
            // Even if we encountered an error, set the len back
            // so we don't leak memory.
            self.set_len(len);
        }
        Ok(self)
    }
}

impl<T> IdFunctor for Box<[T]> {
    type Inner = T;

    #[inline]
    fn try_map_id<F, E>(self, f: F) -> Result<Self, E>
    where
        F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
    {
        Vec::from(self).try_map_id(f).map(Into::into)
    }
}

impl<I: Idx, T> IdFunctor for IndexVec<I, T> {
    type Inner = T;

    #[inline]
    fn try_map_id<F, E>(self, f: F) -> Result<Self, E>
    where
        F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
    {
        self.raw.try_map_id(f).map(IndexVec::from_raw)
    }
}
<commit_msg>Use intrinsic pointer methods<commit_after>use rustc_index::vec::{Idx, IndexVec};
use std::mem;

pub trait IdFunctor: Sized {
    type Inner;

    #[inline]
    fn map_id<F>(self, mut f: F) -> Self
    where
        F: FnMut(Self::Inner) -> Self::Inner,
    {
        self.try_map_id::<_, !>(|value| Ok(f(value))).into_ok()
    }

    fn try_map_id<F, E>(self, f: F) -> Result<Self, E>
    where
        F: FnMut(Self::Inner) -> Result<Self::Inner, E>;
}

impl<T> IdFunctor for Box<T> {
    type Inner = T;

    #[inline]
    fn try_map_id<F, E>(self, mut f: F) -> Result<Self, E>
    where
        F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
    {
        let raw = Box::into_raw(self);
        Ok(unsafe {
            // SAFETY: The raw pointer points to a valid value of type `T`.
            let value = raw.read();
            // SAFETY: Converts `Box<T>` to `Box<MaybeUninit<T>>` which is the
            // inverse of `Box::assume_init()` and should be safe.
            let mut raw: Box<mem::MaybeUninit<T>> = Box::from_raw(raw.cast());
            // SAFETY: Write the mapped value back into the `Box`.
            raw.write(f(value)?);
            // SAFETY: We just initialized `raw`.
            raw.assume_init()
        })
    }
}

impl<T> IdFunctor for Vec<T> {
    type Inner = T;

    #[inline]
    fn try_map_id<F, E>(mut self, mut f: F) -> Result<Self, E>
    where
        F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
    {
        // FIXME: We don't really care about panics here and leak
        // far more than we should, but that should be fine for now.
        let len = self.len();
        unsafe {
            self.set_len(0);
            let start = self.as_mut_ptr();
            for i in 0..len {
                let p = start.add(i);
                match f(p.read()) {
                    Ok(val) => p.write(val),
                    Err(err) => {
                        // drop all other elements in self
                        // (current element was "moved" into the call to f)
                        for j in (0..i).chain(i + 1..len) {
                            start.add(j).drop_in_place();
                        }

                        // returning will drop self, releasing the allocation
                        // (len is 0 so elements will not be re-dropped)
                        return Err(err);
                    }
                }
            }
            // Even if we encountered an error, set the len back
            // so we don't leak memory.
            self.set_len(len);
        }
        Ok(self)
    }
}

impl<T> IdFunctor for Box<[T]> {
    type Inner = T;

    #[inline]
    fn try_map_id<F, E>(self, f: F) -> Result<Self, E>
    where
        F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
    {
        Vec::from(self).try_map_id(f).map(Into::into)
    }
}

impl<I: Idx, T> IdFunctor for IndexVec<I, T> {
    type Inner = T;

    #[inline]
    fn try_map_id<F, E>(self, f: F) -> Result<Self, E>
    where
        F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
    {
        self.raw.try_map_id(f).map(IndexVec::from_raw)
    }
}
<|endoftext|>