<commit_before>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

use anyhow::Result;
use humantime::parse_duration;
use serde::{Deserialize, Serialize};
use std::rc::Rc;
use std::time::Duration;
use structopt::clap::arg_enum;
use structopt::StructOpt;
use thiserror::Error;

use crate::app::TransportWrapper;
use crate::impl_serializable_error;
use crate::io::gpio::GpioPin;
use crate::io::spi::SpiParams;
use crate::io::uart::UartParams;
use crate::transport::Capability;

mod eeprom;
mod legacy;
mod primitive;
mod rescue;

pub use legacy::LegacyBootstrapError;
pub use rescue::RescueError;

#[derive(Debug, Error, Serialize, Deserialize)]
pub enum BootstrapError {
    #[error("Invalid hash length: {0}")]
    InvalidHashLength(usize),
}
impl_serializable_error!(BootstrapError);

arg_enum! {
    /// `BootstrapProtocol` describes the supported types of bootstrap.
    /// The `Primitive` SPI protocol is used by OpenTitan during development.
    /// The `Legacy` SPI protocol is used by previous generations of Google Titan-class chips.
    /// The `Eeprom` SPI protocol is planned to be implemented for OpenTitan.
    /// The `Rescue` UART protocol is used by Google Ti50 firmware.
    /// The 'Emulator' value indicates that this tool has a direct way
    /// of communicating with the OpenTitan emulator, to replace the
    /// contents of the emulated flash storage.
    #[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
    pub enum BootstrapProtocol {
        Primitive,
        Legacy,
        Eeprom,
        Rescue,
        Emulator,
    }
}

// Implementations of bootstrap need to implement the `UpdateProtocol` trait.
trait UpdateProtocol {
    /// Called before any action is taken, to allow the protocol to verify that the transport
    /// supports SPI/UART or whatever it needs.
    fn verify_capabilities(
        &self,
        container: &Bootstrap,
        transport: &TransportWrapper,
    ) -> Result<()>;
    /// Indicates whether the caller should assert the bootstrap pin and reset the chip, before
    /// invoking update().
    fn uses_common_bootstrap_reset(&self) -> bool;
    /// Invoked to perform the actual transfer of an executable image to the OpenTitan chip.
    fn update(
        &self,
        container: &Bootstrap,
        transport: &TransportWrapper,
        payload: &[u8],
        progress: &dyn Fn(u32, u32),
    ) -> Result<()>;
}

/// Options which control bootstrap behavior.
/// The meaning of each of these values depends on the specific bootstrap protocol being used.
#[derive(Clone, Debug, StructOpt, Serialize, Deserialize)]
pub struct BootstrapOptions {
    #[structopt(flatten)]
    pub uart_params: UartParams,
    #[structopt(flatten)]
    pub spi_params: SpiParams,
    #[structopt(
        short,
        long,
        possible_values = &BootstrapProtocol::variants(),
        case_insensitive = true,
        default_value = "eeprom",
        help = "Bootstrap protocol to use"
    )]
    pub protocol: BootstrapProtocol,
    #[structopt(long, parse(try_from_str=parse_duration), help = "Duration of the reset delay")]
    pub reset_delay: Option<Duration>,
    #[structopt(long, parse(try_from_str=parse_duration), help = "Duration of the inter-frame delay")]
    pub inter_frame_delay: Option<Duration>,
    #[structopt(long, parse(try_from_str=parse_duration), help = "Duration of the flash-erase delay")]
    pub flash_erase_delay: Option<Duration>,
}

/// Bootstrap wraps and drives the various bootstrap protocols.
pub struct Bootstrap<'a> {
    pub protocol: BootstrapProtocol,
    pub uart_params: &'a UartParams,
    pub spi_params: &'a SpiParams,
    reset_pin: Rc<dyn GpioPin>,
    reset_delay: Duration,
}

impl<'a> Bootstrap<'a> {
    const RESET_DELAY: Duration = Duration::from_millis(200);

    /// Perform the update, sending the firmware `payload` to a SPI or UART target depending on
    /// given `options`, which specifies protocol and port to use.
    pub fn update(
        transport: &TransportWrapper,
        options: &BootstrapOptions,
        payload: &[u8],
    ) -> Result<()> {
        Self::update_with_progress(transport, options, payload, |_, _| {})
    }

    /// Perform the update, sending the firmware `payload` to a SPI or UART target depending on
    /// given `options`, which specifies protocol and port to use.  The `progress` callback will
    /// be called with the flash address and length of each chunk sent to the target device.
    pub fn update_with_progress(
        transport: &TransportWrapper,
        options: &BootstrapOptions,
        payload: &[u8],
        progress: impl Fn(u32, u32),
    ) -> Result<()> {
        if transport
            .capabilities()?
            .request(Capability::PROXY)
            .ok()
            .is_ok()
        {
            // The transport happens to be connection to a remove opentitan session.  Pass
            // payload along with all relevant command line arguments to the remote session, and
            // it will run the actual bootstrapping logic.
            transport.proxy_ops()?.bootstrap(options, payload)?;
            return Ok(());
        }
        let updater: Box<dyn UpdateProtocol> = match options.protocol {
            BootstrapProtocol::Primitive => Box::new(primitive::Primitive::new(&options)),
            BootstrapProtocol::Legacy => Box::new(legacy::Legacy::new(&options)),
            BootstrapProtocol::Rescue => Box::new(rescue::Rescue::new(&options)),
            BootstrapProtocol::Eeprom => Box::new(eeprom::Eeprom::new()),
            BootstrapProtocol::Emulator => {
                // Not intended to be implemented by this struct.
                unimplemented!();
            }
        };
        Bootstrap {
            protocol: options.protocol,
            uart_params: &options.uart_params,
            spi_params: &options.spi_params,
            reset_pin: transport.gpio_pin("RESET")?,
            reset_delay: options.reset_delay.unwrap_or(Self::RESET_DELAY),
        }
        .do_update(updater, transport, payload, &progress)
    }

    fn do_update(
        &self,
        updater: Box<dyn UpdateProtocol>,
        transport: &TransportWrapper,
        payload: &[u8],
        progress: &dyn Fn(u32, u32),
    ) -> Result<()> {
        updater.verify_capabilities(&self, transport)?;
        let perform_bootstrap_reset = updater.uses_common_bootstrap_reset();

        if perform_bootstrap_reset {
            log::info!("Asserting bootstrap pins...");
            transport.apply_pin_strapping("ROM_BOOTSTRAP")?;

            log::info!("Reseting the target...");
            transport.apply_pin_strapping("RESET")?;
            std::thread::sleep(self.reset_delay);
            transport.remove_pin_strapping("RESET")?;
            std::thread::sleep(self.reset_delay);

            log::info!("Performing bootstrap...");
        }
        let result = updater.update(&self, transport, payload, progress);

        if perform_bootstrap_reset {
            log::info!("Releasing bootstrap pins...");
            transport.remove_pin_strapping("ROM_BOOTSTRAP")?;
        }
        result
    }
}
<commit_msg>[opentitanlib] Add capability to clear UART RX buffer after bootstrap<commit_after>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

use anyhow::Result;
use humantime::parse_duration;
use serde::{Deserialize, Serialize};
use std::rc::Rc;
use std::time::Duration;
use structopt::clap::arg_enum;
use structopt::StructOpt;
use thiserror::Error;

use crate::app::TransportWrapper;
use crate::impl_serializable_error;
use crate::io::gpio::GpioPin;
use crate::io::spi::SpiParams;
use crate::io::uart::UartParams;
use crate::transport::Capability;

mod eeprom;
mod legacy;
mod primitive;
mod rescue;

pub use legacy::LegacyBootstrapError;
pub use rescue::RescueError;

#[derive(Debug, Error, Serialize, Deserialize)]
pub enum BootstrapError {
    #[error("Invalid hash length: {0}")]
    InvalidHashLength(usize),
}
impl_serializable_error!(BootstrapError);

arg_enum! {
    /// `BootstrapProtocol` describes the supported types of bootstrap.
    /// The `Primitive` SPI protocol is used by OpenTitan during development.
    /// The `Legacy` SPI protocol is used by previous generations of Google Titan-class chips.
    /// The `Eeprom` SPI protocol is planned to be implemented for OpenTitan.
    /// The `Rescue` UART protocol is used by Google Ti50 firmware.
    /// The 'Emulator' value indicates that this tool has a direct way
    /// of communicating with the OpenTitan emulator, to replace the
    /// contents of the emulated flash storage.
    #[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
    pub enum BootstrapProtocol {
        Primitive,
        Legacy,
        Eeprom,
        Rescue,
        Emulator,
    }
}

// Implementations of bootstrap need to implement the `UpdateProtocol` trait.
trait UpdateProtocol {
    /// Called before any action is taken, to allow the protocol to verify that the transport
    /// supports SPI/UART or whatever it needs.
    fn verify_capabilities(
        &self,
        container: &Bootstrap,
        transport: &TransportWrapper,
    ) -> Result<()>;
    /// Indicates whether the caller should assert the bootstrap pin and reset the chip, before
    /// invoking update().
    fn uses_common_bootstrap_reset(&self) -> bool;
    /// Invoked to perform the actual transfer of an executable image to the OpenTitan chip.
    fn update(
        &self,
        container: &Bootstrap,
        transport: &TransportWrapper,
        payload: &[u8],
        progress: &dyn Fn(u32, u32),
    ) -> Result<()>;
}

/// Options which control bootstrap behavior.
/// The meaning of each of these values depends on the specific bootstrap protocol being used.
#[derive(Clone, Debug, StructOpt, Serialize, Deserialize)]
pub struct BootstrapOptions {
    #[structopt(flatten)]
    pub uart_params: UartParams,
    #[structopt(flatten)]
    pub spi_params: SpiParams,
    #[structopt(
        short,
        long,
        possible_values = &BootstrapProtocol::variants(),
        case_insensitive = true,
        default_value = "eeprom",
        help = "Bootstrap protocol to use"
    )]
    pub protocol: BootstrapProtocol,
    #[structopt(
        long,
        help = "Whether to reset target and clear UART RX buffer after bootstrap. For CW310 only."
    )]
    pub no_clear_uart_rx: Option<bool>,
    #[structopt(long, parse(try_from_str=parse_duration), help = "Duration of the reset delay")]
    pub reset_delay: Option<Duration>,
    #[structopt(long, parse(try_from_str=parse_duration), help = "Duration of the inter-frame delay")]
    pub inter_frame_delay: Option<Duration>,
    #[structopt(long, parse(try_from_str=parse_duration), help = "Duration of the flash-erase delay")]
    pub flash_erase_delay: Option<Duration>,
}

/// Bootstrap wraps and drives the various bootstrap protocols.
pub struct Bootstrap<'a> {
    pub protocol: BootstrapProtocol,
    pub clear_uart_rx: bool,
    pub uart_params: &'a UartParams,
    pub spi_params: &'a SpiParams,
    reset_pin: Rc<dyn GpioPin>,
    reset_delay: Duration,
}

impl<'a> Bootstrap<'a> {
    const RESET_DELAY: Duration = Duration::from_millis(200);

    /// Perform the update, sending the firmware `payload` to a SPI or UART target depending on
    /// given `options`, which specifies protocol and port to use.
    pub fn update(
        transport: &TransportWrapper,
        options: &BootstrapOptions,
        payload: &[u8],
    ) -> Result<()> {
        Self::update_with_progress(transport, options, payload, |_, _| {})
    }

    /// Perform the update, sending the firmware `payload` to a SPI or UART target depending on
    /// given `options`, which specifies protocol and port to use.  The `progress` callback will
    /// be called with the flash address and length of each chunk sent to the target device.
    pub fn update_with_progress(
        transport: &TransportWrapper,
        options: &BootstrapOptions,
        payload: &[u8],
        progress: impl Fn(u32, u32),
    ) -> Result<()> {
        if transport
            .capabilities()?
            .request(Capability::PROXY)
            .ok()
            .is_ok()
        {
            // The transport happens to be connection to a remove opentitan session.  Pass
            // payload along with all relevant command line arguments to the remote session, and
            // it will run the actual bootstrapping logic.
            transport.proxy_ops()?.bootstrap(options, payload)?;
            return Ok(());
        }
        let updater: Box<dyn UpdateProtocol> = match options.protocol {
            BootstrapProtocol::Primitive => Box::new(primitive::Primitive::new(&options)),
            BootstrapProtocol::Legacy => Box::new(legacy::Legacy::new(&options)),
            BootstrapProtocol::Rescue => Box::new(rescue::Rescue::new(&options)),
            BootstrapProtocol::Eeprom => Box::new(eeprom::Eeprom::new()),
            BootstrapProtocol::Emulator => {
                // Not intended to be implemented by this struct.
                unimplemented!();
            }
        };
        Bootstrap {
            protocol: options.protocol,
            clear_uart_rx: !options.no_clear_uart_rx.unwrap_or(false),
            uart_params: &options.uart_params,
            spi_params: &options.spi_params,
            reset_pin: transport.gpio_pin("RESET")?,
            reset_delay: options.reset_delay.unwrap_or(Self::RESET_DELAY),
        }
        .do_update(updater, transport, payload, &progress)
    }

    fn do_update(
        &self,
        updater: Box<dyn UpdateProtocol>,
        transport: &TransportWrapper,
        payload: &[u8],
        progress: &dyn Fn(u32, u32),
    ) -> Result<()> {
        updater.verify_capabilities(&self, transport)?;
        let perform_bootstrap_reset = updater.uses_common_bootstrap_reset();

        if perform_bootstrap_reset {
            log::info!("Asserting bootstrap pins...");
            transport.apply_pin_strapping("ROM_BOOTSTRAP")?;
            transport.reset_target(self.reset_delay, self.clear_uart_rx)?;
            log::info!("Performing bootstrap...");
        }
        let result = updater.update(&self, transport, payload, progress);

        if perform_bootstrap_reset {
            log::info!("Releasing bootstrap pins...");
            transport.remove_pin_strapping("ROM_BOOTSTRAP")?;
        }

        // Don't clear the UART RX buffer after bootstrap to preserve the bootstrap output.
        transport.reset_target(self.reset_delay, false)?;
        result
    }
}
<|endoftext|>


<commit_before>#![feature(core, exit_status)]

use std::env;
use std::io::BufRead;
mod ranger;
mod streamer;

fn help() -> i32 {
  println!("Usage: cmded-getline <-|filename> <start line>[..<$|end line>]");
  1
}

macro_rules! validate {
  ($e:expr) => (match $e { Ok(e) => e, Err(_) => return help() })
}

fn get_lines(path: &str, range: &str) -> i32 {
  let stream = validate!(streamer::from(path));
  let (start, end) = validate!(ranger::from(range));
  if 1 > start || start > end {
    return help();
  }

  let mut count = 1;
  for line in stream.lines() {
    if start <= count && count <= end {
      println!("{}", line.unwrap());
    }
    count += 1;
  }
  0
}

fn main() {
  let args: Vec<_> = env::args().collect();
  match args.len() {
  3 => env::set_exit_status(get_lines(&args[1], &args[2])),
  _ => env::set_exit_status(help())
  }
}

<commit_msg>printing loop now breaks after last line that should be printed and doesn't wait until all lines are processed<commit_after>#![feature(core, exit_status)]

use std::env;
use std::io::BufRead;
mod ranger;
mod streamer;

fn help() -> i32 {
  println!("Usage: cmded-getline <-|filename> <start line>[..<$|end line>]");
  1
}

macro_rules! validate {
  ($e:expr) => (match $e { Ok(e) => e, Err(_) => return help() })
}

fn get_lines(path: &str, range: &str) -> i32 {
  let stream = validate!(streamer::from(path));
  let (start, end) = validate!(ranger::from(range));
  if 1 > start || start > end {
    return help();
  }

  let mut count = 1;
  for line in stream.lines() {
    if start <= count && count <= end { println!("{}", line.unwrap()); }
    count += 1;
    if count > end { break; }
  }
  0
}

fn main() {
  let args: Vec<_> = env::args().collect();
  match args.len() {
  3 => env::set_exit_status(get_lines(&args[1], &args[2])),
  _ => env::set_exit_status(help())
  }
}

<|endoftext|>


<commit_before>#![allow(unstable)]
#![no_std]
extern crate core;

use core::slice::AsSlice;
use core::str::StrExt;
use core::hash::{Writer, Hasher, Hash, SipHasher};

#[inline]
pub fn displace(f1: u32, f2: u32, d1: u32, d2: u32) -> u32 {
    d2 + f1 * d1 + f2
}

#[inline]
fn split(hash: u64) -> (u32, u32, u32) {
    const BITS: u32 = 21;
    const MASK: u64 = (1 << BITS) - 1;

    ((hash & MASK) as u32,
     ((hash >> BITS) & MASK) as u32,
     ((hash >> (2 * BITS)) & MASK) as u32)
}

/// A trait implemented by types which can be used in PHF data structures
pub trait PhfHash {
    /// Hashes the value of `self`, factoring in a seed
    fn phf_hash(&self, seed: u64) -> (u32, u32, u32);
}

impl<'a> PhfHash for &'a str {
    #[inline]
    fn phf_hash(&self, seed: u64) -> (u32, u32, u32) {
        self.as_bytes().phf_hash(seed)
    }
}

impl<'a> PhfHash for &'a [u8] {
    #[inline]
    fn phf_hash(&self, seed: u64) -> (u32, u32, u32) {
        (*self).phf_hash(seed)
    }
}

impl PhfHash for str {
    #[inline]
    fn phf_hash(&self, seed: u64) -> (u32, u32, u32) {
        self.as_bytes().phf_hash(seed)
    }
}

impl PhfHash for [u8] {
    #[inline]
    fn phf_hash(&self, seed: u64) -> (u32, u32, u32) {
        let mut state = SipHasher::new_with_keys(seed, 0);
        state.write(self);
        split(state.result())
    }
}

macro_rules! sip_impl(
    ($t:ty) => (
        impl PhfHash for $t {
            #[inline]
            fn phf_hash(&self, seed: u64) -> (u32, u32, u32) {
                let mut hasher = SipHasher::new_with_keys(seed, 0);
                self.hash(&mut hasher);
                split(hasher.finish())
            }
        }
    )
);

sip_impl!(u8);
sip_impl!(i8);
sip_impl!(u16);
sip_impl!(i16);
sip_impl!(u32);
sip_impl!(i32);
sip_impl!(u64);
sip_impl!(i64);
sip_impl!(char);
sip_impl!(bool);

macro_rules! array_impl(
    ($t:ty, $n:expr) => (
        impl PhfHash for [$t; $n] {
            #[inline]
            fn phf_hash(&self, seed: u64) -> (u32, u32, u32) {
                let mut hasher = SipHasher::new_with_keys(seed, 0);
                hasher.write(self.as_slice());
                split(hasher.finish())
            }
        }
    )
);

array_impl!(u8, 1);
array_impl!(u8, 2);
array_impl!(u8, 3);
array_impl!(u8, 4);
array_impl!(u8, 5);
array_impl!(u8, 6);
array_impl!(u8, 7);
array_impl!(u8, 8);
array_impl!(u8, 9);
array_impl!(u8, 10);
array_impl!(u8, 11);
array_impl!(u8, 12);
array_impl!(u8, 13);
array_impl!(u8, 14);
array_impl!(u8, 15);
array_impl!(u8, 16);
array_impl!(u8, 17);
array_impl!(u8, 18);
array_impl!(u8, 19);
array_impl!(u8, 20);
array_impl!(u8, 21);
array_impl!(u8, 22);
array_impl!(u8, 23);
array_impl!(u8, 24);
array_impl!(u8, 25);
array_impl!(u8, 26);
array_impl!(u8, 27);
array_impl!(u8, 28);
array_impl!(u8, 29);
array_impl!(u8, 30);
array_impl!(u8, 31);
array_impl!(u8, 32);
<commit_msg>Fix deprecation warning<commit_after>#![allow(unstable)]
#![no_std]
extern crate core;

use core::slice::AsSlice;
use core::str::StrExt;
use core::hash::{Writer, Hasher, Hash, SipHasher};

#[inline]
pub fn displace(f1: u32, f2: u32, d1: u32, d2: u32) -> u32 {
    d2 + f1 * d1 + f2
}

#[inline]
fn split(hash: u64) -> (u32, u32, u32) {
    const BITS: u32 = 21;
    const MASK: u64 = (1 << BITS) - 1;

    ((hash & MASK) as u32,
     ((hash >> BITS) & MASK) as u32,
     ((hash >> (2 * BITS)) & MASK) as u32)
}

/// A trait implemented by types which can be used in PHF data structures
pub trait PhfHash {
    /// Hashes the value of `self`, factoring in a seed
    fn phf_hash(&self, seed: u64) -> (u32, u32, u32);
}

impl<'a> PhfHash for &'a str {
    #[inline]
    fn phf_hash(&self, seed: u64) -> (u32, u32, u32) {
        self.as_bytes().phf_hash(seed)
    }
}

impl<'a> PhfHash for &'a [u8] {
    #[inline]
    fn phf_hash(&self, seed: u64) -> (u32, u32, u32) {
        (*self).phf_hash(seed)
    }
}

impl PhfHash for str {
    #[inline]
    fn phf_hash(&self, seed: u64) -> (u32, u32, u32) {
        self.as_bytes().phf_hash(seed)
    }
}

impl PhfHash for [u8] {
    #[inline]
    fn phf_hash(&self, seed: u64) -> (u32, u32, u32) {
        let mut state = SipHasher::new_with_keys(seed, 0);
        state.write(self);
        split(state.finish())
    }
}

macro_rules! sip_impl(
    ($t:ty) => (
        impl PhfHash for $t {
            #[inline]
            fn phf_hash(&self, seed: u64) -> (u32, u32, u32) {
                let mut hasher = SipHasher::new_with_keys(seed, 0);
                self.hash(&mut hasher);
                split(hasher.finish())
            }
        }
    )
);

sip_impl!(u8);
sip_impl!(i8);
sip_impl!(u16);
sip_impl!(i16);
sip_impl!(u32);
sip_impl!(i32);
sip_impl!(u64);
sip_impl!(i64);
sip_impl!(char);
sip_impl!(bool);

macro_rules! array_impl(
    ($t:ty, $n:expr) => (
        impl PhfHash for [$t; $n] {
            #[inline]
            fn phf_hash(&self, seed: u64) -> (u32, u32, u32) {
                let mut hasher = SipHasher::new_with_keys(seed, 0);
                hasher.write(self.as_slice());
                split(hasher.finish())
            }
        }
    )
);

array_impl!(u8, 1);
array_impl!(u8, 2);
array_impl!(u8, 3);
array_impl!(u8, 4);
array_impl!(u8, 5);
array_impl!(u8, 6);
array_impl!(u8, 7);
array_impl!(u8, 8);
array_impl!(u8, 9);
array_impl!(u8, 10);
array_impl!(u8, 11);
array_impl!(u8, 12);
array_impl!(u8, 13);
array_impl!(u8, 14);
array_impl!(u8, 15);
array_impl!(u8, 16);
array_impl!(u8, 17);
array_impl!(u8, 18);
array_impl!(u8, 19);
array_impl!(u8, 20);
array_impl!(u8, 21);
array_impl!(u8, 22);
array_impl!(u8, 23);
array_impl!(u8, 24);
array_impl!(u8, 25);
array_impl!(u8, 26);
array_impl!(u8, 27);
array_impl!(u8, 28);
array_impl!(u8, 29);
array_impl!(u8, 30);
array_impl!(u8, 31);
array_impl!(u8, 32);
<|endoftext|>


<commit_before>#[doc = "Rust wrappers around the raw JS apis"];

#[allow(non_implicitly_copyable_typarams)];

use bg = jsapi::bindgen;
use core::libc::types::os::arch::c95::{size_t, c_uint};
use core::libc::c_char;
use core::hashmap::linear::LinearMap;
use jsapi::*;
use jsapi::bindgen::*;
use default_stacksize;
use default_heapsize;
use JSOPTION_VAROBJFIX;
use JSOPTION_METHODJIT;
use JSOPTION_TYPE_INFERENCE;
use JSVAL_NULL;
use ERR;
use name_pool::*;
use core::ptr::null;
use result;
use result_obj;
use core::str::raw::from_c_str;

// ___________________________________________________________________________
// friendly Rustic API to runtimes

pub type rt = @rt_rsrc;

pub struct rt_rsrc {
    ptr : *JSRuntime,
}

impl Drop for rt_rsrc {
    fn finalize(&self) {
        unsafe {
            JS_Finish(self.ptr);
        }
    }
}

pub fn new_runtime(p: *JSRuntime) -> rt {
    return @rt_rsrc {
        ptr: p
    }
}

pub impl rt_rsrc {
    fn cx(@self) -> @Cx {
        unsafe {
            new_context(JS_NewContext(self.ptr, default_stacksize as size_t), self)
        }
    }
}

pub fn rt() -> rt {
    unsafe {
        return new_runtime(JS_Init(default_heapsize))
    }
}

// ___________________________________________________________________________
// contexts

pub struct Cx {
    ptr: *JSContext,
    rt: rt,
    classes: @mut LinearMap<~str, @JSClass>,
}

#[unsafe_destructor]
impl Drop for Cx {
    fn finalize(&self) {
        unsafe {
            JS_DestroyContext(self.ptr);
        }
    }
}

pub fn new_context(ptr: *JSContext, rt: rt) -> @Cx {
    return @Cx {
        ptr: ptr,
        rt: rt,
        classes: @mut LinearMap::new()
    }
}

pub impl Cx {
    fn rooted_obj(@self, obj: *JSObject) -> jsobj {
        let jsobj = @jsobj_rsrc {cx: self, cxptr: self.ptr, ptr: obj};
        unsafe {
            JS_AddObjectRoot(self.ptr, ptr::to_unsafe_ptr(&jsobj.ptr));
        }
        jsobj
    }

    fn set_default_options_and_version(@self) {
        self.set_options(JSOPTION_VAROBJFIX | JSOPTION_METHODJIT |
                         JSOPTION_TYPE_INFERENCE);
        self.set_version(JSVERSION_LATEST);
    }

    fn set_options(@self, v: c_uint) {
        unsafe {
            JS_SetOptions(self.ptr, v);
        }
    }

    fn set_version(@self, v: i32) {
        unsafe {
            JS_SetVersion(self.ptr, v);
        }
    }

    fn set_logging_error_reporter(@self) {
        unsafe {
            JS_SetErrorReporter(self.ptr, reportError);
        }
    }

    fn set_error_reporter(@self, reportfn: *u8) {
        unsafe {
            JS_SetErrorReporter(self.ptr, reportfn);
        }
    }

    fn new_compartment(@self,
                       globclsfn: &fn(@mut NamePool) -> JSClass)
                    -> Result<@mut Compartment,()> {
        unsafe {
            let np = NamePool();
            let globcls = @globclsfn(np);
            let globobj = JS_NewGlobalObject(self.ptr, ptr::to_unsafe_ptr(&*globcls), null());
            result(JS_InitStandardClasses(self.ptr, globobj)).chain(|_ok| {
                let compartment = @mut Compartment {
                    cx: self,
                    name_pool: np,
                    global_funcs: ~[],
                    global_props: ~[],
                    global_class: globcls,
                    global_obj: self.rooted_obj(globobj),
                    global_protos: @mut LinearMap::new()
                };
                self.set_cx_private(ptr::to_unsafe_ptr(&*compartment) as *());
                Ok(compartment)
            })
        }
    }

    fn evaluate_script(@self, glob: jsobj, bytes: ~[u8], filename: ~str, line_num: uint)
                    -> Result<(),()> {
        vec::as_imm_buf(bytes, |bytes_ptr, bytes_len| {
            str::as_c_str(filename, |filename_cstr| {
                let bytes_ptr = bytes_ptr as *c_char;
                let rval: JSVal = JSVAL_NULL;
                debug!("Evaluating script from %s with bytes %?", filename, bytes);
                unsafe {
                    if JS_EvaluateScript(self.ptr, glob.ptr,
                                         bytes_ptr, bytes_len as c_uint,
                                         filename_cstr, line_num as c_uint,
                                         ptr::to_unsafe_ptr(&rval)) == ERR {
                        debug!("...err!");
                        Err(())
                    } else {
                        // we could return the script result but then we'd have
                        // to root it and so forth and, really, who cares?
                        debug!("...ok!");
                        Ok(())
                    }
                }
            })
        })
    }

    fn lookup_class_name(@self, s: ~str) ->  @JSClass {
        // FIXME: expect should really take a lambda...
        let error_msg = fmt!("class %s not found in class table", s);
        *(self.classes.find(&s).expect(error_msg))
    }

    unsafe fn get_cx_private(@self) -> *() {
        cast::reinterpret_cast(&JS_GetContextPrivate(self.ptr))
    }

    unsafe fn set_cx_private(@self, data: *()) {
        JS_SetContextPrivate(self.ptr, cast::reinterpret_cast(&data));
    }

    unsafe fn get_obj_private(@self, obj: *JSObject) -> *() {
        cast::reinterpret_cast(&JS_GetPrivate(obj))
    }

    unsafe fn set_obj_private(@self, obj: *JSObject, data: *()) {
        JS_SetPrivate(obj, cast::reinterpret_cast(&data));
    }
}

pub extern fn reportError(_cx: *JSContext, msg: *c_char, report: *JSErrorReport) {
    unsafe {
        let fnptr = (*report).filename;
        let fname = if fnptr.is_not_null() {from_c_str(fnptr)} else {~"none"};
        let lineno = (*report).lineno;
        let msg = from_c_str(msg);
        error!("Error at %s:%?: %s\n", fname, lineno, msg);
    }
}

// ___________________________________________________________________________
// compartment

pub struct Compartment {
    cx: @Cx,
    name_pool: @mut NamePool,
    global_funcs: ~[@~[JSFunctionSpec]],
    global_props: ~[@~[JSPropertySpec]],
    global_class: @JSClass,
    global_obj: jsobj,
    global_protos: @mut LinearMap<~str, jsobj>
}

pub impl Compartment {
    fn define_functions(@mut self,
                        specfn: &fn(@mut NamePool) -> ~[JSFunctionSpec])
                     -> Result<(),()> {
        let specvec = @specfn(self.name_pool);
        vec::push(&mut self.global_funcs, specvec);
        vec::as_imm_buf(*specvec, |specs, _len| {
            unsafe {
                result(JS_DefineFunctions(self.cx.ptr, self.global_obj.ptr, specs))
            }
        })
    }
    fn define_properties(@mut self, specfn: &fn() -> ~[JSPropertySpec]) -> Result<(),()> {
        let specvec = @specfn();
        vec::push(&mut self.global_props, specvec);
        vec::as_imm_buf(*specvec, |specs, _len| {
            unsafe {
                result(JS_DefineProperties(self.cx.ptr, self.global_obj.ptr, specs))
            }
        })
    }
    fn define_property(@mut self,
                       name: ~str,
                       value: JSVal,
                       getter: JSPropertyOp, setter: JSStrictPropertyOp,
                       attrs: c_uint)
                    -> Result<(),()> {
        unsafe {
            result(JS_DefineProperty(self.cx.ptr,
                                     self.global_obj.ptr,
                                     self.add_name(name),
                                     value,
                                     getter,
                                     setter,
                                     attrs))
        }
    }
    fn new_object(@mut self, class_name: ~str, proto: *JSObject, parent: *JSObject)
               -> Result<jsobj, ()> {
        unsafe {
            let classptr = self.cx.lookup_class_name(class_name);
            let obj = self.cx.rooted_obj(JS_NewObject(self.cx.ptr, &*classptr, proto, parent));
            result_obj(obj)
        }
    }
    fn new_object_with_proto(@mut self, class_name: ~str, proto_name: ~str, parent: *JSObject)
                          -> Result<jsobj, ()> {
        let classptr = self.cx.lookup_class_name(class_name);
        let proto = self.global_protos.find(&copy proto_name).expect(
            fmt!("new_object_with_proto: expected to find %s in the proto \
                  table", proto_name));
        unsafe {
            let obj = self.cx.rooted_obj(JS_NewObject(self.cx.ptr, ptr::to_unsafe_ptr(&*classptr),
                                                      proto.ptr, parent));
            result_obj(obj)
        }
    }
    fn get_global_proto(@mut self, name: ~str) -> jsobj {
        *(self.global_protos.get(&name))
    }
    fn stash_global_proto(@mut self, name: ~str, proto: jsobj) {
        let global_protos = self.global_protos;
        if !global_protos.insert(name, proto) {
            fail!(~"Duplicate global prototype registered; you're gonna have a bad time.")
        }
    }
    fn register_class(@mut self, class_fn: &fn(x: @mut Compartment) -> JSClass) {
        let classptr = @class_fn(self);
        if !self.cx.classes.insert(
            unsafe { from_c_str(classptr.name) },
            classptr) {
            fail!(~"Duplicate JSClass registered; you're gonna have a bad time.")
        }
    }
    fn add_name(@mut self, name: ~str) -> *c_char {
        self.name_pool.add(copy name)
    }
}

// ___________________________________________________________________________
// objects

pub type jsobj = @jsobj_rsrc;

pub struct jsobj_rsrc {
    cx: @Cx,
    cxptr: *JSContext,
    ptr: *JSObject,
}

#[unsafe_destructor]
impl Drop for jsobj_rsrc {
    fn finalize(&self) {
        unsafe {
            JS_RemoveObjectRoot(self.cxptr, ptr::to_unsafe_ptr(&self.ptr));
        }
    }
}

impl jsobj_rsrc {
    fn new_object(&self, cx: @Cx, cxptr: *JSContext, ptr: *JSObject) -> jsobj {
        return @jsobj_rsrc {
            cx: cx,
            cxptr: cxptr,
            ptr: ptr
        }
    }
}

// ___________________________________________________________________________
// random utilities

pub trait to_jsstr {
    fn to_jsstr(self, cx: @Cx) -> *JSString;
}

impl to_jsstr for ~str {
    fn to_jsstr(self, cx: @Cx) -> *JSString {
        str::as_buf(self, |buf, len| {
            unsafe {
                let cbuf = cast::reinterpret_cast(&buf);
                bg::JS_NewStringCopyN(cx.ptr, cbuf, len as size_t)
            }
        })
    }
}

#[cfg(test)]
pub mod test {
    use super::rt;
    use super::super::global;

    #[test]
    pub fn dummy() {
        let rt = rt();
        let cx = rt.cx();
        cx.set_default_options_and_version();
        cx.set_logging_error_reporter();
        cx.new_compartment(global::global_class).chain(|comp| {
            comp.define_functions(global::debug_fns);

            let bytes = str::to_bytes(~"debug(22);");
            cx.evaluate_script(comp.global_obj, bytes, ~"test", 1u)
        });
    }

}
<commit_msg>Change LinearMap to HashMap.<commit_after>#[doc = "Rust wrappers around the raw JS apis"];

#[allow(non_implicitly_copyable_typarams)];

use bg = jsapi::bindgen;
use core::libc::types::os::arch::c95::{size_t, c_uint};
use core::libc::c_char;
use core::hashmap::HashMap;
use jsapi::*;
use jsapi::bindgen::*;
use default_stacksize;
use default_heapsize;
use JSOPTION_VAROBJFIX;
use JSOPTION_METHODJIT;
use JSOPTION_TYPE_INFERENCE;
use JSVAL_NULL;
use ERR;
use name_pool::*;
use core::ptr::null;
use result;
use result_obj;
use core::str::raw::from_c_str;

// ___________________________________________________________________________
// friendly Rustic API to runtimes

pub type rt = @rt_rsrc;

pub struct rt_rsrc {
    ptr : *JSRuntime,
}

impl Drop for rt_rsrc {
    fn finalize(&self) {
        unsafe {
            JS_Finish(self.ptr);
        }
    }
}

pub fn new_runtime(p: *JSRuntime) -> rt {
    return @rt_rsrc {
        ptr: p
    }
}

pub impl rt_rsrc {
    fn cx(@self) -> @Cx {
        unsafe {
            new_context(JS_NewContext(self.ptr, default_stacksize as size_t), self)
        }
    }
}

pub fn rt() -> rt {
    unsafe {
        return new_runtime(JS_Init(default_heapsize))
    }
}

// ___________________________________________________________________________
// contexts

pub struct Cx {
    ptr: *JSContext,
    rt: rt,
    classes: @mut HashMap<~str, @JSClass>,
}

#[unsafe_destructor]
impl Drop for Cx {
    fn finalize(&self) {
        unsafe {
            JS_DestroyContext(self.ptr);
        }
    }
}

pub fn new_context(ptr: *JSContext, rt: rt) -> @Cx {
    return @Cx {
        ptr: ptr,
        rt: rt,
        classes: @mut HashMap::new()
    }
}

pub impl Cx {
    fn rooted_obj(@self, obj: *JSObject) -> jsobj {
        let jsobj = @jsobj_rsrc {cx: self, cxptr: self.ptr, ptr: obj};
        unsafe {
            JS_AddObjectRoot(self.ptr, ptr::to_unsafe_ptr(&jsobj.ptr));
        }
        jsobj
    }

    fn set_default_options_and_version(@self) {
        self.set_options(JSOPTION_VAROBJFIX | JSOPTION_METHODJIT |
                         JSOPTION_TYPE_INFERENCE);
        self.set_version(JSVERSION_LATEST);
    }

    fn set_options(@self, v: c_uint) {
        unsafe {
            JS_SetOptions(self.ptr, v);
        }
    }

    fn set_version(@self, v: i32) {
        unsafe {
            JS_SetVersion(self.ptr, v);
        }
    }

    fn set_logging_error_reporter(@self) {
        unsafe {
            JS_SetErrorReporter(self.ptr, reportError);
        }
    }

    fn set_error_reporter(@self, reportfn: *u8) {
        unsafe {
            JS_SetErrorReporter(self.ptr, reportfn);
        }
    }

    fn new_compartment(@self,
                       globclsfn: &fn(@mut NamePool) -> JSClass)
                    -> Result<@mut Compartment,()> {
        unsafe {
            let np = NamePool();
            let globcls = @globclsfn(np);
            let globobj = JS_NewGlobalObject(self.ptr, ptr::to_unsafe_ptr(&*globcls), null());
            result(JS_InitStandardClasses(self.ptr, globobj)).chain(|_ok| {
                let compartment = @mut Compartment {
                    cx: self,
                    name_pool: np,
                    global_funcs: ~[],
                    global_props: ~[],
                    global_class: globcls,
                    global_obj: self.rooted_obj(globobj),
                    global_protos: @mut HashMap::new()
                };
                self.set_cx_private(ptr::to_unsafe_ptr(&*compartment) as *());
                Ok(compartment)
            })
        }
    }

    fn evaluate_script(@self, glob: jsobj, bytes: ~[u8], filename: ~str, line_num: uint)
                    -> Result<(),()> {
        vec::as_imm_buf(bytes, |bytes_ptr, bytes_len| {
            str::as_c_str(filename, |filename_cstr| {
                let bytes_ptr = bytes_ptr as *c_char;
                let rval: JSVal = JSVAL_NULL;
                debug!("Evaluating script from %s with bytes %?", filename, bytes);
                unsafe {
                    if JS_EvaluateScript(self.ptr, glob.ptr,
                                         bytes_ptr, bytes_len as c_uint,
                                         filename_cstr, line_num as c_uint,
                                         ptr::to_unsafe_ptr(&rval)) == ERR {
                        debug!("...err!");
                        Err(())
                    } else {
                        // we could return the script result but then we'd have
                        // to root it and so forth and, really, who cares?
                        debug!("...ok!");
                        Ok(())
                    }
                }
            })
        })
    }

    fn lookup_class_name(@self, s: ~str) ->  @JSClass {
        // FIXME: expect should really take a lambda...
        let error_msg = fmt!("class %s not found in class table", s);
        *(self.classes.find(&s).expect(error_msg))
    }

    unsafe fn get_cx_private(@self) -> *() {
        cast::reinterpret_cast(&JS_GetContextPrivate(self.ptr))
    }

    unsafe fn set_cx_private(@self, data: *()) {
        JS_SetContextPrivate(self.ptr, cast::reinterpret_cast(&data));
    }

    unsafe fn get_obj_private(@self, obj: *JSObject) -> *() {
        cast::reinterpret_cast(&JS_GetPrivate(obj))
    }

    unsafe fn set_obj_private(@self, obj: *JSObject, data: *()) {
        JS_SetPrivate(obj, cast::reinterpret_cast(&data));
    }
}

pub extern fn reportError(_cx: *JSContext, msg: *c_char, report: *JSErrorReport) {
    unsafe {
        let fnptr = (*report).filename;
        let fname = if fnptr.is_not_null() {from_c_str(fnptr)} else {~"none"};
        let lineno = (*report).lineno;
        let msg = from_c_str(msg);
        error!("Error at %s:%?: %s\n", fname, lineno, msg);
    }
}

// ___________________________________________________________________________
// compartment

pub struct Compartment {
    cx: @Cx,
    name_pool: @mut NamePool,
    global_funcs: ~[@~[JSFunctionSpec]],
    global_props: ~[@~[JSPropertySpec]],
    global_class: @JSClass,
    global_obj: jsobj,
    global_protos: @mut HashMap<~str, jsobj>
}

pub impl Compartment {
    fn define_functions(@mut self,
                        specfn: &fn(@mut NamePool) -> ~[JSFunctionSpec])
                     -> Result<(),()> {
        let specvec = @specfn(self.name_pool);
        vec::push(&mut self.global_funcs, specvec);
        vec::as_imm_buf(*specvec, |specs, _len| {
            unsafe {
                result(JS_DefineFunctions(self.cx.ptr, self.global_obj.ptr, specs))
            }
        })
    }
    fn define_properties(@mut self, specfn: &fn() -> ~[JSPropertySpec]) -> Result<(),()> {
        let specvec = @specfn();
        vec::push(&mut self.global_props, specvec);
        vec::as_imm_buf(*specvec, |specs, _len| {
            unsafe {
                result(JS_DefineProperties(self.cx.ptr, self.global_obj.ptr, specs))
            }
        })
    }
    fn define_property(@mut self,
                       name: ~str,
                       value: JSVal,
                       getter: JSPropertyOp, setter: JSStrictPropertyOp,
                       attrs: c_uint)
                    -> Result<(),()> {
        unsafe {
            result(JS_DefineProperty(self.cx.ptr,
                                     self.global_obj.ptr,
                                     self.add_name(name),
                                     value,
                                     getter,
                                     setter,
                                     attrs))
        }
    }
    fn new_object(@mut self, class_name: ~str, proto: *JSObject, parent: *JSObject)
               -> Result<jsobj, ()> {
        unsafe {
            let classptr = self.cx.lookup_class_name(class_name);
            let obj = self.cx.rooted_obj(JS_NewObject(self.cx.ptr, &*classptr, proto, parent));
            result_obj(obj)
        }
    }
    fn new_object_with_proto(@mut self, class_name: ~str, proto_name: ~str, parent: *JSObject)
                          -> Result<jsobj, ()> {
        let classptr = self.cx.lookup_class_name(class_name);
        let proto = self.global_protos.find(&copy proto_name).expect(
            fmt!("new_object_with_proto: expected to find %s in the proto \
                  table", proto_name));
        unsafe {
            let obj = self.cx.rooted_obj(JS_NewObject(self.cx.ptr, ptr::to_unsafe_ptr(&*classptr),
                                                      proto.ptr, parent));
            result_obj(obj)
        }
    }
    fn get_global_proto(@mut self, name: ~str) -> jsobj {
        *(self.global_protos.get(&name))
    }
    fn stash_global_proto(@mut self, name: ~str, proto: jsobj) {
        let global_protos = self.global_protos;
        if !global_protos.insert(name, proto) {
            fail!(~"Duplicate global prototype registered; you're gonna have a bad time.")
        }
    }
    fn register_class(@mut self, class_fn: &fn(x: @mut Compartment) -> JSClass) {
        let classptr = @class_fn(self);
        if !self.cx.classes.insert(
            unsafe { from_c_str(classptr.name) },
            classptr) {
            fail!(~"Duplicate JSClass registered; you're gonna have a bad time.")
        }
    }
    fn add_name(@mut self, name: ~str) -> *c_char {
        self.name_pool.add(copy name)
    }
}

// ___________________________________________________________________________
// objects

pub type jsobj = @jsobj_rsrc;

pub struct jsobj_rsrc {
    cx: @Cx,
    cxptr: *JSContext,
    ptr: *JSObject,
}

#[unsafe_destructor]
impl Drop for jsobj_rsrc {
    fn finalize(&self) {
        unsafe {
            JS_RemoveObjectRoot(self.cxptr, ptr::to_unsafe_ptr(&self.ptr));
        }
    }
}

impl jsobj_rsrc {
    fn new_object(&self, cx: @Cx, cxptr: *JSContext, ptr: *JSObject) -> jsobj {
        return @jsobj_rsrc {
            cx: cx,
            cxptr: cxptr,
            ptr: ptr
        }
    }
}

// ___________________________________________________________________________
// random utilities

pub trait to_jsstr {
    fn to_jsstr(self, cx: @Cx) -> *JSString;
}

impl to_jsstr for ~str {
    fn to_jsstr(self, cx: @Cx) -> *JSString {
        str::as_buf(self, |buf, len| {
            unsafe {
                let cbuf = cast::reinterpret_cast(&buf);
                bg::JS_NewStringCopyN(cx.ptr, cbuf, len as size_t)
            }
        })
    }
}

#[cfg(test)]
pub mod test {
    use super::rt;
    use super::super::global;

    #[test]
    pub fn dummy() {
        let rt = rt();
        let cx = rt.cx();
        cx.set_default_options_and_version();
        cx.set_logging_error_reporter();
        cx.new_compartment(global::global_class).chain(|comp| {
            comp.define_functions(global::debug_fns);

            let bytes = str::to_bytes(~"debug(22);");
            cx.evaluate_script(comp.global_obj, bytes, ~"test", 1u)
        });
    }

}
<|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 http://mozilla.org/MPL/2.0/. */

//! Traits that nodes must implement. Breaks the otherwise-cyclic dependency
//! between layout and style.

use attr::{AttrSelectorOperation, NamespaceConstraint, CaseSensitivity};
use context::VisitedHandlingMode;
use matching::{ElementSelectorFlags, MatchingContext};
use parser::SelectorImpl;
use servo_arc::NonZeroPtrMut;
use std::fmt::Debug;

/// Opaque representation of an Element, for identity comparisons. We use
/// NonZeroPtrMut to get the NonZero optimization.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct OpaqueElement(pub NonZeroPtrMut<()>);

impl OpaqueElement {
    /// Creates a new OpaqueElement from an arbitrarily-typed pointer.
    pub fn new<T>(ptr: *const T) -> Self {
        OpaqueElement(NonZeroPtrMut::new(ptr as *const () as *mut ()))
    }
}

pub trait Element: Sized + Clone + Debug {
    type Impl: SelectorImpl;

    /// Converts self into an opaque representation.
    fn opaque(&self) -> OpaqueElement;

    fn parent_element(&self) -> Option<Self>;

    /// The parent of a given pseudo-element, after matching a pseudo-element
    /// selector.
    ///
    /// This is guaranteed to be called in a pseudo-element.
    fn pseudo_element_originating_element(&self) -> Option<Self> {
        self.parent_element()
    }

    /// Skips non-element nodes
    fn first_child_element(&self) -> Option<Self>;

    /// Skips non-element nodes
    fn last_child_element(&self) -> Option<Self>;

    /// Skips non-element nodes
    fn prev_sibling_element(&self) -> Option<Self>;

    /// Skips non-element nodes
    fn next_sibling_element(&self) -> Option<Self>;

    fn is_html_element_in_html_document(&self) -> bool;

    fn get_local_name(&self) -> &<Self::Impl as SelectorImpl>::BorrowedLocalName;

    /// Empty string for no namespace
    fn get_namespace(&self) -> &<Self::Impl as SelectorImpl>::BorrowedNamespaceUrl;

    fn attr_matches(&self,
                    ns: &NamespaceConstraint<&<Self::Impl as SelectorImpl>::NamespaceUrl>,
                    local_name: &<Self::Impl as SelectorImpl>::LocalName,
                    operation: &AttrSelectorOperation<&<Self::Impl as SelectorImpl>::AttrValue>)
                    -> bool;

    fn match_non_ts_pseudo_class<F>(
        &self,
        pc: &<Self::Impl as SelectorImpl>::NonTSPseudoClass,
        context: &mut MatchingContext<Self::Impl>,
        visited_handling: VisitedHandlingMode,
        flags_setter: &mut F,
    ) -> bool
    where
        F: FnMut(&Self, ElementSelectorFlags);

    fn match_pseudo_element(
        &self,
        pe: &<Self::Impl as SelectorImpl>::PseudoElement,
        context: &mut MatchingContext<Self::Impl>,
    ) -> bool;

    /// Whether this element is a `link`.
    fn is_link(&self) -> bool;

    /// Returns the assigned <slot> element this element is assigned to.
    ///
    /// Necessary for the `::slotted` pseudo-class.
    fn assigned_slot(&self) -> Option<Self> {
        None
    }

    fn has_id(&self,
              id: &<Self::Impl as SelectorImpl>::Identifier,
              case_sensitivity: CaseSensitivity)
              -> bool;

    fn has_class(&self,
                 name: &<Self::Impl as SelectorImpl>::ClassName,
                 case_sensitivity: CaseSensitivity)
                 -> bool;

    /// Returns whether this element matches `:empty`.
    ///
    /// That is, whether it does not contain any child element or any non-zero-length text node.
    /// See http://dev.w3.org/csswg/selectors-3/#empty-pseudo
    fn is_empty(&self) -> bool;

    /// Returns whether this element matches `:root`,
    /// i.e. whether it is the root element of a document.
    ///
    /// Note: this can be false even if `.parent_element()` is `None`
    /// if the parent node is a `DocumentFragment`.
    fn is_root(&self) -> bool;

    /// Returns whether this element should ignore matching nth child
    /// selector.
    fn ignores_nth_child_selectors(&self) -> bool {
        false
    }

    /// Return true if we want to stop lookup ancestor of the current
    /// element while matching complex selectors with descendant/child
    /// combinator.
    fn blocks_ancestor_combinators(&self) -> bool {
        false
    }
}
<commit_msg>Make OpaqueElement’s field private.<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 http://mozilla.org/MPL/2.0/. */

//! Traits that nodes must implement. Breaks the otherwise-cyclic dependency
//! between layout and style.

use attr::{AttrSelectorOperation, NamespaceConstraint, CaseSensitivity};
use context::VisitedHandlingMode;
use matching::{ElementSelectorFlags, MatchingContext};
use parser::SelectorImpl;
use servo_arc::NonZeroPtrMut;
use std::fmt::Debug;

/// Opaque representation of an Element, for identity comparisons. We use
/// NonZeroPtrMut to get the NonZero optimization.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct OpaqueElement(NonZeroPtrMut<()>);

impl OpaqueElement {
    /// Creates a new OpaqueElement from an arbitrarily-typed pointer.
    pub fn new<T>(ptr: *const T) -> Self {
        OpaqueElement(NonZeroPtrMut::new(ptr as *const () as *mut ()))
    }
}

pub trait Element: Sized + Clone + Debug {
    type Impl: SelectorImpl;

    /// Converts self into an opaque representation.
    fn opaque(&self) -> OpaqueElement;

    fn parent_element(&self) -> Option<Self>;

    /// The parent of a given pseudo-element, after matching a pseudo-element
    /// selector.
    ///
    /// This is guaranteed to be called in a pseudo-element.
    fn pseudo_element_originating_element(&self) -> Option<Self> {
        self.parent_element()
    }

    /// Skips non-element nodes
    fn first_child_element(&self) -> Option<Self>;

    /// Skips non-element nodes
    fn last_child_element(&self) -> Option<Self>;

    /// Skips non-element nodes
    fn prev_sibling_element(&self) -> Option<Self>;

    /// Skips non-element nodes
    fn next_sibling_element(&self) -> Option<Self>;

    fn is_html_element_in_html_document(&self) -> bool;

    fn get_local_name(&self) -> &<Self::Impl as SelectorImpl>::BorrowedLocalName;

    /// Empty string for no namespace
    fn get_namespace(&self) -> &<Self::Impl as SelectorImpl>::BorrowedNamespaceUrl;

    fn attr_matches(&self,
                    ns: &NamespaceConstraint<&<Self::Impl as SelectorImpl>::NamespaceUrl>,
                    local_name: &<Self::Impl as SelectorImpl>::LocalName,
                    operation: &AttrSelectorOperation<&<Self::Impl as SelectorImpl>::AttrValue>)
                    -> bool;

    fn match_non_ts_pseudo_class<F>(
        &self,
        pc: &<Self::Impl as SelectorImpl>::NonTSPseudoClass,
        context: &mut MatchingContext<Self::Impl>,
        visited_handling: VisitedHandlingMode,
        flags_setter: &mut F,
    ) -> bool
    where
        F: FnMut(&Self, ElementSelectorFlags);

    fn match_pseudo_element(
        &self,
        pe: &<Self::Impl as SelectorImpl>::PseudoElement,
        context: &mut MatchingContext<Self::Impl>,
    ) -> bool;

    /// Whether this element is a `link`.
    fn is_link(&self) -> bool;

    /// Returns the assigned <slot> element this element is assigned to.
    ///
    /// Necessary for the `::slotted` pseudo-class.
    fn assigned_slot(&self) -> Option<Self> {
        None
    }

    fn has_id(&self,
              id: &<Self::Impl as SelectorImpl>::Identifier,
              case_sensitivity: CaseSensitivity)
              -> bool;

    fn has_class(&self,
                 name: &<Self::Impl as SelectorImpl>::ClassName,
                 case_sensitivity: CaseSensitivity)
                 -> bool;

    /// Returns whether this element matches `:empty`.
    ///
    /// That is, whether it does not contain any child element or any non-zero-length text node.
    /// See http://dev.w3.org/csswg/selectors-3/#empty-pseudo
    fn is_empty(&self) -> bool;

    /// Returns whether this element matches `:root`,
    /// i.e. whether it is the root element of a document.
    ///
    /// Note: this can be false even if `.parent_element()` is `None`
    /// if the parent node is a `DocumentFragment`.
    fn is_root(&self) -> bool;

    /// Returns whether this element should ignore matching nth child
    /// selector.
    fn ignores_nth_child_selectors(&self) -> bool {
        false
    }

    /// Return true if we want to stop lookup ancestor of the current
    /// element while matching complex selectors with descendant/child
    /// combinator.
    fn blocks_ancestor_combinators(&self) -> bool {
        false
    }
}
<|endoftext|>


<commit_before>extern crate gtk;
extern crate glib;
extern crate gstreamer as gst;

#[cfg(any(feature = "profiling-listener", feature = "profiling-tracker"))]
use chrono::Utc;

use std::rc::Rc;
use std::cell::RefCell;

use std::path::PathBuf;

use std::sync::mpsc::{channel, Receiver};

use gtk::prelude::*;

use media::{Context, ContextMessage};
use media::ContextMessage::*;

use super::{AudioController, InfoController, VideoController};

#[derive(Clone, PartialEq)]
pub enum ControllerState {
    Stopped,
    Paused,
    Playing,
}

const LISTENER_PERIOD: u32 = 250; // 250 ms (4 Hz)
const TRACKER_PERIOD:  u32 = 17;  //  17 ms (60 Hz)

pub struct MainController {
    window: gtk::ApplicationWindow,
    header_bar: gtk::HeaderBar,
    play_pause_btn: gtk::ToolButton,

    video_ctrl: VideoController,
    info_ctrl: InfoController,
    audio_ctrl: AudioController,

    context: Option<Context>,
    state: ControllerState,
    duration: u64,
    seeking: bool,

    this_opt: Option<Rc<RefCell<MainController>>>,
    keep_going: bool,
    listener_src: Option<glib::SourceId>,
    tracker_src: Option<glib::SourceId>,
}

impl MainController {
    pub fn new(builder: gtk::Builder) -> Rc<RefCell<Self>> {
        let this = Rc::new(RefCell::new(MainController {
            window: builder.get_object("application-window").unwrap(),
            header_bar: builder.get_object("header-bar").unwrap(),
            play_pause_btn: builder.get_object("play_pause-toolbutton").unwrap(),

            video_ctrl: VideoController::new(&builder),
            info_ctrl: InfoController::new(&builder),
            audio_ctrl: AudioController::new(&builder),

            context: None,
            state: ControllerState::Stopped,
            duration: 0,
            seeking: false,

            this_opt: None,
            keep_going: true,
            listener_src: None,
            tracker_src: None,
        }));

        {
            let mut this_mut = this.borrow_mut();

            let this_rc = Rc::clone(&this);
            this_mut.this_opt = Some(this_rc);

            this_mut.window.connect_delete_event(|_, _| {
                gtk::main_quit();
                Inhibit(false)
            });
            this_mut.window.set_titlebar(&this_mut.header_bar);

            let this_rc = Rc::clone(&this);
            this_mut.play_pause_btn.connect_clicked(move |_| {
                this_rc.borrow_mut().play_pause();
            });

            // TODO: add key bindings to seek by steps
            // play/pause, etc.

            this_mut.video_ctrl.register_callbacks(&this);
            this_mut.info_ctrl.register_callbacks(&this);
            this_mut.audio_ctrl.register_callbacks(&this);
        }

        let open_btn: gtk::Button = builder.get_object("open-btn").unwrap();
        let this_rc = Rc::clone(&this);
        open_btn.connect_clicked(move |_| {
            this_rc.borrow_mut().select_media();
        });

        this
    }

    pub fn show_all(&self) {
        self.window.show_all();
    }

    pub fn get_state(&self) -> ControllerState {
        self.state.clone()
    }

    fn play_pause(&mut self) {
        let mut context =
            match self.context.take() {
                Some(context) => context,
                None => {
                    self.select_media();
                    return;
                },
            };

        match context.get_state() {
            gst::State::Paused => {
                if context.get_position() < self.duration {
                    self.register_tracker(TRACKER_PERIOD);
                    self.play_pause_btn.set_icon_name("media-playback-pause");
                    self.state = ControllerState::Playing;
                    context.play().unwrap();
                    self.context = Some(context);
                } else {
                    self.context = Some(context);
                    self.seek(0);
                }
            }
            gst::State::Playing => {
                context.pause().unwrap();
                self.play_pause_btn.set_icon_name("media-playback-start");
                self.remove_tracker();
                self.state = ControllerState::Paused;
                self.context = Some(context);
            },
            state => {
                println!("Can't play/pause in state {:?}", state);
                self.context = Some(context);
            },
        };
    }

    fn stop(&mut self) {
        if let Some(context) = self.context.as_mut() {
            context.stop();
        };

        // remove callbacks in order to avoid conflict on borrowing of self
        self.remove_listener();
        self.remove_tracker();

        self.audio_ctrl.cleanup();

        self.play_pause_btn.set_icon_name("media-playback-start");

        self.state = ControllerState::Stopped;
        self.duration = 0;
    }

    pub fn seek(&mut self, position: u64) {
        if self.state != ControllerState::Stopped {
            self.seeking = true;
            // update position eventhough the stream
            // is not sync yet for the user to notice
            // the seek request in being handled
            self.info_ctrl.seek(position);
            self.audio_ctrl.seek(position);
            self.context.as_ref()
                .expect("MainController::seek no context")
                .seek(position);

            if self.state == ControllerState::Paused {
                self.register_tracker(TRACKER_PERIOD);
                self.play_pause_btn.set_icon_name("media-playback-pause");
                self.context.as_mut().unwrap().play().unwrap();
            }
        }
    }

    fn select_media(&mut self) {
        self.stop();

        let file_dlg = gtk::FileChooserDialog::new(
            Some("Open a media file"),
            Some(&self.window),
            gtk::FileChooserAction::Open,
        );
        // Note: couldn't find equivalents for STOCK_OK
        file_dlg.add_button("Open", gtk::ResponseType::Ok.into());

        if file_dlg.run() == gtk::ResponseType::Ok.into() {
            self.open_media(file_dlg.get_filename().unwrap());
        }

        file_dlg.close();
    }

    fn remove_listener(&mut self) {
        if let Some(source_id) = self.listener_src.take() {
            glib::source_remove(source_id);
        }
    }

    fn register_listener(&mut self,
        timeout: u32,
        ui_rx: Receiver<ContextMessage>,
    ) {
        if self.listener_src.is_some() {
            return;
        }

        let this_rc = Rc::clone(self.this_opt.as_ref().unwrap());

        self.listener_src = Some(gtk::timeout_add(timeout, move || {
            let mut keep_going = true;

            for message in ui_rx.try_iter() {
                match message {
                    AsyncDone => {
                        this_rc.borrow_mut().seeking = false;
                    },
                    InitDone => {
                        let mut this_mut = this_rc.borrow_mut();

                        let context = this_mut.context.take()
                            .expect("MainController: InitDone but no context available");

                        this_mut.header_bar.set_subtitle(
                            Some(context.file_name.as_str())
                        );

                        this_mut.duration = context.get_duration();

                        this_mut.info_ctrl.new_media(&context);
                        this_mut.video_ctrl.new_media(&context);
                        this_mut.audio_ctrl.new_media(&context);

                        this_mut.context = Some(context);
                    },
                    Eos => {
                        let mut this = this_rc.borrow_mut();

                        this.audio_ctrl.tick();
                        this.play_pause_btn.set_icon_name("media-playback-start");
                        this.state = ControllerState::Paused;
                        this.remove_tracker();
                    },
                    FailedToOpenMedia => {
                        eprintln!("ERROR: failed to open media");

                        let mut this_mut = this_rc.borrow_mut();

                        this_mut.context = None;
                        this_mut.keep_going = false;
                        keep_going = false;
                    },
                };

                if !keep_going { break; }
            }

            if !keep_going {
                let mut this_mut = this_rc.borrow_mut();
                this_mut.listener_src = None;
                this_mut.tracker_src = None;
            }

            glib::Continue(keep_going)
        }));
    }

    fn remove_tracker(&mut self) {
        if let Some(source_id) = self.tracker_src.take() {
            glib::source_remove(source_id);
        }
    }

    fn register_tracker(&mut self, timeout: u32) {
        if self.tracker_src.is_some() {
            return;
        }

        let this_rc = Rc::clone(self.this_opt.as_ref().unwrap());

        self.tracker_src = Some(gtk::timeout_add(timeout, move || {
            #[cfg(feature = "profiling-tracker")]
            let start = Utc::now();

            let mut keep_going = true;

            let mut this_mut = this_rc.borrow_mut();

            #[cfg(feature = "profiling-tracker")]
            let before_tick = Utc::now();

            let position = this_mut.context.as_mut()
                .expect("MainController::tracker no context while getting position")
                .get_position();
            this_mut.info_ctrl.tick(position);
            this_mut.audio_ctrl.tick();

            if position > this_mut.duration {
                // this check is necessary as EOS is not sent
                // after the first EOS even afte a seek
                if let Some(context) = this_mut.context.as_mut() {
                    context.pause().unwrap();
                }
                this_mut.play_pause_btn.set_icon_name("media-playback-start");
                this_mut.state = ControllerState::Paused;
                this_mut.tracker_src = None;
                keep_going = false;
            }

            #[cfg(feature = "profiling-tracker")]
            let end = Utc::now();

            #[cfg(feature = "profiling-tracker")]
            println!("tracker,{},{},{}",
                start.time().format("%H:%M:%S%.6f"),
                before_tick.time().format("%H:%M:%S%.6f"),
                end.time().format("%H:%M:%S%.6f"),
            );

            glib::Continue(this_mut.keep_going && keep_going)
        }));
    }

    fn open_media(&mut self, filepath: PathBuf) {
        assert_eq!(self.listener_src, None);

        self.info_ctrl.cleanup();
        self.audio_ctrl.cleanup();
        self.header_bar.set_subtitle("");

        let (ctx_tx, ui_rx) = channel();

        self.seeking = false;
        self.keep_going = true;
        self.register_listener(LISTENER_PERIOD, ui_rx);

        match Context::new(
            filepath,
            self.audio_ctrl.get_dbl_buffer_mtx(),
            self.video_ctrl.video_box.clone(),
            ctx_tx
        ) {
            Ok(context) => {
                self.context = Some(context);
            },
            Err(error) => eprintln!("Error opening media: {}", error),
        };
    }
}
<commit_msg>Don't switch to play while seeking in Paused state (#37)<commit_after>extern crate gtk;
extern crate glib;
extern crate gstreamer as gst;

#[cfg(any(feature = "profiling-listener", feature = "profiling-tracker"))]
use chrono::Utc;

use std::rc::Rc;
use std::cell::RefCell;

use std::path::PathBuf;

use std::sync::mpsc::{channel, Receiver};

use gtk::prelude::*;

use media::{Context, ContextMessage};
use media::ContextMessage::*;

use super::{AudioController, InfoController, VideoController};

#[derive(Clone, PartialEq)]
pub enum ControllerState {
    Stopped,
    Paused,
    Playing,
}

const LISTENER_PERIOD: u32 = 250; // 250 ms (4 Hz)
const TRACKER_PERIOD:  u32 = 17;  //  17 ms (60 Hz)

pub struct MainController {
    window: gtk::ApplicationWindow,
    header_bar: gtk::HeaderBar,
    play_pause_btn: gtk::ToolButton,

    video_ctrl: VideoController,
    info_ctrl: InfoController,
    audio_ctrl: AudioController,

    context: Option<Context>,
    state: ControllerState,
    duration: u64,
    seeking: bool,

    this_opt: Option<Rc<RefCell<MainController>>>,
    keep_going: bool,
    listener_src: Option<glib::SourceId>,
    tracker_src: Option<glib::SourceId>,
}

impl MainController {
    pub fn new(builder: gtk::Builder) -> Rc<RefCell<Self>> {
        let this = Rc::new(RefCell::new(MainController {
            window: builder.get_object("application-window").unwrap(),
            header_bar: builder.get_object("header-bar").unwrap(),
            play_pause_btn: builder.get_object("play_pause-toolbutton").unwrap(),

            video_ctrl: VideoController::new(&builder),
            info_ctrl: InfoController::new(&builder),
            audio_ctrl: AudioController::new(&builder),

            context: None,
            state: ControllerState::Stopped,
            duration: 0,
            seeking: false,

            this_opt: None,
            keep_going: true,
            listener_src: None,
            tracker_src: None,
        }));

        {
            let mut this_mut = this.borrow_mut();

            let this_rc = Rc::clone(&this);
            this_mut.this_opt = Some(this_rc);

            this_mut.window.connect_delete_event(|_, _| {
                gtk::main_quit();
                Inhibit(false)
            });
            this_mut.window.set_titlebar(&this_mut.header_bar);

            let this_rc = Rc::clone(&this);
            this_mut.play_pause_btn.connect_clicked(move |_| {
                this_rc.borrow_mut().play_pause();
            });

            // TODO: add key bindings to seek by steps
            // play/pause, etc.

            this_mut.video_ctrl.register_callbacks(&this);
            this_mut.info_ctrl.register_callbacks(&this);
            this_mut.audio_ctrl.register_callbacks(&this);
        }

        let open_btn: gtk::Button = builder.get_object("open-btn").unwrap();
        let this_rc = Rc::clone(&this);
        open_btn.connect_clicked(move |_| {
            this_rc.borrow_mut().select_media();
        });

        this
    }

    pub fn show_all(&self) {
        self.window.show_all();
    }

    pub fn get_state(&self) -> ControllerState {
        self.state.clone()
    }

    fn play_pause(&mut self) {
        let mut context =
            match self.context.take() {
                Some(context) => context,
                None => {
                    self.select_media();
                    return;
                },
            };

        match context.get_state() {
            gst::State::Paused => {
                if context.get_position() < self.duration {
                    self.register_tracker(TRACKER_PERIOD);
                    self.play_pause_btn.set_icon_name("media-playback-pause");
                    self.state = ControllerState::Playing;
                    context.play().unwrap();
                    self.context = Some(context);
                } else {
                    self.context = Some(context);
                    self.seek(0);
                }
            }
            gst::State::Playing => {
                context.pause().unwrap();
                self.play_pause_btn.set_icon_name("media-playback-start");
                self.remove_tracker();
                self.state = ControllerState::Paused;
                self.context = Some(context);
            },
            state => {
                println!("Can't play/pause in state {:?}", state);
                self.context = Some(context);
            },
        };
    }

    fn stop(&mut self) {
        if let Some(context) = self.context.as_mut() {
            context.stop();
        };

        // remove callbacks in order to avoid conflict on borrowing of self
        self.remove_listener();
        self.remove_tracker();

        self.audio_ctrl.cleanup();

        self.play_pause_btn.set_icon_name("media-playback-start");

        self.state = ControllerState::Stopped;
        self.duration = 0;
    }

    pub fn seek(&mut self, position: u64) {
        if self.state != ControllerState::Stopped {
            self.seeking = true;
            // update position eventhough the stream
            // is not sync yet for the user to notice
            // the seek request in being handled
            self.info_ctrl.seek(position);
            self.audio_ctrl.seek(position);
            self.context.as_ref()
                .expect("MainController::seek no context")
                .seek(position);
        }
    }

    fn select_media(&mut self) {
        self.stop();

        let file_dlg = gtk::FileChooserDialog::new(
            Some("Open a media file"),
            Some(&self.window),
            gtk::FileChooserAction::Open,
        );
        // Note: couldn't find equivalents for STOCK_OK
        file_dlg.add_button("Open", gtk::ResponseType::Ok.into());

        if file_dlg.run() == gtk::ResponseType::Ok.into() {
            self.open_media(file_dlg.get_filename().unwrap());
        }

        file_dlg.close();
    }

    fn remove_listener(&mut self) {
        if let Some(source_id) = self.listener_src.take() {
            glib::source_remove(source_id);
        }
    }

    fn register_listener(&mut self,
        timeout: u32,
        ui_rx: Receiver<ContextMessage>,
    ) {
        if self.listener_src.is_some() {
            return;
        }

        let this_rc = Rc::clone(self.this_opt.as_ref().unwrap());

        self.listener_src = Some(gtk::timeout_add(timeout, move || {
            let mut keep_going = true;

            for message in ui_rx.try_iter() {
                match message {
                    AsyncDone => {
                        this_rc.borrow_mut().seeking = false;
                    },
                    InitDone => {
                        let mut this_mut = this_rc.borrow_mut();

                        let context = this_mut.context.take()
                            .expect("MainController: InitDone but no context available");

                        this_mut.header_bar.set_subtitle(
                            Some(context.file_name.as_str())
                        );

                        this_mut.duration = context.get_duration();

                        this_mut.info_ctrl.new_media(&context);
                        this_mut.video_ctrl.new_media(&context);
                        this_mut.audio_ctrl.new_media(&context);

                        this_mut.context = Some(context);
                    },
                    Eos => {
                        let mut this = this_rc.borrow_mut();

                        this.audio_ctrl.tick();
                        this.play_pause_btn.set_icon_name("media-playback-start");
                        this.state = ControllerState::Paused;
                        this.remove_tracker();
                    },
                    FailedToOpenMedia => {
                        eprintln!("ERROR: failed to open media");

                        let mut this_mut = this_rc.borrow_mut();

                        this_mut.context = None;
                        this_mut.keep_going = false;
                        keep_going = false;
                    },
                };

                if !keep_going { break; }
            }

            if !keep_going {
                let mut this_mut = this_rc.borrow_mut();
                this_mut.listener_src = None;
                this_mut.tracker_src = None;
            }

            glib::Continue(keep_going)
        }));
    }

    fn remove_tracker(&mut self) {
        if let Some(source_id) = self.tracker_src.take() {
            glib::source_remove(source_id);
        }
    }

    fn register_tracker(&mut self, timeout: u32) {
        if self.tracker_src.is_some() {
            return;
        }

        let this_rc = Rc::clone(self.this_opt.as_ref().unwrap());

        self.tracker_src = Some(gtk::timeout_add(timeout, move || {
            #[cfg(feature = "profiling-tracker")]
            let start = Utc::now();

            let mut keep_going = true;

            let mut this_mut = this_rc.borrow_mut();

            #[cfg(feature = "profiling-tracker")]
            let before_tick = Utc::now();

            let position = this_mut.context.as_mut()
                .expect("MainController::tracker no context while getting position")
                .get_position();
            this_mut.info_ctrl.tick(position);
            this_mut.audio_ctrl.tick();

            if position > this_mut.duration {
                // this check is necessary as EOS is not sent
                // after the first EOS even afte a seek
                if let Some(context) = this_mut.context.as_mut() {
                    context.pause().unwrap();
                }
                this_mut.play_pause_btn.set_icon_name("media-playback-start");
                this_mut.state = ControllerState::Paused;
                this_mut.tracker_src = None;
                keep_going = false;
            }

            #[cfg(feature = "profiling-tracker")]
            let end = Utc::now();

            #[cfg(feature = "profiling-tracker")]
            println!("tracker,{},{},{}",
                start.time().format("%H:%M:%S%.6f"),
                before_tick.time().format("%H:%M:%S%.6f"),
                end.time().format("%H:%M:%S%.6f"),
            );

            glib::Continue(this_mut.keep_going && keep_going)
        }));
    }

    fn open_media(&mut self, filepath: PathBuf) {
        assert_eq!(self.listener_src, None);

        self.info_ctrl.cleanup();
        self.audio_ctrl.cleanup();
        self.header_bar.set_subtitle("");

        let (ctx_tx, ui_rx) = channel();

        self.seeking = false;
        self.keep_going = true;
        self.register_listener(LISTENER_PERIOD, ui_rx);

        match Context::new(
            filepath,
            self.audio_ctrl.get_dbl_buffer_mtx(),
            self.video_ctrl.video_box.clone(),
            ctx_tx
        ) {
            Ok(context) => {
                self.context = Some(context);
            },
            Err(error) => eprintln!("Error opening media: {}", error),
        };
    }
}
<|endoftext|>