<commit_before>use cocoa::base::{id, nil};
use cocoa::foundation::{NSString, NSUInteger};
use error::NSError;
use objc::runtime::YES;
use objc_bringup::NSArray;
use sys::{MTLCopyAllDevices, MTLCreateSystemDefaultDevice, MTLDevice};
use std::borrow::Cow;
use std::convert::{AsRef, From};
use std::error::Error;
use std::ffi::CStr;
use std::fmt::{self, Display, Formatter};
use std::path::Path;
use sys::MTLFeatureSet;
use {CommandQueue, CommandQueueError, CompileOptions, FromRaw, FromRawError, Library,
     LibraryError, LibraryErrorType, Size};

pub struct Device(id);

impl Device {
    pub fn system_default_device() -> Result<Self, DeviceError> {
        let device = unsafe { MTLCreateSystemDefaultDevice() };
        if device != nil { Ok(Device(device)) } else { Err(DeviceError::ConstructionFailed) }
    }

    pub fn enumerate_all_system_devices() -> Vec<Result<Self, DeviceError>> {
        let all_devices = unsafe { MTLCopyAllDevices() };
        let mut devices_vec = vec![];

        unsafe {
            for i in 0..all_devices.count() {
                let device = all_devices.objectAtIndex(i);
                if device != nil {
                    devices_vec.push(Ok(Device(device)));
                } else {
                    devices_vec.push(Err(DeviceError::ConstructionFailed));
                }
            }
        }

        devices_vec
    }

    pub fn is_depth24_stencil8_pixel_format_supported(&self) -> bool {
        unsafe { self.0.depth24Stencil8PixelFormatSupported() == YES }
    }

    pub fn is_headless(&self) -> bool {
        unsafe { self.0.headless() == YES }
    }

    pub fn is_low_power(&self) -> bool {
        unsafe { self.0.lowPower() == YES }
    }

    pub fn max_threads_per_group(&self) -> Size {
        unsafe { self.0.maxThreadsPerGroup().into() }
    }

    pub fn name(&self) -> Cow<str> {
        unsafe { CStr::from_ptr(self.0.name().UTF8String()).to_string_lossy() }
    }

    pub fn supports_feature_set(&self, feature_set: FeatureSet) -> bool {
        unsafe { self.0.supportsFeatureSet(feature_set.into()) == YES }
    }

    pub fn supports_texture_sample_count(&self, sample_count: usize) -> bool {
        unsafe { self.0.supportsTextureSampleCount(sample_count as NSUInteger) == YES }
    }

    pub fn new_command_queue(&mut self) -> Result<CommandQueue, CommandQueueError> {
        let command_queue = unsafe { self.0.newCommandQueue() };
        Ok(try!(FromRaw::from_raw(command_queue)))
    }

    pub fn new_command_queue_with_max_buffer_count(&mut self, max_command_buffer_count: usize)
                                                   -> Result<CommandQueue, CommandQueueError> {
        let command_queue = unsafe {
            self.0.newCommandQueueWithMaxCommandBufferCount(max_command_buffer_count as NSUInteger)
        };
        Ok(try!(FromRaw::from_raw(command_queue)))
    }

    // TODO(George): This will panic in the metal lib if not called from a binary in a bundle. Need
    // to add proper error checking
    pub fn new_default_library(&mut self) -> Result<Library, LibraryError> {
        unsafe {
            let library = self.0.newDefaultLibrary();
            Ok(try!(FromRaw::from_raw(library)))
        }
    }

    #[allow(unused_variables)]
    #[cfg_attr(rustfmt, rustfmt_skip)]
    pub fn new_library_with_file(&mut self, file_path: &AsRef<Path>)
                                 -> Result<Library, LibraryError> {
        unimplemented!();
    }

    pub fn new_library_with_source(&mut self, source: &AsRef<str>, compile_options: &CompileOptions)
                                   -> Result<Library, LibraryError> {
        unsafe {
            let source = NSString::alloc(nil).init_str(source.as_ref());
            let options = compile_options.mtl_compile_options();
            let mut error = nil;
            let library = self.0.newLibraryWithSource_options_error(source, options, &mut error);
            if library == nil {
                Err(LibraryError {
                    ns_error: NSError::new(error),
                    error_type: LibraryErrorType::SourceError
                })
            } else {
                Ok(try!(FromRaw::from_raw(library)))
            }
        }
    }

    #[allow(unused_variables)]
    // TODO(George): `data` parameter should be of the correct type
    pub fn new_library_with_data(&mut self, data: ()) -> Result<Library, LibraryError> {
        unimplemented!();
    }
}

impl_from_into_raw!(Device, of protocol "MTLDevice");

#[cfg(target_os = "ios")]
convertible_enum! {
    #[allow(non_camel_case_types)]
    #[derive(Clone, Copy, Eq, Hash, PartialEq)]
    pub enum FeatureSet: MTLFeatureSet {
        iOSGpuFamily1_v1 => MTLFeatureSet_iOS_GPUFamily1_v1,
        iOSGpuFamily2_v1 => MTLFeatureSet_iOS_GPUFamily2_v1,
        iOSGpuFamily1_v2 => MTLFeatureSet_iOS_GPUFamily1_v2,
        iOSGpuFamily2_v2 => MTLFeatureSet_iOS_GPUFamily2_v2,
        iOSGpuFamily3_v1 => MTLFeatureSet_iOS_GPUFamily3_v1
    }
}

#[cfg(target_os = "macos")]
convertible_enum! {
    #[allow(non_camel_case_types)]
    #[derive(Clone, Copy, Eq, Hash, PartialEq)]
    enum FeatureSet: MTLFeatureSet {
        OsxGpuFamily1_v1 => MTLFeatureSet_OSX_GPUFamily1_v1,
        _non_unary_compile_dummy => _non_unary_compile_dummy
    }
}

#[derive(Clone, Debug)]
pub enum DeviceError {
    ConstructionFailed,
    RawError(FromRawError)
}

impl From<FromRawError> for DeviceError {
    fn from(error: FromRawError) -> Self {
        DeviceError::RawError(error)
    }
}

impl Display for DeviceError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let descr = match *self {
            DeviceError::ConstructionFailed => "DeviceError::ConstructionFailed",
            DeviceError::RawError(_) => "DeviceError::ConstructionFailed",
        };
        write!(f, "{}", descr)
    }
}

impl Error for DeviceError {
    fn description(&self) -> &str {
        match *self {
            DeviceError::ConstructionFailed => {
                "Could not create a default device. Please ensure that you are using at least OSX \
                 10.11 or iOS 8.0"
            }
            DeviceError::RawError(_) => "There was an error with the device pointer",
        }
    }

    fn cause(&self) -> Option<&Error> {
        match self {
            &DeviceError::ConstructionFailed => None,
            &DeviceError::RawError(ref raw_err) => Some(raw_err),
        }
    }
}
<commit_msg>rustfmt<commit_after>use cocoa::base::{id, nil};
use cocoa::foundation::{NSString, NSUInteger};
use error::NSError;
use objc::runtime::YES;
use objc_bringup::NSArray;
use sys::{MTLCopyAllDevices, MTLCreateSystemDefaultDevice, MTLDevice};
use std::borrow::Cow;
use std::convert::{AsRef, From};
use std::error::Error;
use std::ffi::CStr;
use std::fmt::{self, Display, Formatter};
use std::path::Path;
use sys::MTLFeatureSet;
use {CommandQueue, CommandQueueError, CompileOptions, FromRaw, FromRawError, Library,
     LibraryError, LibraryErrorType, Size};

pub struct Device(id);

impl Device {
    pub fn system_default_device() -> Result<Self, DeviceError> {
        let device = unsafe { MTLCreateSystemDefaultDevice() };
        if device != nil { Ok(Device(device)) } else { Err(DeviceError::ConstructionFailed) }
    }

    pub fn enumerate_all_system_devices() -> Vec<Result<Self, DeviceError>> {
        let all_devices = unsafe { MTLCopyAllDevices() };
        let mut devices_vec = vec![];

        unsafe {
            for i in 0..all_devices.count() {
                let device = all_devices.objectAtIndex(i);
                if device != nil {
                    devices_vec.push(Ok(Device(device)));
                } else {
                    devices_vec.push(Err(DeviceError::ConstructionFailed));
                }
            }
        }

        devices_vec
    }

    pub fn is_depth24_stencil8_pixel_format_supported(&self) -> bool {
        unsafe { self.0.depth24Stencil8PixelFormatSupported() == YES }
    }

    pub fn is_headless(&self) -> bool {
        unsafe { self.0.headless() == YES }
    }

    pub fn is_low_power(&self) -> bool {
        unsafe { self.0.lowPower() == YES }
    }

    pub fn max_threads_per_group(&self) -> Size {
        unsafe { self.0.maxThreadsPerGroup().into() }
    }

    pub fn name(&self) -> Cow<str> {
        unsafe { CStr::from_ptr(self.0.name().UTF8String()).to_string_lossy() }
    }

    pub fn supports_feature_set(&self, feature_set: FeatureSet) -> bool {
        unsafe { self.0.supportsFeatureSet(feature_set.into()) == YES }
    }

    pub fn supports_texture_sample_count(&self, sample_count: usize) -> bool {
        unsafe { self.0.supportsTextureSampleCount(sample_count as NSUInteger) == YES }
    }

    pub fn new_command_queue(&mut self) -> Result<CommandQueue, CommandQueueError> {
        let command_queue = unsafe { self.0.newCommandQueue() };
        Ok(try!(FromRaw::from_raw(command_queue)))
    }

    pub fn new_command_queue_with_max_buffer_count(&mut self, max_command_buffer_count: usize)
                                                   -> Result<CommandQueue, CommandQueueError> {
        let command_queue = unsafe {
            self.0.newCommandQueueWithMaxCommandBufferCount(max_command_buffer_count as NSUInteger)
        };
        Ok(try!(FromRaw::from_raw(command_queue)))
    }

    // TODO(George): This will panic in the metal lib if not called from a binary in a bundle. Need
    // to add proper error checking
    pub fn new_default_library(&mut self) -> Result<Library, LibraryError> {
        unsafe {
            let library = self.0.newDefaultLibrary();
            Ok(try!(FromRaw::from_raw(library)))
        }
    }

    #[allow(unused_variables)]
    #[cfg_attr(rustfmt, rustfmt_skip)]
    pub fn new_library_with_file(&mut self, file_path: &AsRef<Path>)
                                 -> Result<Library, LibraryError> {
        unimplemented!();
    }

    pub fn new_library_with_source(&mut self, source: &AsRef<str>, compile_options: &CompileOptions)
                                   -> Result<Library, LibraryError> {
        unsafe {
            let source = NSString::alloc(nil).init_str(source.as_ref());
            let options = compile_options.mtl_compile_options();
            let mut error = nil;
            let library = self.0.newLibraryWithSource_options_error(source, options, &mut error);
            if library == nil {
                Err(LibraryError {
                    ns_error: NSError::new(error),
                    error_type: LibraryErrorType::SourceError
                })
            } else {
                Ok(try!(FromRaw::from_raw(library)))
            }
        }
    }

    #[allow(unused_variables)]
    // TODO(George): `data` parameter should be of the correct type
    pub fn new_library_with_data(&mut self, data: ()) -> Result<Library, LibraryError> {
        unimplemented!();
    }
}

impl_from_into_raw!(Device, of protocol "MTLDevice");

#[cfg(target_os = "ios")]
convertible_enum! {
    #[allow(non_camel_case_types)]
    #[derive(Clone, Copy, Eq, Hash, PartialEq)]
    pub enum FeatureSet: MTLFeatureSet {
        iOSGpuFamily1_v1 => MTLFeatureSet_iOS_GPUFamily1_v1,
        iOSGpuFamily2_v1 => MTLFeatureSet_iOS_GPUFamily2_v1,
        iOSGpuFamily1_v2 => MTLFeatureSet_iOS_GPUFamily1_v2,
        iOSGpuFamily2_v2 => MTLFeatureSet_iOS_GPUFamily2_v2,
        iOSGpuFamily3_v1 => MTLFeatureSet_iOS_GPUFamily3_v1
    }
}

#[cfg(target_os = "macos")]
convertible_enum! {
    #[allow(non_camel_case_types)]
    #[derive(Clone, Copy, Eq, Hash, PartialEq)]
    enum FeatureSet: MTLFeatureSet {
        OsxGpuFamily1_v1 => MTLFeatureSet_OSX_GPUFamily1_v1,
        _non_unary_compile_dummy => _non_unary_compile_dummy
    }
}

#[derive(Clone, Debug)]
pub enum DeviceError {
    ConstructionFailed,
    RawError(FromRawError)
}

impl From<FromRawError> for DeviceError {
    fn from(error: FromRawError) -> Self {
        DeviceError::RawError(error)
    }
}

impl Display for DeviceError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let descr = match *self {
            DeviceError::ConstructionFailed => "DeviceError::ConstructionFailed",
            DeviceError::RawError(_) => "DeviceError::ConstructionFailed",
        };
        write!(f, "{}", descr)
    }
}

impl Error for DeviceError {
    fn description(&self) -> &str {
        match *self {
            DeviceError::ConstructionFailed => {
                "Could not create a default device. Please ensure that you are using at least OSX \
                 10.11 or iOS 8.0"
            }
            DeviceError::RawError(_) => "There was an error with the device pointer",
        }
    }

    fn cause(&self) -> Option<&Error> {
        match self {
            &DeviceError::ConstructionFailed => None,
            &DeviceError::RawError(ref raw_err) => Some(raw_err),
        }
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::prelude::*;
use std::mem;
use std::process::{Output, Command, Stdio, ExitStatus};
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::{Duration, Instant};

use wait_timeout::ChildExt;

pub struct Container {
    id: String,
}

impl Container {
    pub fn new(cmd: &str,
               args: &[String],
               name: &str) -> io::Result<Container> {
        let out = try!(run(Command::new("docker")
                                   .arg("create")
                                   .arg("--cap-drop=ALL")
                                   .arg("--memory=128m")
                                   .arg("--net=none")
                                   .arg("--security-opt=no-new-privileges")
                                   .arg("--interactive")
                                   .arg(name)
                                   .arg(cmd)
                                   .stderr(Stdio::inherit())
                                   .args(args)));
        let stdout = String::from_utf8_lossy(&out.stdout);
        Ok(Container {
            id: stdout.trim().to_string(),
        })
    }

    pub fn run(&self,
               input: &[u8],
               timeout: Duration)
               -> io::Result<(ExitStatus, Vec<u8>, bool)> {
        let mut cmd = Command::new("docker");
        cmd.arg("start")
           .arg("--attach")
           .arg("--interactive")
           .arg(&self.id)
           .stdin(Stdio::piped())
           .stdout(Stdio::piped())
           .stderr(Stdio::piped());
        debug!("attaching with {:?}", cmd);
        let start = Instant::now();
        let mut cmd = try!(cmd.spawn());
        try!(cmd.stdin.take().unwrap().write_all(input));
        debug!("input written, now waiting");

        let mut stdout = cmd.stdout.take().unwrap();
        let mut stderr = cmd.stderr.take().unwrap();
        let sink = Arc::new(Mutex::new(Vec::new()));
        let sink2 = sink.clone();
        let stdout = thread::spawn(move || append(&sink2, &mut stdout));
        let sink2 = sink.clone();
        let stderr = thread::spawn(move || append(&sink2, &mut stderr));

        let (status, timeout) = match try!(cmd.wait_timeout(timeout)) {
            Some(status) => {
                debug!("finished before timeout");
                // TODO: document this
                (unsafe { mem::transmute(status) }, false)
            }
            None => {
                debug!("timeout, going to kill");
                try!(run(Command::new("docker").arg("kill").arg(&self.id)));
                (try!(cmd.wait()), true)
            }
        };
        stdout.join().unwrap();
        stderr.join().unwrap();
        debug!("timing: {:?}", start.elapsed());
        let mut lock = sink.lock().unwrap();
        let output = mem::replace(&mut *lock, Vec::new());
        debug!("status: {}", status);
        debug!("output: {}", String::from_utf8_lossy(&output));
        Ok((status, output, timeout))
    }
}

fn append(into: &Mutex<Vec<u8>>, from: &mut Read) {
    let mut buf = [0; 1024];
    while let Ok(amt) = from.read(&mut buf) {
        if amt == 0 {
            break
        }
        into.lock().unwrap().extend_from_slice(&buf[..amt]);
    }
}

impl Drop for Container {
    fn drop(&mut self) {
        run(Command::new("docker")
                    .arg("rm")
                    .arg("--force")
                    .arg(&self.id)).unwrap();
    }
}

fn run(cmd: &mut Command) -> io::Result<Output> {
    debug!("spawning: {:?}", cmd);
    let start = Instant::now();
    let out = try!(cmd.output());
    debug!("done in: {:?}", start.elapsed());
    debug!("output: {:?}", out);
    if !out.status.success() {
        let msg = format!("process failed: {:?}\n{:?}", cmd, out);
        return Err(io::Error::new(io::ErrorKind::Other, msg))
    }
    Ok(out)
}
<commit_msg>Revert "Don't pass --pids-limit for now"<commit_after>use std::io;
use std::io::prelude::*;
use std::mem;
use std::process::{Output, Command, Stdio, ExitStatus};
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::{Duration, Instant};

use wait_timeout::ChildExt;

pub struct Container {
    id: String,
}

impl Container {
    pub fn new(cmd: &str,
               args: &[String],
               name: &str) -> io::Result<Container> {
        let out = try!(run(Command::new("docker")
                                   .arg("create")
                                   .arg("--cap-drop=ALL")
                                   .arg("--memory=128m")
                                   .arg("--net=none")
                                   .arg("--pids-limit=5")
                                   .arg("--security-opt=no-new-privileges")
                                   .arg("--interactive")
                                   .arg(name)
                                   .arg(cmd)
                                   .stderr(Stdio::inherit())
                                   .args(args)));
        let stdout = String::from_utf8_lossy(&out.stdout);
        Ok(Container {
            id: stdout.trim().to_string(),
        })
    }

    pub fn run(&self,
               input: &[u8],
               timeout: Duration)
               -> io::Result<(ExitStatus, Vec<u8>, bool)> {
        let mut cmd = Command::new("docker");
        cmd.arg("start")
           .arg("--attach")
           .arg("--interactive")
           .arg(&self.id)
           .stdin(Stdio::piped())
           .stdout(Stdio::piped())
           .stderr(Stdio::piped());
        debug!("attaching with {:?}", cmd);
        let start = Instant::now();
        let mut cmd = try!(cmd.spawn());
        try!(cmd.stdin.take().unwrap().write_all(input));
        debug!("input written, now waiting");

        let mut stdout = cmd.stdout.take().unwrap();
        let mut stderr = cmd.stderr.take().unwrap();
        let sink = Arc::new(Mutex::new(Vec::new()));
        let sink2 = sink.clone();
        let stdout = thread::spawn(move || append(&sink2, &mut stdout));
        let sink2 = sink.clone();
        let stderr = thread::spawn(move || append(&sink2, &mut stderr));

        let (status, timeout) = match try!(cmd.wait_timeout(timeout)) {
            Some(status) => {
                debug!("finished before timeout");
                // TODO: document this
                (unsafe { mem::transmute(status) }, false)
            }
            None => {
                debug!("timeout, going to kill");
                try!(run(Command::new("docker").arg("kill").arg(&self.id)));
                (try!(cmd.wait()), true)
            }
        };
        stdout.join().unwrap();
        stderr.join().unwrap();
        debug!("timing: {:?}", start.elapsed());
        let mut lock = sink.lock().unwrap();
        let output = mem::replace(&mut *lock, Vec::new());
        debug!("status: {}", status);
        debug!("output: {}", String::from_utf8_lossy(&output));
        Ok((status, output, timeout))
    }
}

fn append(into: &Mutex<Vec<u8>>, from: &mut Read) {
    let mut buf = [0; 1024];
    while let Ok(amt) = from.read(&mut buf) {
        if amt == 0 {
            break
        }
        into.lock().unwrap().extend_from_slice(&buf[..amt]);
    }
}

impl Drop for Container {
    fn drop(&mut self) {
        run(Command::new("docker")
                    .arg("rm")
                    .arg("--force")
                    .arg(&self.id)).unwrap();
    }
}

fn run(cmd: &mut Command) -> io::Result<Output> {
    debug!("spawning: {:?}", cmd);
    let start = Instant::now();
    let out = try!(cmd.output());
    debug!("done in: {:?}", start.elapsed());
    debug!("output: {:?}", out);
    if !out.status.success() {
        let msg = format!("process failed: {:?}\n{:?}", cmd, out);
        return Err(io::Error::new(io::ErrorKind::Other, msg))
    }
    Ok(out)
}
<|endoftext|>


<commit_before>use error_chain::ChainedError;
use ffmpeg;
use std::sync::{Mutex, ONCE_INIT, Once};

use errors::*;

lazy_static! {
    static ref VIDEO_ENCODER: Mutex<Option<ffmpeg::codec::Video>> = Mutex::new(None);
}

/// An encoder used to encode a video to a file.
///
/// Call `Encoder::start()` to start the encoding, then encode some frames with `Encoder::encode()`.
/// The encoder will flush and save the output file automatically upon being dropped.
pub struct Encoder {
    converter: ffmpeg::software::scaling::Context,
    context: ffmpeg::format::context::Output,
    encoder: ffmpeg::codec::encoder::Video,
    output_frame: ffmpeg::util::frame::Video,
    packet: ffmpeg::Packet,
    finished: bool,

    time_base: ffmpeg::Rational,
    stream_time_base: ffmpeg::Rational,

    pts: i64,

    /// Difference, in video frames, between how much time passed in-game and how much video we
    /// output.
    remainder: f64,
}

unsafe impl Send for Encoder {}

/// Parameters for encoding and muxing.
pub struct EncoderParameters {
    pub bitrate: usize,
    pub crf: String,
    pub filename: String,
    pub muxer_settings: String,
    pub preset: String,
    pub time_base: ffmpeg::Rational,
    pub video_encoder_settings: String,
    pub vpx_cpu_usage: String,
    pub vpx_threads: String,
}

impl Encoder {
    pub fn start(parameters: &EncoderParameters, (width, height): (u32, u32)) -> Result<Self> {
        let codec = VIDEO_ENCODER.lock().unwrap();
        ensure!(codec.is_some(), "video encoder was not set");
        let codec = codec.unwrap();

        let mut context = ffmpeg::format::output(&parameters.filename)
            .chain_err(|| "could not create the output context")?;

        let encoder = {
            let mut stream =
                context.add_stream(codec)
                       .chain_err(|| "could not add the video stream")?;

            let mut encoder =
                stream.codec()
                      .encoder()
                      .video()
                      .chain_err(|| "could not retrieve the video encoder")?;

            encoder.set_width(width);
            encoder.set_height(height);
            encoder.set_time_base(parameters.time_base);
            encoder.set_bit_rate(parameters.bitrate);

            if let Some(mut formats) = codec.formats() {
                encoder.set_format(formats.next().unwrap());
            } else {
                encoder.set_format(ffmpeg::format::Pixel::YUV420P);
            }

            let encoder_settings =
                parameters.video_encoder_settings
                          .split_whitespace()
                          .filter_map(|s| {
                              let mut split = s.splitn(2, '=');

                              if let (Some(key), Some(value)) = (split.next(), split.next()) {
                                  return Some((key, value));
                              }

                              None
                          })
                          .chain([("crf", parameters.crf.as_str()),
                                  ("preset", parameters.preset.as_str()),
                                  ("cpu-usage", parameters.vpx_cpu_usage.as_str()),
                                  ("threads", parameters.vpx_threads.as_str())]
                                     .iter()
                                     .map(|x| *x)) // By-value iterators?
                          .collect();

            let encoder = encoder.open_as_with(codec, encoder_settings)
                                 .chain_err(|| "could not open the video encoder",)?;
            stream.set_parameters(&encoder);

            stream.set_time_base(parameters.time_base);

            encoder
        };

        context.write_header()
               .chain_err(|| "could not write the header")?;

        let stream_time_base = context.stream(0).unwrap().time_base();

        let converter = ffmpeg::software::converter((width, height),
                                                    ffmpeg::format::Pixel::RGB24,
                                                    encoder.format())
            .chain_err(|| "could not get the color conversion context")?;

        let output_frame = ffmpeg::frame::Video::new(encoder.format(), width, height);

        let packet = ffmpeg::Packet::empty();

        Ok(Self {
               converter,
               context,
               encoder,
               output_frame,
               packet,
               finished: false,

               time_base: parameters.time_base,
               stream_time_base,

               pts: 0,
               remainder: 0f64,
           })
    }

    fn push_frame(&mut self) -> Result<()> {
        self.output_frame.set_pts(Some(self.pts));
        self.pts += 1;

        if self.encoder
               .encode(&self.output_frame, &mut self.packet)
               .chain_err(|| "could not encode the frame")? {
            self.packet
                .rescale_ts(self.time_base, self.stream_time_base);

            self.packet
                .write_interleaved(&mut self.context)
                .chain_err(|| "could not write the packet")?;
        }

        Ok(())
    }

    pub fn take(&mut self, frame: &ffmpeg::frame::Video, frametime: f64) -> Result<()> {
        self.converter
            .run(frame, &mut self.output_frame)
            .chain_err(|| "could not convert the frame to the correct format")?;

        let time_base: f64 = self.time_base.into();
        self.remainder += frametime / time_base;

        loop {
            // Push this frame as long as it takes up the most of the video frame.
            // TODO: move this logic somewhere to skip glReadPixels and other stuff
            // altogether if we're gonna drop this frame anyway.
            if self.remainder <= 0.5f64 {
                break;
            }

            self.push_frame()?;
            self.remainder -= 1f64;
        }

        Ok(())
    }

    fn flush(&mut self) -> Result<()> {
        while self.encoder
                  .flush(&mut self.packet)
                  .chain_err(|| "could not get the packet")? {
            self.packet
                .rescale_ts(self.time_base, self.stream_time_base);

            self.packet
                .write_interleaved(&mut self.context)
                .chain_err(|| "could not write the packet")?;
        }

        Ok(())
    }

    pub fn finish(&mut self) -> Result<()> {
        // This should be at the beginning because we want to be able to drop the Encoder even if
        // stuff here fails.
        self.finished = true;

        self.flush().chain_err(|| "unable to flush the encoder")?;
        self.context
            .write_trailer()
            .chain_err(|| "could not write the trailer")?;

        Ok(())
    }

    pub fn width(&self) -> u32 {
        self.encoder.width()
    }

    pub fn height(&self) -> u32 {
        self.encoder.height()
    }
}

impl Drop for Encoder {
    fn drop(&mut self) {
        if !self.finished {
            panic!("dropped an Encoder that was not properly closed (see Encoder::finish())");
        }
    }
}

/// Initialize the encoding stuff.
pub fn initialize() {
    static INIT: Once = ONCE_INIT;

    INIT.call_once(|| {
        if let Err(ref e) = ffmpeg::init().chain_err(|| "error initializing ffmpeg") {
            panic!("{}", e.display());
        }

        *VIDEO_ENCODER.lock().unwrap() = ffmpeg::encoder::find_by_name("libx264")
            .and_then(|e| e.video().ok());
    });
}

command!(cap_set_video_encoder, |engine| {
    let mut args = engine.args();

    if args.len() != 2 {
        let mut buf = String::new();

        buf.push_str("Usage:\n");
        buf.push_str("    cap_set_video_encoder <encoder>\n");
        buf.push_str("     - Set the video encoder by name.\n");
        buf.push_str("Example:\n");
        buf.push_str("    cap_set_video_encoder libx264\n");

        engine.con_print(&buf);
        return;
    }

    let encoder_name = args.nth(1).unwrap();

    if let Some(encoder) = ffmpeg::encoder::find_by_name(&encoder_name) {
        if let Ok(video) = encoder.video() {
            let mut buf = String::new();

            buf.push_str(&format!("Selected encoder: {}\n", encoder_name));
            buf.push_str(&format!("Description: {}\n", encoder.description()));
            buf.push_str("Pixel formats: ");

            if let Some(formats) = video.formats() {
                buf.push_str(&format!("{:?}\n", formats.collect::<Vec<_>>()));
            } else {
                buf.push_str("any\n");
            }

            engine.con_print(&buf);

            *VIDEO_ENCODER.lock().unwrap() = Some(video);
        } else {
            engine.con_print(&format!("Invalid encoder type '{}'\n", encoder_name));
        }
    } else {
        engine.con_print(&format!("Unknown encoder '{}'\n", encoder_name));
    }
});

// command!(cap_test_video_output, |engine| {
//     if VIDEO_ENCODER.lock().unwrap().is_none() {
//         engine.con_print("Please set the video encoder with cap_set_video_encoder.\n");
//         return;
//     }
//
//     if let Err(ref e) = test_video_output().chain_err(|| "error in test_video_output()") {
//         engine.con_print(&format!("{}", e.display()));
//         return;
//     }
//
//     engine.con_print("Done!\n");
// });
//
// fn test_video_output() -> Result<()> {
//     let mut encoder = Encoder::start("/home/yalter/test.mkv",
//                                      (1680, 1050),
//                                      (1, 60).into())
//         .chain_err(|| "could not create the encoder")?;
//
//     let mut frame = ffmpeg::frame::Video::new(ffmpeg::format::Pixel::RGB24, 1680, 1050);
//
//     {
//         let mut data = frame.plane_mut::<(u8, u8, u8)>(0);
//         for pixel in data.iter_mut() {
//             *pixel = (0, 255, 0);
//         }
//     }
//
//     let linesize = unsafe {
//         (*frame.as_ptr()).linesize[0] / 3
//     };
//
//     for f in 0..240 {
//         {
//             let mut data = frame.plane_mut::<(u8, u8, u8)>(0);
//             for y in 0..1050 {
//                 data[y * linesize as usize + f * 2] = (255, 0, 0);
//                 data[y * linesize as usize + f * 2 + 1] = (255, 0, 0);
//             }
//         }
//
//         encoder.encode(&frame)
//             .chain_err(|| "could not encode a frame")?;
//     }
//
//     Ok(())
// }
<commit_msg>Actually add cap_muxer_settings<commit_after>use error_chain::ChainedError;
use ffmpeg;
use std::sync::{Mutex, ONCE_INIT, Once};

use errors::*;

lazy_static! {
    static ref VIDEO_ENCODER: Mutex<Option<ffmpeg::codec::Video>> = Mutex::new(None);
}

/// An encoder used to encode a video to a file.
///
/// Call `Encoder::start()` to start the encoding, then encode some frames with `Encoder::encode()`.
/// The encoder will flush and save the output file automatically upon being dropped.
pub struct Encoder {
    converter: ffmpeg::software::scaling::Context,
    context: ffmpeg::format::context::Output,
    encoder: ffmpeg::codec::encoder::Video,
    output_frame: ffmpeg::util::frame::Video,
    packet: ffmpeg::Packet,
    finished: bool,

    time_base: ffmpeg::Rational,
    stream_time_base: ffmpeg::Rational,

    pts: i64,

    /// Difference, in video frames, between how much time passed in-game and how much video we
    /// output.
    remainder: f64,
}

unsafe impl Send for Encoder {}

/// Parameters for encoding and muxing.
pub struct EncoderParameters {
    pub bitrate: usize,
    pub crf: String,
    pub filename: String,
    pub muxer_settings: String,
    pub preset: String,
    pub time_base: ffmpeg::Rational,
    pub video_encoder_settings: String,
    pub vpx_cpu_usage: String,
    pub vpx_threads: String,
}

impl Encoder {
    pub fn start(parameters: &EncoderParameters, (width, height): (u32, u32)) -> Result<Self> {
        let codec = VIDEO_ENCODER.lock().unwrap();
        ensure!(codec.is_some(), "video encoder was not set");
        let codec = codec.unwrap();

        let mut context = ffmpeg::format::output(&parameters.filename)
            .chain_err(|| "could not create the output context")?;

        let encoder = {
            let mut stream =
                context.add_stream(codec)
                       .chain_err(|| "could not add the video stream")?;

            let mut encoder =
                stream.codec()
                      .encoder()
                      .video()
                      .chain_err(|| "could not retrieve the video encoder")?;

            encoder.set_width(width);
            encoder.set_height(height);
            encoder.set_time_base(parameters.time_base);
            encoder.set_bit_rate(parameters.bitrate);

            if let Some(mut formats) = codec.formats() {
                encoder.set_format(formats.next().unwrap());
            } else {
                encoder.set_format(ffmpeg::format::Pixel::YUV420P);
            }

            let encoder_settings =
                parameters.video_encoder_settings
                          .split_whitespace()
                          .filter_map(|s| {
                              let mut split = s.splitn(2, '=');

                              if let (Some(key), Some(value)) = (split.next(), split.next()) {
                                  return Some((key, value));
                              }

                              None
                          })
                          .chain([("crf", parameters.crf.as_str()),
                                  ("preset", parameters.preset.as_str()),
                                  ("cpu-usage", parameters.vpx_cpu_usage.as_str()),
                                  ("threads", parameters.vpx_threads.as_str())]
                                     .iter()
                                     .map(|x| *x)) // By-value iterators?
                          .collect();

            let encoder = encoder.open_as_with(codec, encoder_settings)
                                 .chain_err(|| "could not open the video encoder",)?;
            stream.set_parameters(&encoder);

            stream.set_time_base(parameters.time_base);

            encoder
        };

        let muxer_settings = parameters.muxer_settings
            .split_whitespace()
            .filter_map(|s| {
                let mut split = s.splitn(2, '=');

                if let (Some(key), Some(value)) = (split.next(), split.next()) {
                    return Some((key, value));
                }

                None
            }).collect();

        context.write_header_with(muxer_settings)
               .chain_err(|| "could not write the header")?;

        let stream_time_base = context.stream(0).unwrap().time_base();

        let converter = ffmpeg::software::converter((width, height),
                                                    ffmpeg::format::Pixel::RGB24,
                                                    encoder.format())
            .chain_err(|| "could not get the color conversion context")?;

        let output_frame = ffmpeg::frame::Video::new(encoder.format(), width, height);

        let packet = ffmpeg::Packet::empty();

        Ok(Self {
               converter,
               context,
               encoder,
               output_frame,
               packet,
               finished: false,

               time_base: parameters.time_base,
               stream_time_base,

               pts: 0,
               remainder: 0f64,
           })
    }

    fn push_frame(&mut self) -> Result<()> {
        self.output_frame.set_pts(Some(self.pts));
        self.pts += 1;

        if self.encoder
               .encode(&self.output_frame, &mut self.packet)
               .chain_err(|| "could not encode the frame")? {
            self.packet
                .rescale_ts(self.time_base, self.stream_time_base);

            self.packet
                .write_interleaved(&mut self.context)
                .chain_err(|| "could not write the packet")?;
        }

        Ok(())
    }

    pub fn take(&mut self, frame: &ffmpeg::frame::Video, frametime: f64) -> Result<()> {
        self.converter
            .run(frame, &mut self.output_frame)
            .chain_err(|| "could not convert the frame to the correct format")?;

        let time_base: f64 = self.time_base.into();
        self.remainder += frametime / time_base;

        loop {
            // Push this frame as long as it takes up the most of the video frame.
            // TODO: move this logic somewhere to skip glReadPixels and other stuff
            // altogether if we're gonna drop this frame anyway.
            if self.remainder <= 0.5f64 {
                break;
            }

            self.push_frame()?;
            self.remainder -= 1f64;
        }

        Ok(())
    }

    fn flush(&mut self) -> Result<()> {
        while self.encoder
                  .flush(&mut self.packet)
                  .chain_err(|| "could not get the packet")? {
            self.packet
                .rescale_ts(self.time_base, self.stream_time_base);

            self.packet
                .write_interleaved(&mut self.context)
                .chain_err(|| "could not write the packet")?;
        }

        Ok(())
    }

    pub fn finish(&mut self) -> Result<()> {
        // This should be at the beginning because we want to be able to drop the Encoder even if
        // stuff here fails.
        self.finished = true;

        self.flush().chain_err(|| "unable to flush the encoder")?;
        self.context
            .write_trailer()
            .chain_err(|| "could not write the trailer")?;

        Ok(())
    }

    pub fn width(&self) -> u32 {
        self.encoder.width()
    }

    pub fn height(&self) -> u32 {
        self.encoder.height()
    }
}

impl Drop for Encoder {
    fn drop(&mut self) {
        if !self.finished {
            panic!("dropped an Encoder that was not properly closed (see Encoder::finish())");
        }
    }
}

/// Initialize the encoding stuff.
pub fn initialize() {
    static INIT: Once = ONCE_INIT;

    INIT.call_once(|| {
        if let Err(ref e) = ffmpeg::init().chain_err(|| "error initializing ffmpeg") {
            panic!("{}", e.display());
        }

        *VIDEO_ENCODER.lock().unwrap() = ffmpeg::encoder::find_by_name("libx264")
            .and_then(|e| e.video().ok());
    });
}

command!(cap_set_video_encoder, |engine| {
    let mut args = engine.args();

    if args.len() != 2 {
        let mut buf = String::new();

        buf.push_str("Usage:\n");
        buf.push_str("    cap_set_video_encoder <encoder>\n");
        buf.push_str("     - Set the video encoder by name.\n");
        buf.push_str("Example:\n");
        buf.push_str("    cap_set_video_encoder libx264\n");

        engine.con_print(&buf);
        return;
    }

    let encoder_name = args.nth(1).unwrap();

    if let Some(encoder) = ffmpeg::encoder::find_by_name(&encoder_name) {
        if let Ok(video) = encoder.video() {
            let mut buf = String::new();

            buf.push_str(&format!("Selected encoder: {}\n", encoder_name));
            buf.push_str(&format!("Description: {}\n", encoder.description()));
            buf.push_str("Pixel formats: ");

            if let Some(formats) = video.formats() {
                buf.push_str(&format!("{:?}\n", formats.collect::<Vec<_>>()));
            } else {
                buf.push_str("any\n");
            }

            engine.con_print(&buf);

            *VIDEO_ENCODER.lock().unwrap() = Some(video);
        } else {
            engine.con_print(&format!("Invalid encoder type '{}'\n", encoder_name));
        }
    } else {
        engine.con_print(&format!("Unknown encoder '{}'\n", encoder_name));
    }
});

// command!(cap_test_video_output, |engine| {
//     if VIDEO_ENCODER.lock().unwrap().is_none() {
//         engine.con_print("Please set the video encoder with cap_set_video_encoder.\n");
//         return;
//     }
//
//     if let Err(ref e) = test_video_output().chain_err(|| "error in test_video_output()") {
//         engine.con_print(&format!("{}", e.display()));
//         return;
//     }
//
//     engine.con_print("Done!\n");
// });
//
// fn test_video_output() -> Result<()> {
//     let mut encoder = Encoder::start("/home/yalter/test.mkv",
//                                      (1680, 1050),
//                                      (1, 60).into())
//         .chain_err(|| "could not create the encoder")?;
//
//     let mut frame = ffmpeg::frame::Video::new(ffmpeg::format::Pixel::RGB24, 1680, 1050);
//
//     {
//         let mut data = frame.plane_mut::<(u8, u8, u8)>(0);
//         for pixel in data.iter_mut() {
//             *pixel = (0, 255, 0);
//         }
//     }
//
//     let linesize = unsafe {
//         (*frame.as_ptr()).linesize[0] / 3
//     };
//
//     for f in 0..240 {
//         {
//             let mut data = frame.plane_mut::<(u8, u8, u8)>(0);
//             for y in 0..1050 {
//                 data[y * linesize as usize + f * 2] = (255, 0, 0);
//                 data[y * linesize as usize + f * 2 + 1] = (255, 0, 0);
//             }
//         }
//
//         encoder.encode(&frame)
//             .chain_err(|| "could not encode a frame")?;
//     }
//
//     Ok(())
// }
<|endoftext|>


<commit_before>use std::str;
use network::{ActorId, ObjectId, StreamId};
use attributes::Attribute;

#[derive(PartialEq, Debug, Clone, Fail)]
pub enum ParseError {
    #[fail(display = "A size of zero is not valid")] ZeroSize,

    #[fail(display = "Unable decode data as utf8: {}", _0)] Utf8Error(#[cause] str::Utf8Error),

    #[fail(display = "Text of size {} is too large", _0)] TextTooLarge(i32),

    #[fail(display = "Insufficient data. Expected {} bytes, but only {} left", _0, _1)]
    InsufficientData(i32, i32),

    #[fail(display = "Did not expect a property of: {}", _0)] UnexpectedProperty(String),

    #[fail(display = "Crc mismatch. Expected {} but received {}", _0, _1)] CrcMismatch(u32, u32),

    #[fail(display = "list of size {} is too large", _0)] ListTooLarge(usize),
}

impl From<str::Utf8Error> for ParseError {
    fn from(error: str::Utf8Error) -> Self {
        ParseError::Utf8Error(error)
    }
}

#[derive(PartialEq, Debug, Clone, Fail)]
pub enum AttributeError {
    #[fail(display = "Not enough data to decode attribute {}", _0)] NotEnoughDataFor(&'static str),

    #[fail(display = "Unrecognized remote id of {}", _0)] UnrecognizedRemoteId(u8),

    #[fail(display = "Does not have an attribute implementation")] Unimplemented,

    #[fail(display = "Unexpected size for string: {}", _0)] TooBigString(i32),
}

#[derive(PartialEq, Debug, Clone, Fail)]
pub enum NetworkError {
    #[fail(display = "Not enough data to decode {}", _0)]
    NotEnoughDataFor(&'static str),

    #[fail(display = "Time is out of range: {}", _0)]
    TimeOutOfRange(f32),

    #[fail(display = "Backtracking from frame: {} to {}, the last actor ({}) had a stream id of {}. This may mean that a new update of Rocket League updated this attribute. Decoded into {:?}", _0, _1, _2, _3, _4)]
    TimeOutOfRangeUpdate(usize, usize, ActorId, StreamId, Attribute),

    #[fail(display = "Delta is out of range: {}", _0)]
    DeltaOutOfRange(f32),

    #[fail(display = "Too many stream ids ({}) for object id: {}", _0, _1)]
    MaxStreamIdTooLarge(i32, ObjectId),

    #[fail(display = "Number of channels exceeds maximum: {}", _0)]
    ChannelsTooLarge(i32),

    #[fail(display = "Object Id of {} exceeds range", _0)]
    ObjectIdOutOfRange(ObjectId),

    #[fail(display = "Stream id of {} references out of range object index: {}", _0, _1)]
    StreamTooLargeIndex(i32, i32),

    #[fail(display = "Replay contained object: {} but not the parent class: {}", _0, _1)]
    MissingParentClass(String, String),

    #[fail(display = "Parent id of {} for object id of {} was not recognized to have attributes", _0, _1)]
    ParentHasNoAttributes(ObjectId, ObjectId),

    #[fail(display = "Actor id: {} was not found", _0)]
    MissingActor(ActorId),

    #[fail(display = "Actor id: {} of object id: {} ({}) but no attributes found", _0, _1, _2)]
    MissingCache(ActorId, ObjectId, String),

    #[fail(display = "Actor id: {} of object id: {} ({}) but stream id: {} not found in {}", _0, _1, _2, _3, _4)]
    MissingAttribute(ActorId, ObjectId, String, StreamId, String),

    #[fail(display = "Actor id: {} of object id: {} ({}) but stream id: {} ({}) was not implemented. Possible missing implementations for stream id {}\n{}", _0, _1, _2, _3, _4, _3, _5)]
    UnimplementedAttribute(ActorId, ObjectId, String, StreamId, String, String),

    #[fail(display = "Attribute error: {}", _0)]
    AttributeError(#[cause] AttributeError),
}
<commit_msg>Reformat errors<commit_after>use std::str;
use network::{ActorId, ObjectId, StreamId};
use attributes::Attribute;

#[derive(PartialEq, Debug, Clone, Fail)]
pub enum ParseError {
    #[fail(display = "A size of zero is not valid")]
    ZeroSize,

    #[fail(display = "Unable decode data as utf8: {}", _0)]
    Utf8Error(#[cause] str::Utf8Error),

    #[fail(display = "Text of size {} is too large", _0)]
    TextTooLarge(i32),

    #[fail(display = "Insufficient data. Expected {} bytes, but only {} left", _0, _1)]
    InsufficientData(i32, i32),

    #[fail(display = "Did not expect a property of: {}", _0)]
    UnexpectedProperty(String),

    #[fail(display = "Crc mismatch. Expected {} but received {}", _0, _1)]
    CrcMismatch(u32, u32),

    #[fail(display = "list of size {} is too large", _0)]
    ListTooLarge(usize),
}

impl From<str::Utf8Error> for ParseError {
    fn from(error: str::Utf8Error) -> Self {
        ParseError::Utf8Error(error)
    }
}

#[derive(PartialEq, Debug, Clone, Fail)]
pub enum AttributeError {
    #[fail(display = "Not enough data to decode attribute {}", _0)]
    NotEnoughDataFor(&'static str),

    #[fail(display = "Unrecognized remote id of {}", _0)]
    UnrecognizedRemoteId(u8),

    #[fail(display = "Does not have an attribute implementation")]
    Unimplemented,

    #[fail(display = "Unexpected size for string: {}", _0)]
    TooBigString(i32),
}

#[derive(PartialEq, Debug, Clone, Fail)]
pub enum NetworkError {
    #[fail(display = "Not enough data to decode {}", _0)]
    NotEnoughDataFor(&'static str),

    #[fail(display = "Time is out of range: {}", _0)]
    TimeOutOfRange(f32),

    #[fail(display = "Backtracking from frame: {} to {}, the last actor ({}) had a stream id of {}. This may mean that a new update of Rocket League updated this attribute. Decoded into {:?}", _0, _1, _2, _3, _4)]
    TimeOutOfRangeUpdate(usize, usize, ActorId, StreamId, Attribute),

    #[fail(display = "Delta is out of range: {}", _0)]
    DeltaOutOfRange(f32),

    #[fail(display = "Too many stream ids ({}) for object id: {}", _0, _1)]
    MaxStreamIdTooLarge(i32, ObjectId),

    #[fail(display = "Number of channels exceeds maximum: {}", _0)]
    ChannelsTooLarge(i32),

    #[fail(display = "Object Id of {} exceeds range", _0)]
    ObjectIdOutOfRange(ObjectId),

    #[fail(display = "Stream id of {} references out of range object index: {}", _0, _1)]
    StreamTooLargeIndex(i32, i32),

    #[fail(display = "Replay contained object: {} but not the parent class: {}", _0, _1)]
    MissingParentClass(String, String),

    #[fail(display = "Parent id of {} for object id of {} was not recognized to have attributes", _0, _1)]
    ParentHasNoAttributes(ObjectId, ObjectId),

    #[fail(display = "Actor id: {} was not found", _0)]
    MissingActor(ActorId),

    #[fail(display = "Actor id: {} of object id: {} ({}) but no attributes found", _0, _1, _2)]
    MissingCache(ActorId, ObjectId, String),

    #[fail(display = "Actor id: {} of object id: {} ({}) but stream id: {} not found in {}", _0, _1, _2, _3, _4)]
    MissingAttribute(ActorId, ObjectId, String, StreamId, String),

    #[fail(display = "Actor id: {} of object id: {} ({}) but stream id: {} ({}) was not implemented. Possible missing implementations for stream id {}\n{}", _0, _1, _2, _3, _4, _3, _5)]
    UnimplementedAttribute(ActorId, ObjectId, String, StreamId, String, String),

    #[fail(display = "Attribute error: {}", _0)]
    AttributeError(#[cause] AttributeError),
}
<|endoftext|>


<commit_before>use std::env;
use std::path::PathBuf;

pub struct EnvironmentUtils {}

impl EnvironmentUtils {
    pub fn indy_home_path() -> PathBuf {
        // TODO: FIXME: Provide better handling for the unknown home path case!!!
        let mut path = env::home_dir().unwrap_or(PathBuf::from("/home/indy"));
        let mut indy_client_dir = ".indy_client";
        if cfg!(target_os = "ios"){
            indy_client_dir = "Documents/.indy_client"
        }else if cfg!(target_os = "android"){ //TODO: FIX ME: Check for more secure location for the wallet.
            indy_client_dir = "/sdcard/Documents/.indy_client"
        }
        path.push(indy_client_dir);
        path
    }

    pub fn wallet_home_path() -> PathBuf {
        let mut path = EnvironmentUtils::indy_home_path();
        path.push("wallet");
        path
    }

    pub fn wallet_path(wallet_name: &str) -> PathBuf {
        let mut path = EnvironmentUtils::wallet_home_path();
        path.push(wallet_name);
        path
    }

    pub fn pool_home_path() -> PathBuf {
        let mut path = EnvironmentUtils::indy_home_path();
        path.push("pool");
        path
    }

    pub fn pool_path(pool_name: &str) -> PathBuf {
        let mut path = EnvironmentUtils::pool_home_path();
        path.push(pool_name);
        path
    }

    pub fn tmp_path() -> PathBuf {
        let mut path = env::temp_dir();
        path.push("indy_client");
        path
    }

    pub fn tmp_file_path(file_name: &str) -> PathBuf {
        let mut path = EnvironmentUtils::tmp_path();
        path.push(file_name);
        path
    }

    #[cfg(test)]
    pub fn test_pool_ip() -> String {
        env::var("TEST_POOL_IP").unwrap_or("127.0.0.1".to_string())
    }
}

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

    #[test]
    fn indy_home_path_works() {
        let path = EnvironmentUtils::indy_home_path();

        assert!(path.is_absolute());
        assert!(path.has_root());
        assert!(path.to_string_lossy().contains(".indy_client"));
    }

    #[test]
    fn wallet_home_path_works() {
        let path = EnvironmentUtils::wallet_home_path();

        assert!(path.is_absolute());
        assert!(path.has_root());
        assert!(path.to_string_lossy().contains(".indy_client"));
        assert!(path.to_string_lossy().contains("wallet"));
    }

    #[test]
    fn wallet_path_works() {
        let path = EnvironmentUtils::wallet_path("wallet1");

        assert!(path.is_absolute());
        assert!(path.has_root());
        assert!(path.to_string_lossy().contains(".indy_client"));
        assert!(path.to_string_lossy().contains("wallet1"));
    }

    #[test]
    fn pool_home_path_works() {
        let path = EnvironmentUtils::pool_home_path();

        assert!(path.is_absolute());
        assert!(path.has_root());
        assert!(path.to_string_lossy().contains(".indy_client"));
        assert!(path.to_string_lossy().contains("pool"));
    }

    #[test]
    fn pool_path_works() {
        let path = EnvironmentUtils::pool_path("pool1");

        assert!(path.is_absolute());
        assert!(path.has_root());
        assert!(path.to_string_lossy().contains(".indy_client"));
        assert!(path.to_string_lossy().contains("pool1"));
    }

    #[test]
    fn tmp_path_works() {
        let path = EnvironmentUtils::tmp_path();

        assert!(path.is_absolute());
        assert!(path.has_root());
        assert!(path.to_string_lossy().contains("indy_client"));
    }

    #[test]
    fn tmp_file_path_works() {
        let path = EnvironmentUtils::tmp_file_path("test.txt");

        assert!(path.is_absolute());
        assert!(path.has_root());
        assert!(path.to_string_lossy().contains("indy_client"));
        assert!(path.to_string_lossy().contains("test.txt"));
    }

    #[test]
    fn test_pool_ip_works() {
        let pool_ip = EnvironmentUtils::test_pool_ip();
        assert!(!pool_ip.is_empty());
    }
}<commit_msg>Fixed external storage path for universal compatibility<commit_after>use std::env;
use std::path::PathBuf;

pub struct EnvironmentUtils {}

impl EnvironmentUtils {
    pub fn indy_home_path() -> PathBuf {
        // TODO: FIXME: Provide better handling for the unknown home path case!!!
        let mut path = env::home_dir().unwrap_or(PathBuf::from("/home/indy"));
        let mut indy_client_dir = ".indy_client";
        if cfg!(target_os = "ios"){
            indy_client_dir = "Documents/.indy_client"
        }else if cfg!(target_os = "android"){ //TODO: FIX ME: Check for more secure location for the wallet.
            indy_client_dir = env::var("EXTERNAL_STORAGE") +  ".indy_client"
        }
        path.push(indy_client_dir);
        path
    }

    pub fn wallet_home_path() -> PathBuf {
        let mut path = EnvironmentUtils::indy_home_path();
        path.push("wallet");
        path
    }

    pub fn wallet_path(wallet_name: &str) -> PathBuf {
        let mut path = EnvironmentUtils::wallet_home_path();
        path.push(wallet_name);
        path
    }

    pub fn pool_home_path() -> PathBuf {
        let mut path = EnvironmentUtils::indy_home_path();
        path.push("pool");
        path
    }

    pub fn pool_path(pool_name: &str) -> PathBuf {
        let mut path = EnvironmentUtils::pool_home_path();
        path.push(pool_name);
        path
    }

    pub fn tmp_path() -> PathBuf {
        let mut path = env::temp_dir();
        path.push("indy_client");
        path
    }

    pub fn tmp_file_path(file_name: &str) -> PathBuf {
        let mut path = EnvironmentUtils::tmp_path();
        path.push(file_name);
        path
    }

    #[cfg(test)]
    pub fn test_pool_ip() -> String {
        env::var("TEST_POOL_IP").unwrap_or("127.0.0.1".to_string())
    }
}

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

    #[test]
    fn indy_home_path_works() {
        let path = EnvironmentUtils::indy_home_path();

        assert!(path.is_absolute());
        assert!(path.has_root());
        assert!(path.to_string_lossy().contains(".indy_client"));
    }

    #[test]
    fn wallet_home_path_works() {
        let path = EnvironmentUtils::wallet_home_path();

        assert!(path.is_absolute());
        assert!(path.has_root());
        assert!(path.to_string_lossy().contains(".indy_client"));
        assert!(path.to_string_lossy().contains("wallet"));
    }

    #[test]
    fn wallet_path_works() {
        let path = EnvironmentUtils::wallet_path("wallet1");

        assert!(path.is_absolute());
        assert!(path.has_root());
        assert!(path.to_string_lossy().contains(".indy_client"));
        assert!(path.to_string_lossy().contains("wallet1"));
    }

    #[test]
    fn pool_home_path_works() {
        let path = EnvironmentUtils::pool_home_path();

        assert!(path.is_absolute());
        assert!(path.has_root());
        assert!(path.to_string_lossy().contains(".indy_client"));
        assert!(path.to_string_lossy().contains("pool"));
    }

    #[test]
    fn pool_path_works() {
        let path = EnvironmentUtils::pool_path("pool1");

        assert!(path.is_absolute());
        assert!(path.has_root());
        assert!(path.to_string_lossy().contains(".indy_client"));
        assert!(path.to_string_lossy().contains("pool1"));
    }

    #[test]
    fn tmp_path_works() {
        let path = EnvironmentUtils::tmp_path();

        assert!(path.is_absolute());
        assert!(path.has_root());
        assert!(path.to_string_lossy().contains("indy_client"));
    }

    #[test]
    fn tmp_file_path_works() {
        let path = EnvironmentUtils::tmp_file_path("test.txt");

        assert!(path.is_absolute());
        assert!(path.has_root());
        assert!(path.to_string_lossy().contains("indy_client"));
        assert!(path.to_string_lossy().contains("test.txt"));
    }

    #[test]
    fn test_pool_ip_works() {
        let pool_ip = EnvironmentUtils::test_pool_ip();
        assert!(!pool_ip.is_empty());
    }
}<|endoftext|>


<commit_before>extern crate std;
extern crate hyper;
extern crate serde_json;

use std::string::String;
use std::io::Read;
use self::serde_json::Value;

#[derive(Debug)]
pub struct GithubError;

impl From<hyper::error::Error> for GithubError {
    fn from(_: hyper::error::Error) -> Self {
        GithubError
    }
}

impl From<serde_json::error::Error> for GithubError {
    fn from(_: serde_json::error::Error) -> Self {
        GithubError
    }
}

impl From<std::io::Error> for GithubError {
    fn from(_: std::io::Error) -> Self {
        GithubError
    }
}

pub fn get_display_text(user: &str, repo: &str, issue: &str)
    -> Result<String, GithubError> {

    let url = format!("https://api.github.com/repos/{}/{}/issues/{}",
                      user, repo, issue);
    let client = hyper::client::Client::new();
    let mut resp = try!(client
        .get(&url)
        .header(hyper::header::UserAgent("ids1024".to_owned()))
        .send());

    let mut body = String::new();
    try!(resp.read_to_string(&mut body));
    let data: Value = try!(serde_json::from_str(&body));
    let obj = try!(data.as_object().ok_or(GithubError));

    let title = try!(try!(obj.get("title").ok_or(GithubError))
                     .as_string().ok_or(GithubError));
    let state = try!(try!(obj.get("state").ok_or(GithubError))
                     .as_string().ok_or(GithubError));
    let url = try!(try!(obj.get("html_url").ok_or(GithubError))
                        .as_string().ok_or(GithubError));
    let issuetype =
        if obj.get("pull_request") != None {
            "pull request"
        } else {
            "issue"
        };

    return Ok(format!("[{}] [{}] {}\n{}", issuetype, state, title, url));
}
<commit_msg>Use Option.is_some() instead of != None<commit_after>extern crate std;
extern crate hyper;
extern crate serde_json;

use std::string::String;
use std::io::Read;
use self::serde_json::Value;

#[derive(Debug)]
pub struct GithubError;

impl From<hyper::error::Error> for GithubError {
    fn from(_: hyper::error::Error) -> Self {
        GithubError
    }
}

impl From<serde_json::error::Error> for GithubError {
    fn from(_: serde_json::error::Error) -> Self {
        GithubError
    }
}

impl From<std::io::Error> for GithubError {
    fn from(_: std::io::Error) -> Self {
        GithubError
    }
}

pub fn get_display_text(user: &str, repo: &str, issue: &str)
    -> Result<String, GithubError> {

    let url = format!("https://api.github.com/repos/{}/{}/issues/{}",
                      user, repo, issue);
    let client = hyper::client::Client::new();
    let mut resp = try!(client
        .get(&url)
        .header(hyper::header::UserAgent("ids1024".to_owned()))
        .send());

    let mut body = String::new();
    try!(resp.read_to_string(&mut body));
    let data: Value = try!(serde_json::from_str(&body));
    let obj = try!(data.as_object().ok_or(GithubError));

    let title = try!(try!(obj.get("title").ok_or(GithubError))
                     .as_string().ok_or(GithubError));
    let state = try!(try!(obj.get("state").ok_or(GithubError))
                     .as_string().ok_or(GithubError));
    let url = try!(try!(obj.get("html_url").ok_or(GithubError))
                        .as_string().ok_or(GithubError));
    let issuetype =
        if obj.get("pull_request").is_some() {
            "pull request"
        } else {
            "issue"
        };

    return Ok(format!("[{}] [{}] {}\n{}", issuetype, state, title, url));
}
<|endoftext|>


<commit_before>
use std::fmt;
use std::io::Read;  // Trait providing read_to_string()
use std::env;

use hyper;
use serde;
use serde_json;

use BuildQuery;
use Groups;

pub const API_VERSION: u16 = 3;

#[derive(Default, Clone, Copy, Debug)]
pub struct Pagination {
    pub page: u16,
    pub per_page: u16,
}

#[derive(Default)]
pub struct GitLab {
    scheme: String,
    domain: String,
    port: u16,
    private_token: String,
    pagination: Option<Pagination>,
    client: hyper::Client,
}

// Explicitly implement Debug trait for GitLab so we can hide the token.
impl fmt::Debug for GitLab {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "GitLab {{ scheme: {}, domain: {}, port: {}, private_token: XXXXXXXXXXXXXXXXXXXX, \
                pagination: {:?} }}",
               self.scheme,
               self.domain,
               self.port,
            // client: {:?}, \
            //    self.client,
               self.pagination)
    }
}

impl GitLab {
    pub fn _new(scheme: &str, domain: &str, port: u16, private_token: &str) -> GitLab {
        GitLab {
            scheme: scheme.to_string(),
            domain: domain.to_string(),
            port: port,
            private_token: private_token.to_string(),
            pagination: None,
            client: match env::var("HTTP_PROXY") {
                Ok(proxy) => {
                    let proxy: Vec<&str> = proxy.trim_left_matches("http://").split(':').collect();
                    let hostname = proxy[0].to_string();
                    let port = proxy[1];

                    hyper::Client::with_http_proxy(hostname, port.parse().unwrap())
                }
                Err(_) => hyper::Client::new(),
            },
        }
    }

    pub fn new_insecure(domain: &str, private_token: &str) -> GitLab {
        warn!("Using insecure http:// protocol: Token will be sent in clear!");
        GitLab::_new("http", domain, 80, private_token)
    }

    pub fn new(domain: &str, private_token: &str) -> GitLab {
        GitLab::_new("https", domain, 443, private_token)
    }

    /// Build a URL used to access GitLab instance, including some parameters.
    ///
    /// # Examples
    ///
    /// Example from GitLab: https://docs.gitlab.com/ce/api/#basic-usage
    ///
    /// ```
    /// use gitlab_api::GitLab;
    ///
    /// let expected_url = "https://gitlab.example.com:\
    ///                     443/api/v3/groups?order_by=path&private_token=XXXXXXXXXXXXX";
    ///
    /// let gl = GitLab::new("gitlab.example.com", "XXXXXXXXXXXXX");
    ///
    /// assert_eq!(gl.build_url("groups?order_by=path"), expected_url);
    /// ```
    pub fn build_url(&self, query: &str) -> String {
        let params_splitter = if query.find('?').is_some() { "&" } else { "?" };
        let mut url = format!("{}://{}:{}/api/v{}/{}{}private_token={}",
                              self.scheme,
                              self.domain,
                              self.port,
                              API_VERSION,
                              query,
                              params_splitter,
                              self.private_token);

        self.pagination.as_ref().map(|pagination| {
            url.push_str(&format!("&page={}&per_page={}", pagination.page, pagination.per_page));
        });

        url
    }

    // pub fn attempt_connection(&self) -> Result<hyper::client::Response, hyper::Error> {
    //     let url = self.build_url("version");
    //     // Close connections after each GET.
    //     self.client.get(&url).header(hyper::header::Connection::close()).send()
    // }

    pub fn set_pagination(&mut self, pagination: Pagination) {
        self.pagination = Some(pagination);
    }

    pub fn get<T>(&self, query: &str) -> Result<T, serde_json::Error>
        where T: serde::Deserialize
    {
        // FIXME: Properly handle any errors. Use chain_error crate.

        let url = self.build_url(query);
        info!("url: {:?}", url);

        // Close connections after each GET.
        let mut res: hyper::client::Response = self.client
            .get(&url)
            .header(hyper::header::Connection::close())
            .send()
            .unwrap();
        info!("res.status: {:?}", res.status);
        debug!("res.headers: {:?}", res.headers);
        debug!("res.url: {:?}", res.url);

        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();
        debug!("body:\n{:?}", body);

        assert_eq!(res.status, hyper::status::StatusCode::Ok);

        serde_json::from_str(body.as_str())
    }

    // pub fn version(&self) -> Result<Version, serde_json::Error> {
    //     self.get("version")
    // }
    //
    // pub fn groups(&self) -> Result<Groups, serde_json::Error> {
    //     self.get("groups")
    // }

    pub fn projects(&self) -> ::projects::ProjectsLister {
        ::projects::ProjectsLister::new(&self)
    }

    pub fn groups(&mut self, listing: ::groups::Listing) -> Result<Groups, serde_json::Error> {
        let query = listing.build_query();
        // self.get(&query)
        unimplemented!();
    }

    pub fn owned_groups(&mut self) -> Result<Groups, serde_json::Error> {
        let query = ::groups::owned_groups::Listing::new().build_query();
        info!("query: {:?}", query);
        self.get(&query)
    }
}

// #[cfg(test)]
// mod tests {
//
// #[test]
// fn it_works() {
// }
// }
//
<commit_msg>Cleanup commented code<commit_after>
use std::fmt;
use std::io::Read;  // Trait providing read_to_string()
use std::env;

use hyper;
use serde;
use serde_json;

use BuildQuery;
use Groups;

pub const API_VERSION: u16 = 3;

#[derive(Default, Clone, Copy, Debug)]
pub struct Pagination {
    pub page: u16,
    pub per_page: u16,
}

#[derive(Default)]
pub struct GitLab {
    scheme: String,
    domain: String,
    port: u16,
    private_token: String,
    pagination: Option<Pagination>,
    client: hyper::Client,
}

// Explicitly implement Debug trait for GitLab so we can hide the token.
impl fmt::Debug for GitLab {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "GitLab {{ scheme: {}, domain: {}, port: {}, private_token: XXXXXXXXXXXXXXXXXXXX, \
                pagination: {:?} }}",
               self.scheme,
               self.domain,
               self.port,
               self.pagination)
    }
}

impl GitLab {
    pub fn _new(scheme: &str, domain: &str, port: u16, private_token: &str) -> GitLab {
        GitLab {
            scheme: scheme.to_string(),
            domain: domain.to_string(),
            port: port,
            private_token: private_token.to_string(),
            pagination: None,
            client: match env::var("HTTP_PROXY") {
                Ok(proxy) => {
                    let proxy: Vec<&str> = proxy.trim_left_matches("http://").split(':').collect();
                    let hostname = proxy[0].to_string();
                    let port = proxy[1];

                    hyper::Client::with_http_proxy(hostname, port.parse().unwrap())
                }
                Err(_) => hyper::Client::new(),
            },
        }
    }

    pub fn new_insecure(domain: &str, private_token: &str) -> GitLab {
        warn!("Using insecure http:// protocol: Token will be sent in clear!");
        GitLab::_new("http", domain, 80, private_token)
    }

    pub fn new(domain: &str, private_token: &str) -> GitLab {
        GitLab::_new("https", domain, 443, private_token)
    }

    /// Build a URL used to access GitLab instance, including some parameters.
    ///
    /// # Examples
    ///
    /// Example from GitLab: https://docs.gitlab.com/ce/api/#basic-usage
    ///
    /// ```
    /// use gitlab_api::GitLab;
    ///
    /// let expected_url = "https://gitlab.example.com:\
    ///                     443/api/v3/groups?order_by=path&private_token=XXXXXXXXXXXXX";
    ///
    /// let gl = GitLab::new("gitlab.example.com", "XXXXXXXXXXXXX");
    ///
    /// assert_eq!(gl.build_url("groups?order_by=path"), expected_url);
    /// ```
    pub fn build_url(&self, query: &str) -> String {
        let params_splitter = if query.find('?').is_some() { "&" } else { "?" };
        let mut url = format!("{}://{}:{}/api/v{}/{}{}private_token={}",
                              self.scheme,
                              self.domain,
                              self.port,
                              API_VERSION,
                              query,
                              params_splitter,
                              self.private_token);

        self.pagination.as_ref().map(|pagination| {
            url.push_str(&format!("&page={}&per_page={}", pagination.page, pagination.per_page));
        });

        url
    }

    // pub fn attempt_connection(&self) -> Result<hyper::client::Response, hyper::Error> {
    //     let url = self.build_url("version");
    //     // Close connections after each GET.
    //     self.client.get(&url).header(hyper::header::Connection::close()).send()
    // }

    pub fn set_pagination(&mut self, pagination: Pagination) {
        self.pagination = Some(pagination);
    }

    pub fn get<T>(&self, query: &str) -> Result<T, serde_json::Error>
        where T: serde::Deserialize
    {
        // FIXME: Properly handle any errors. Use chain_error crate.

        let url = self.build_url(query);
        info!("url: {:?}", url);

        // Close connections after each GET.
        let mut res: hyper::client::Response = self.client
            .get(&url)
            .header(hyper::header::Connection::close())
            .send()
            .unwrap();
        info!("res.status: {:?}", res.status);
        debug!("res.headers: {:?}", res.headers);
        debug!("res.url: {:?}", res.url);

        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();
        debug!("body:\n{:?}", body);

        assert_eq!(res.status, hyper::status::StatusCode::Ok);

        serde_json::from_str(body.as_str())
    }

    // pub fn version(&self) -> Result<Version, serde_json::Error> {
    //     self.get("version")
    // }
    //
    // pub fn groups(&self) -> Result<Groups, serde_json::Error> {
    //     self.get("groups")
    // }

    pub fn projects(&self) -> ::projects::ProjectsLister {
        ::projects::ProjectsLister::new(&self)
    }

    pub fn groups(&mut self, listing: ::groups::Listing) -> Result<Groups, serde_json::Error> {
        let query = listing.build_query();
        // self.get(&query)
        unimplemented!();
    }

    pub fn owned_groups(&mut self) -> Result<Groups, serde_json::Error> {
        let query = ::groups::owned_groups::Listing::new().build_query();
        info!("query: {:?}", query);
        self.get(&query)
    }
}

// #[cfg(test)]
// mod tests {
//
// #[test]
// fn it_works() {
// }
// }
//
<|endoftext|>


<commit_before>use crate::cmp::Ordering;
use crate::time::Duration;

use core::hash::{Hash, Hasher};

pub use self::inner::{Instant, SystemTime, UNIX_EPOCH};
use crate::convert::TryInto;

const NSEC_PER_SEC: u64 = 1_000_000_000;

#[derive(Copy, Clone)]
struct Timespec {
    t: libc::timespec,
}

impl Timespec {
    const fn zero() -> Timespec {
        Timespec { t: libc::timespec { tv_sec: 0, tv_nsec: 0 } }
    }

    fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
        if self >= other {
            // NOTE(eddyb) two aspects of this `if`-`else` are required for LLVM
            // to optimize it into a branchless form (see also #75545):
            //
            // 1. `self.t.tv_sec - other.t.tv_sec` shows up as a common expression
            //    in both branches, i.e. the `else` must have its `- 1`
            //    subtraction after the common one, not interleaved with it
            //    (it used to be `self.t.tv_sec - 1 - other.t.tv_sec`)
            //
            // 2. the `Duration::new` call (or any other additional complexity)
            //    is outside of the `if`-`else`, not duplicated in both branches
            //
            // Ideally this code could be rearranged such that it more
            // directly expresses the lower-cost behavior we want from it.
            let (secs, nsec) = if self.t.tv_nsec >= other.t.tv_nsec {
                ((self.t.tv_sec - other.t.tv_sec) as u64, (self.t.tv_nsec - other.t.tv_nsec) as u32)
            } else {
                (
                    (self.t.tv_sec - other.t.tv_sec - 1) as u64,
                    self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) - other.t.tv_nsec as u32,
                )
            };

            Ok(Duration::new(secs, nsec))
        } else {
            match other.sub_timespec(self) {
                Ok(d) => Err(d),
                Err(d) => Ok(d),
            }
        }
    }

    fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
        let mut secs = other
            .as_secs()
            .try_into() // <- target type would be `libc::time_t`
            .ok()
            .and_then(|secs| self.t.tv_sec.checked_add(secs))?;

        // Nano calculations can't overflow because nanos are <1B which fit
        // in a u32.
        let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32;
        if nsec >= NSEC_PER_SEC as u32 {
            nsec -= NSEC_PER_SEC as u32;
            secs = secs.checked_add(1)?;
        }
        Some(Timespec { t: libc::timespec { tv_sec: secs, tv_nsec: nsec as _ } })
    }

    fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
        let mut secs = other
            .as_secs()
            .try_into() // <- target type would be `libc::time_t`
            .ok()
            .and_then(|secs| self.t.tv_sec.checked_sub(secs))?;

        // Similar to above, nanos can't overflow.
        let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32;
        if nsec < 0 {
            nsec += NSEC_PER_SEC as i32;
            secs = secs.checked_sub(1)?;
        }
        Some(Timespec { t: libc::timespec { tv_sec: secs, tv_nsec: nsec as _ } })
    }
}

impl PartialEq for Timespec {
    fn eq(&self, other: &Timespec) -> bool {
        self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec
    }
}

impl Eq for Timespec {}

impl PartialOrd for Timespec {
    fn partial_cmp(&self, other: &Timespec) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Timespec {
    fn cmp(&self, other: &Timespec) -> Ordering {
        let me = (self.t.tv_sec, self.t.tv_nsec);
        let other = (other.t.tv_sec, other.t.tv_nsec);
        me.cmp(&other)
    }
}

impl Hash for Timespec {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.t.tv_sec.hash(state);
        self.t.tv_nsec.hash(state);
    }
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
mod inner {
    use crate::fmt;
    use crate::sync::atomic::{AtomicU64, Ordering};
    use crate::sys::cvt;
    use crate::sys_common::mul_div_u64;
    use crate::time::Duration;

    use super::Timespec;
    use super::NSEC_PER_SEC;

    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
    pub struct Instant {
        t: u64,
    }

    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
    pub struct SystemTime {
        t: Timespec,
    }

    pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };

    #[repr(C)]
    #[derive(Copy, Clone)]
    struct mach_timebase_info {
        numer: u32,
        denom: u32,
    }
    type mach_timebase_info_t = *mut mach_timebase_info;
    type kern_return_t = libc::c_int;

    impl Instant {
        pub fn now() -> Instant {
            extern "C" {
                fn mach_absolute_time() -> u64;
            }
            Instant { t: unsafe { mach_absolute_time() } }
        }

        pub const fn zero() -> Instant {
            Instant { t: 0 }
        }

        pub fn actually_monotonic() -> bool {
            true
        }

        pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
            let diff = self.t.checked_sub(other.t)?;
            let info = info();
            let nanos = mul_div_u64(diff, info.numer as u64, info.denom as u64);
            Some(Duration::new(nanos / NSEC_PER_SEC, (nanos % NSEC_PER_SEC) as u32))
        }

        pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
            Some(Instant { t: self.t.checked_add(checked_dur2intervals(other)?)? })
        }

        pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
            Some(Instant { t: self.t.checked_sub(checked_dur2intervals(other)?)? })
        }
    }

    impl SystemTime {
        pub fn now() -> SystemTime {
            use crate::ptr;

            let mut s = libc::timeval { tv_sec: 0, tv_usec: 0 };
            cvt(unsafe { libc::gettimeofday(&mut s, ptr::null_mut()) }).unwrap();
            return SystemTime::from(s);
        }

        pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
            self.t.sub_timespec(&other.t)
        }

        pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
            Some(SystemTime { t: self.t.checked_add_duration(other)? })
        }

        pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
            Some(SystemTime { t: self.t.checked_sub_duration(other)? })
        }
    }

    impl From<libc::timeval> for SystemTime {
        fn from(t: libc::timeval) -> SystemTime {
            SystemTime::from(libc::timespec {
                tv_sec: t.tv_sec,
                tv_nsec: (t.tv_usec * 1000) as libc::c_long,
            })
        }
    }

    impl From<libc::timespec> for SystemTime {
        fn from(t: libc::timespec) -> SystemTime {
            SystemTime { t: Timespec { t } }
        }
    }

    impl fmt::Debug for SystemTime {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            f.debug_struct("SystemTime")
                .field("tv_sec", &self.t.t.tv_sec)
                .field("tv_nsec", &self.t.t.tv_nsec)
                .finish()
        }
    }

    fn checked_dur2intervals(dur: &Duration) -> Option<u64> {
        let nanos =
            dur.as_secs().checked_mul(NSEC_PER_SEC)?.checked_add(dur.subsec_nanos() as u64)?;
        let info = info();
        Some(mul_div_u64(nanos, info.denom as u64, info.numer as u64))
    }

    fn info() -> mach_timebase_info {
        // INFO_BITS conceptually is an `Option<mach_timebase_info>`. We can do
        // this in 64 bits because we know 0 is never a valid value for the
        // `denom` field.
        //
        // Encoding this as a single `AtomicU64` allows us to use `Relaxed`
        // operations, as we are only interested in in the effects on a single
        // memory location.
        static INFO_BITS: AtomicU64 = AtomicU64::new(0);

        // If a previous thread has initialized `INFO_BITS`, use it.
        let info_bits = INFO_BITS.load(Ordering::Relaxed);
        if info_bits != 0 {
            return info_from_bits(info_bits);
        }

        // ... otherwise learn for ourselves ...
        extern "C" {
            fn mach_timebase_info(info: mach_timebase_info_t) -> kern_return_t;
        }

        let mut info = info_from_bits(0);
        unsafe {
            mach_timebase_info(&mut info);
        }
        INFO_BITS.store(info_to_bits(info), Ordering::Relaxed);
        info
    }

    #[inline]
    fn info_to_bits(info: mach_timebase_info) -> u64 {
        ((info.denom as u64) << 32) | (info.numer as u64)
    }

    #[inline]
    fn info_from_bits(bits: u64) -> mach_timebase_info {
        mach_timebase_info { numer: bits as u32, denom: (bits >> 32) as u32 }
    }
}

#[cfg(not(any(target_os = "macos", target_os = "ios")))]
mod inner {
    use crate::fmt;
    use crate::sys::cvt;
    use crate::time::Duration;

    use super::Timespec;

    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
    pub struct Instant {
        t: Timespec,
    }

    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
    pub struct SystemTime {
        t: Timespec,
    }

    pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };

    impl Instant {
        pub fn now() -> Instant {
            Instant { t: now(libc::CLOCK_MONOTONIC) }
        }

        pub const fn zero() -> Instant {
            Instant { t: Timespec::zero() }
        }

        pub fn actually_monotonic() -> bool {
            (cfg!(target_os = "linux") && cfg!(target_arch = "x86_64"))
                || (cfg!(target_os = "linux") && cfg!(target_arch = "x86"))
                || cfg!(target_os = "fuchsia")
        }

        pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
            self.t.sub_timespec(&other.t).ok()
        }

        pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
            Some(Instant { t: self.t.checked_add_duration(other)? })
        }

        pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
            Some(Instant { t: self.t.checked_sub_duration(other)? })
        }
    }

    impl fmt::Debug for Instant {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            f.debug_struct("Instant")
                .field("tv_sec", &self.t.t.tv_sec)
                .field("tv_nsec", &self.t.t.tv_nsec)
                .finish()
        }
    }

    impl SystemTime {
        pub fn now() -> SystemTime {
            SystemTime { t: now(libc::CLOCK_REALTIME) }
        }

        pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
            self.t.sub_timespec(&other.t)
        }

        pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
            Some(SystemTime { t: self.t.checked_add_duration(other)? })
        }

        pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
            Some(SystemTime { t: self.t.checked_sub_duration(other)? })
        }
    }

    impl From<libc::timespec> for SystemTime {
        fn from(t: libc::timespec) -> SystemTime {
            SystemTime { t: Timespec { t } }
        }
    }

    impl fmt::Debug for SystemTime {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            f.debug_struct("SystemTime")
                .field("tv_sec", &self.t.t.tv_sec)
                .field("tv_nsec", &self.t.t.tv_nsec)
                .finish()
        }
    }

    #[cfg(not(target_os = "dragonfly"))]
    pub type clock_t = libc::c_int;
    #[cfg(target_os = "dragonfly")]
    pub type clock_t = libc::c_ulong;

    fn now(clock: clock_t) -> Timespec {
        let mut t = Timespec { t: libc::timespec { tv_sec: 0, tv_nsec: 0 } };
        cvt(unsafe { libc::clock_gettime(clock, &mut t.t) }).unwrap();
        t
    }
}
<commit_msg>Fix small typo in time comment<commit_after>use crate::cmp::Ordering;
use crate::time::Duration;

use core::hash::{Hash, Hasher};

pub use self::inner::{Instant, SystemTime, UNIX_EPOCH};
use crate::convert::TryInto;

const NSEC_PER_SEC: u64 = 1_000_000_000;

#[derive(Copy, Clone)]
struct Timespec {
    t: libc::timespec,
}

impl Timespec {
    const fn zero() -> Timespec {
        Timespec { t: libc::timespec { tv_sec: 0, tv_nsec: 0 } }
    }

    fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
        if self >= other {
            // NOTE(eddyb) two aspects of this `if`-`else` are required for LLVM
            // to optimize it into a branchless form (see also #75545):
            //
            // 1. `self.t.tv_sec - other.t.tv_sec` shows up as a common expression
            //    in both branches, i.e. the `else` must have its `- 1`
            //    subtraction after the common one, not interleaved with it
            //    (it used to be `self.t.tv_sec - 1 - other.t.tv_sec`)
            //
            // 2. the `Duration::new` call (or any other additional complexity)
            //    is outside of the `if`-`else`, not duplicated in both branches
            //
            // Ideally this code could be rearranged such that it more
            // directly expresses the lower-cost behavior we want from it.
            let (secs, nsec) = if self.t.tv_nsec >= other.t.tv_nsec {
                ((self.t.tv_sec - other.t.tv_sec) as u64, (self.t.tv_nsec - other.t.tv_nsec) as u32)
            } else {
                (
                    (self.t.tv_sec - other.t.tv_sec - 1) as u64,
                    self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) - other.t.tv_nsec as u32,
                )
            };

            Ok(Duration::new(secs, nsec))
        } else {
            match other.sub_timespec(self) {
                Ok(d) => Err(d),
                Err(d) => Ok(d),
            }
        }
    }

    fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
        let mut secs = other
            .as_secs()
            .try_into() // <- target type would be `libc::time_t`
            .ok()
            .and_then(|secs| self.t.tv_sec.checked_add(secs))?;

        // Nano calculations can't overflow because nanos are <1B which fit
        // in a u32.
        let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32;
        if nsec >= NSEC_PER_SEC as u32 {
            nsec -= NSEC_PER_SEC as u32;
            secs = secs.checked_add(1)?;
        }
        Some(Timespec { t: libc::timespec { tv_sec: secs, tv_nsec: nsec as _ } })
    }

    fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
        let mut secs = other
            .as_secs()
            .try_into() // <- target type would be `libc::time_t`
            .ok()
            .and_then(|secs| self.t.tv_sec.checked_sub(secs))?;

        // Similar to above, nanos can't overflow.
        let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32;
        if nsec < 0 {
            nsec += NSEC_PER_SEC as i32;
            secs = secs.checked_sub(1)?;
        }
        Some(Timespec { t: libc::timespec { tv_sec: secs, tv_nsec: nsec as _ } })
    }
}

impl PartialEq for Timespec {
    fn eq(&self, other: &Timespec) -> bool {
        self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec
    }
}

impl Eq for Timespec {}

impl PartialOrd for Timespec {
    fn partial_cmp(&self, other: &Timespec) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Timespec {
    fn cmp(&self, other: &Timespec) -> Ordering {
        let me = (self.t.tv_sec, self.t.tv_nsec);
        let other = (other.t.tv_sec, other.t.tv_nsec);
        me.cmp(&other)
    }
}

impl Hash for Timespec {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.t.tv_sec.hash(state);
        self.t.tv_nsec.hash(state);
    }
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
mod inner {
    use crate::fmt;
    use crate::sync::atomic::{AtomicU64, Ordering};
    use crate::sys::cvt;
    use crate::sys_common::mul_div_u64;
    use crate::time::Duration;

    use super::Timespec;
    use super::NSEC_PER_SEC;

    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
    pub struct Instant {
        t: u64,
    }

    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
    pub struct SystemTime {
        t: Timespec,
    }

    pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };

    #[repr(C)]
    #[derive(Copy, Clone)]
    struct mach_timebase_info {
        numer: u32,
        denom: u32,
    }
    type mach_timebase_info_t = *mut mach_timebase_info;
    type kern_return_t = libc::c_int;

    impl Instant {
        pub fn now() -> Instant {
            extern "C" {
                fn mach_absolute_time() -> u64;
            }
            Instant { t: unsafe { mach_absolute_time() } }
        }

        pub const fn zero() -> Instant {
            Instant { t: 0 }
        }

        pub fn actually_monotonic() -> bool {
            true
        }

        pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
            let diff = self.t.checked_sub(other.t)?;
            let info = info();
            let nanos = mul_div_u64(diff, info.numer as u64, info.denom as u64);
            Some(Duration::new(nanos / NSEC_PER_SEC, (nanos % NSEC_PER_SEC) as u32))
        }

        pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
            Some(Instant { t: self.t.checked_add(checked_dur2intervals(other)?)? })
        }

        pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
            Some(Instant { t: self.t.checked_sub(checked_dur2intervals(other)?)? })
        }
    }

    impl SystemTime {
        pub fn now() -> SystemTime {
            use crate::ptr;

            let mut s = libc::timeval { tv_sec: 0, tv_usec: 0 };
            cvt(unsafe { libc::gettimeofday(&mut s, ptr::null_mut()) }).unwrap();
            return SystemTime::from(s);
        }

        pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
            self.t.sub_timespec(&other.t)
        }

        pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
            Some(SystemTime { t: self.t.checked_add_duration(other)? })
        }

        pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
            Some(SystemTime { t: self.t.checked_sub_duration(other)? })
        }
    }

    impl From<libc::timeval> for SystemTime {
        fn from(t: libc::timeval) -> SystemTime {
            SystemTime::from(libc::timespec {
                tv_sec: t.tv_sec,
                tv_nsec: (t.tv_usec * 1000) as libc::c_long,
            })
        }
    }

    impl From<libc::timespec> for SystemTime {
        fn from(t: libc::timespec) -> SystemTime {
            SystemTime { t: Timespec { t } }
        }
    }

    impl fmt::Debug for SystemTime {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            f.debug_struct("SystemTime")
                .field("tv_sec", &self.t.t.tv_sec)
                .field("tv_nsec", &self.t.t.tv_nsec)
                .finish()
        }
    }

    fn checked_dur2intervals(dur: &Duration) -> Option<u64> {
        let nanos =
            dur.as_secs().checked_mul(NSEC_PER_SEC)?.checked_add(dur.subsec_nanos() as u64)?;
        let info = info();
        Some(mul_div_u64(nanos, info.denom as u64, info.numer as u64))
    }

    fn info() -> mach_timebase_info {
        // INFO_BITS conceptually is an `Option<mach_timebase_info>`. We can do
        // this in 64 bits because we know 0 is never a valid value for the
        // `denom` field.
        //
        // Encoding this as a single `AtomicU64` allows us to use `Relaxed`
        // operations, as we are only interested in the effects on a single
        // memory location.
        static INFO_BITS: AtomicU64 = AtomicU64::new(0);

        // If a previous thread has initialized `INFO_BITS`, use it.
        let info_bits = INFO_BITS.load(Ordering::Relaxed);
        if info_bits != 0 {
            return info_from_bits(info_bits);
        }

        // ... otherwise learn for ourselves ...
        extern "C" {
            fn mach_timebase_info(info: mach_timebase_info_t) -> kern_return_t;
        }

        let mut info = info_from_bits(0);
        unsafe {
            mach_timebase_info(&mut info);
        }
        INFO_BITS.store(info_to_bits(info), Ordering::Relaxed);
        info
    }

    #[inline]
    fn info_to_bits(info: mach_timebase_info) -> u64 {
        ((info.denom as u64) << 32) | (info.numer as u64)
    }

    #[inline]
    fn info_from_bits(bits: u64) -> mach_timebase_info {
        mach_timebase_info { numer: bits as u32, denom: (bits >> 32) as u32 }
    }
}

#[cfg(not(any(target_os = "macos", target_os = "ios")))]
mod inner {
    use crate::fmt;
    use crate::sys::cvt;
    use crate::time::Duration;

    use super::Timespec;

    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
    pub struct Instant {
        t: Timespec,
    }

    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
    pub struct SystemTime {
        t: Timespec,
    }

    pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };

    impl Instant {
        pub fn now() -> Instant {
            Instant { t: now(libc::CLOCK_MONOTONIC) }
        }

        pub const fn zero() -> Instant {
            Instant { t: Timespec::zero() }
        }

        pub fn actually_monotonic() -> bool {
            (cfg!(target_os = "linux") && cfg!(target_arch = "x86_64"))
                || (cfg!(target_os = "linux") && cfg!(target_arch = "x86"))
                || cfg!(target_os = "fuchsia")
        }

        pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
            self.t.sub_timespec(&other.t).ok()
        }

        pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
            Some(Instant { t: self.t.checked_add_duration(other)? })
        }

        pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
            Some(Instant { t: self.t.checked_sub_duration(other)? })
        }
    }

    impl fmt::Debug for Instant {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            f.debug_struct("Instant")
                .field("tv_sec", &self.t.t.tv_sec)
                .field("tv_nsec", &self.t.t.tv_nsec)
                .finish()
        }
    }

    impl SystemTime {
        pub fn now() -> SystemTime {
            SystemTime { t: now(libc::CLOCK_REALTIME) }
        }

        pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
            self.t.sub_timespec(&other.t)
        }

        pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
            Some(SystemTime { t: self.t.checked_add_duration(other)? })
        }

        pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
            Some(SystemTime { t: self.t.checked_sub_duration(other)? })
        }
    }

    impl From<libc::timespec> for SystemTime {
        fn from(t: libc::timespec) -> SystemTime {
            SystemTime { t: Timespec { t } }
        }
    }

    impl fmt::Debug for SystemTime {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            f.debug_struct("SystemTime")
                .field("tv_sec", &self.t.t.tv_sec)
                .field("tv_nsec", &self.t.t.tv_nsec)
                .finish()
        }
    }

    #[cfg(not(target_os = "dragonfly"))]
    pub type clock_t = libc::c_int;
    #[cfg(target_os = "dragonfly")]
    pub type clock_t = libc::c_ulong;

    fn now(clock: clock_t) -> Timespec {
        let mut t = Timespec { t: libc::timespec { tv_sec: 0, tv_nsec: 0 } };
        cvt(unsafe { libc::clock_gettime(clock, &mut t.t) }).unwrap();
        t
    }
}
<|endoftext|>


<commit_before>use js::value::{Value, ResultValue, VString, VUndefined, to_value};
use url::{encode, decode, encode_component, decode_component};
use std::gc::Gc;

/// Encode a URI
pub fn encode_uri(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(if args.len() == 0 {
		VUndefined
	} else {
		VString(encode(args.get(0).borrow().to_str()))
	}))
}
/// Encode a URI component
pub fn encode_uri_component(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(if args.len() == 0 {
		VUndefined
	} else {
		VString(encode_component(args.get(0).borrow().to_str()))
	}))
}
/// Decode a URI
pub fn decode_uri(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(if args.len() == 0 {
		VUndefined
	} else {
		VString(decode(args.get(0).borrow().to_str()))
	}))
}
/// Decode a URI component
pub fn decode_uri_component(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(if args.len() == 0 {
		VUndefined
	} else {
		VString(decode_component(args.get(0).borrow().to_str()))
	}))
}
/// Initialise the URI functions on a global object
pub fn init(obj:Value) {
	obj.borrow().set_field(~"encodeURI", to_value(encode_uri));
	obj.borrow().set_field(~"encodeURIComponent", to_value(encode_uri_component));
	obj.borrow().set_field(~"decodeURI", to_value(decode_uri));
	obj.borrow().set_field(~"decodeURIComponent", to_value(decode_uri_component));
}<commit_msg>Add info about RFC to JS URI<commit_after>use js::value::{Value, ResultValue, VString, VUndefined, to_value};
use url::{encode, decode, encode_component, decode_component};
use std::gc::Gc;

/// Encode a URI
pub fn encode_uri(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(if args.len() == 0 {
		VUndefined
	} else {
		VString(encode(args.get(0).borrow().to_str()))
	}))
}
/// Encode a URI component
/// Rust uses RFC 3986, but JS doesn't, this will need a fix
pub fn encode_uri_component(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(if args.len() == 0 {
		VUndefined
	} else {
		VString(encode_component(args.get(0).borrow().to_str()))
	}))
}
/// Decode a URI
pub fn decode_uri(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(if args.len() == 0 {
		VUndefined
	} else {
		VString(decode(args.get(0).borrow().to_str()))
	}))
}
/// Decode a URI component
/// Rust uses RFC 3986, but JS doesn't, this will need a fix
pub fn decode_uri_component(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(if args.len() == 0 {
		VUndefined
	} else {
		VString(decode_component(args.get(0).borrow().to_str()))
	}))
}
/// Initialise the URI functions on a global object
pub fn init(obj:Value) {
	obj.borrow().set_field(~"encodeURI", to_value(encode_uri));
	obj.borrow().set_field(~"encodeURIComponent", to_value(encode_uri_component));
	obj.borrow().set_field(~"decodeURI", to_value(decode_uri));
	obj.borrow().set_field(~"decodeURIComponent", to_value(decode_uri_component));
}<|endoftext|>