<commit_before>//! Implementation of the install aspects of the compiler.
//!
//! This module is responsible for installing the standard library,
//! compiler, and documentation.

use std::env;
use std::fs;
use std::path::{Component, Path, PathBuf};
use std::process::Command;

use build_helper::t;

use crate::dist::{self, pkgname, sanitize_sh, tmpdir};
use crate::Compiler;

use crate::builder::{Builder, RunConfig, ShouldRun, Step};
use crate::cache::Interned;
use crate::config::Config;

pub fn install_docs(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "docs", "rust-docs", stage, Some(host));
}

pub fn install_std(builder: &Builder<'_>, stage: u32, target: Interned<String>) {
    install_sh(builder, "std", "rust-std", stage, Some(target));
}

pub fn install_cargo(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "cargo", "cargo", stage, Some(host));
}

pub fn install_rls(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "rls", "rls", stage, Some(host));
}
pub fn install_clippy(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "clippy", "clippy", stage, Some(host));
}
pub fn install_miri(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "miri", "miri", stage, Some(host));
}

pub fn install_rustfmt(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "rustfmt", "rustfmt", stage, Some(host));
}

pub fn install_analysis(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "analysis", "rust-analysis", stage, Some(host));
}

pub fn install_src(builder: &Builder<'_>, stage: u32) {
    install_sh(builder, "src", "rust-src", stage, None);
}
pub fn install_rustc(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "rustc", "rustc", stage, Some(host));
}

fn install_sh(
    builder: &Builder<'_>,
    package: &str,
    name: &str,
    stage: u32,
    host: Option<Interned<String>>,
) {
    builder.info(&format!("Install {} stage{} ({:?})", package, stage, host));

    let prefix_default = PathBuf::from("/usr/local");
    let sysconfdir_default = PathBuf::from("/etc");
    let datadir_default = PathBuf::from("share");
    let docdir_default = datadir_default.join("doc/rust");
    let bindir_default = PathBuf::from("bin");
    let libdir_default = PathBuf::from("lib");
    let mandir_default = datadir_default.join("man");
    let prefix = builder.config.prefix.as_ref().map_or(prefix_default, |p| {
        fs::canonicalize(p).unwrap_or_else(|_| panic!("could not canonicalize {}", p.display()))
    });
    let sysconfdir = builder.config.sysconfdir.as_ref().unwrap_or(&sysconfdir_default);
    let datadir = builder.config.datadir.as_ref().unwrap_or(&datadir_default);
    let docdir = builder.config.docdir.as_ref().unwrap_or(&docdir_default);
    let bindir = builder.config.bindir.as_ref().unwrap_or(&bindir_default);
    let libdir = builder.config.libdir.as_ref().unwrap_or(&libdir_default);
    let mandir = builder.config.mandir.as_ref().unwrap_or(&mandir_default);

    let sysconfdir = prefix.join(sysconfdir);
    let datadir = prefix.join(datadir);
    let docdir = prefix.join(docdir);
    let bindir = prefix.join(bindir);
    let libdir = prefix.join(libdir);
    let mandir = prefix.join(mandir);

    let destdir = env::var_os("DESTDIR").map(PathBuf::from);

    let prefix = add_destdir(&prefix, &destdir);
    let sysconfdir = add_destdir(&sysconfdir, &destdir);
    let datadir = add_destdir(&datadir, &destdir);
    let docdir = add_destdir(&docdir, &destdir);
    let bindir = add_destdir(&bindir, &destdir);
    let libdir = add_destdir(&libdir, &destdir);
    let mandir = add_destdir(&mandir, &destdir);

    let empty_dir = builder.out.join("tmp/empty_dir");

    t!(fs::create_dir_all(&empty_dir));
    let package_name = if let Some(host) = host {
        format!("{}-{}", pkgname(builder, name), host)
    } else {
        pkgname(builder, name)
    };

    let mut cmd = Command::new("sh");
    cmd.current_dir(&empty_dir)
        .arg(sanitize_sh(&tmpdir(builder).join(&package_name).join("install.sh")))
        .arg(format!("--prefix={}", sanitize_sh(&prefix)))
        .arg(format!("--sysconfdir={}", sanitize_sh(&sysconfdir)))
        .arg(format!("--datadir={}", sanitize_sh(&datadir)))
        .arg(format!("--docdir={}", sanitize_sh(&docdir)))
        .arg(format!("--bindir={}", sanitize_sh(&bindir)))
        .arg(format!("--libdir={}", sanitize_sh(&libdir)))
        .arg(format!("--mandir={}", sanitize_sh(&mandir)))
        .arg("--disable-ldconfig");
    builder.run(&mut cmd);
    t!(fs::remove_dir_all(&empty_dir));
}

fn add_destdir(path: &Path, destdir: &Option<PathBuf>) -> PathBuf {
    let mut ret = match *destdir {
        Some(ref dest) => dest.clone(),
        None => return path.to_path_buf(),
    };
    for part in path.components() {
        match part {
            Component::Normal(s) => ret.push(s),
            _ => {}
        }
    }
    ret
}

macro_rules! install {
    (($sel:ident, $builder:ident, $_config:ident),
       $($name:ident,
       $path:expr,
       $default_cond:expr,
       only_hosts: $only_hosts:expr,
       $run_item:block $(, $c:ident)*;)+) => {
        $(
            #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
        pub struct $name {
            pub compiler: Compiler,
            pub target: Interned<String>,
        }

        impl $name {
            #[allow(dead_code)]
            fn should_build(config: &Config) -> bool {
                config.extended && config.tools.as_ref()
                    .map_or(true, |t| t.contains($path))
            }

            #[allow(dead_code)]
            fn should_install(builder: &Builder<'_>) -> bool {
                builder.config.tools.as_ref().map_or(false, |t| t.contains($path))
            }
        }

        impl Step for $name {
            type Output = ();
            const DEFAULT: bool = true;
            const ONLY_HOSTS: bool = $only_hosts;
            $(const $c: bool = true;)*

            fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
                let $_config = &run.builder.config;
                run.path($path).default_condition($default_cond)
            }

            fn make_run(run: RunConfig<'_>) {
                run.builder.ensure($name {
                    compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
                    target: run.target,
                });
            }

            fn run($sel, $builder: &Builder<'_>) {
                $run_item
            }
        })+
    }
}

install!((self, builder, _config),
    Docs, "src/doc", _config.docs, only_hosts: false, {
        builder.ensure(dist::Docs { host: self.target });
        install_docs(builder, self.compiler.stage, self.target);
    };
    Std, "src/libstd", true, only_hosts: true, {
        for target in &builder.targets {
            builder.ensure(dist::Std {
                compiler: self.compiler,
                target: *target
            });
            install_std(builder, self.compiler.stage, *target);
        }
    };
    Cargo, "cargo", Self::should_build(_config), only_hosts: true, {
        builder.ensure(dist::Cargo { compiler: self.compiler, target: self.target });
        install_cargo(builder, self.compiler.stage, self.target);
    };
    Rls, "rls", Self::should_build(_config), only_hosts: true, {
        if builder.ensure(dist::Rls { compiler: self.compiler, target: self.target }).is_some() ||
            Self::should_install(builder) {
            install_rls(builder, self.compiler.stage, self.target);
        } else {
            builder.info(
                &format!("skipping Install RLS stage{} ({})", self.compiler.stage, self.target),
            );
        }
    };
    Clippy, "clippy", Self::should_build(_config), only_hosts: true, {
        if builder.ensure(dist::Clippy {
            compiler: self.compiler,
            target: self.target,
        }).is_some() || Self::should_install(builder) {
            install_clippy(builder, self.compiler.stage, self.target);
        } else {
            builder.info(
                &format!("skipping Install clippy stage{} ({})", self.compiler.stage, self.target),
            );
        }
    };
    Miri, "miri", Self::should_build(_config), only_hosts: true, {
        if builder.ensure(dist::Miri { compiler: self.compiler, target: self.target }).is_some() ||
            Self::should_install(builder) {
            install_miri(builder, self.compiler.stage, self.target);
        } else {
            builder.info(
                &format!("skipping Install miri stage{} ({})", self.compiler.stage, self.target),
            );
        }
    };
    Rustfmt, "rustfmt", Self::should_build(_config), only_hosts: true, {
        if builder.ensure(dist::Rustfmt {
            compiler: self.compiler,
            target: self.target
        }).is_some() || Self::should_install(builder) {
            install_rustfmt(builder, self.compiler.stage, self.target);
        } else {
            builder.info(
                &format!("skipping Install Rustfmt stage{} ({})", self.compiler.stage, self.target),
            );
        }
    };
    Analysis, "analysis", Self::should_build(_config), only_hosts: false, {
        builder.ensure(dist::Analysis {
            compiler: self.compiler,
            target: self.target
        });
        install_analysis(builder, self.compiler.stage, self.target);
    };
    Rustc, "src/librustc", true, only_hosts: true, {
        builder.ensure(dist::Rustc {
            compiler: self.compiler,
        });
        install_rustc(builder, self.compiler.stage, self.target);
    };
);

#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Src {
    pub stage: u32,
}

impl Step for Src {
    type Output = ();
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;

    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
        let config = &run.builder.config;
        let cond = config.extended && config.tools.as_ref().map_or(true, |t| t.contains("src"));
        run.path("src").default_condition(cond)
    }

    fn make_run(run: RunConfig<'_>) {
        run.builder.ensure(Src { stage: run.builder.top_stage });
    }

    fn run(self, builder: &Builder<'_>) {
        builder.ensure(dist::Src);
        install_src(builder, self.stage);
    }
}
<commit_msg>Fix x.py install<commit_after>//! Implementation of the install aspects of the compiler.
//!
//! This module is responsible for installing the standard library,
//! compiler, and documentation.

use std::env;
use std::fs;
use std::path::{Component, Path, PathBuf};
use std::process::Command;

use build_helper::t;

use crate::dist::{self, pkgname, sanitize_sh, tmpdir};
use crate::Compiler;

use crate::builder::{Builder, RunConfig, ShouldRun, Step};
use crate::cache::Interned;
use crate::config::Config;

pub fn install_docs(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "docs", "rust-docs", stage, Some(host));
}

pub fn install_std(builder: &Builder<'_>, stage: u32, target: Interned<String>) {
    install_sh(builder, "std", "rust-std", stage, Some(target));
}

pub fn install_cargo(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "cargo", "cargo", stage, Some(host));
}

pub fn install_rls(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "rls", "rls", stage, Some(host));
}
pub fn install_clippy(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "clippy", "clippy", stage, Some(host));
}
pub fn install_miri(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "miri", "miri", stage, Some(host));
}

pub fn install_rustfmt(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "rustfmt", "rustfmt", stage, Some(host));
}

pub fn install_analysis(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "analysis", "rust-analysis", stage, Some(host));
}

pub fn install_src(builder: &Builder<'_>, stage: u32) {
    install_sh(builder, "src", "rust-src", stage, None);
}
pub fn install_rustc(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "rustc", "rustc", stage, Some(host));
}

fn install_sh(
    builder: &Builder<'_>,
    package: &str,
    name: &str,
    stage: u32,
    host: Option<Interned<String>>,
) {
    builder.info(&format!("Install {} stage{} ({:?})", package, stage, host));

    let prefix_default = PathBuf::from("/usr/local");
    let sysconfdir_default = PathBuf::from("/etc");
    let datadir_default = PathBuf::from("share");
    let docdir_default = datadir_default.join("doc/rust");
    let bindir_default = PathBuf::from("bin");
    let libdir_default = PathBuf::from("lib");
    let mandir_default = datadir_default.join("man");
    let prefix = builder.config.prefix.as_ref().map_or(prefix_default, |p| {
        fs::canonicalize(p).unwrap_or_else(|_| panic!("could not canonicalize {}", p.display()))
    });
    let sysconfdir = builder.config.sysconfdir.as_ref().unwrap_or(&sysconfdir_default);
    let datadir = builder.config.datadir.as_ref().unwrap_or(&datadir_default);
    let docdir = builder.config.docdir.as_ref().unwrap_or(&docdir_default);
    let bindir = builder.config.bindir.as_ref().unwrap_or(&bindir_default);
    let libdir = builder.config.libdir.as_ref().unwrap_or(&libdir_default);
    let mandir = builder.config.mandir.as_ref().unwrap_or(&mandir_default);

    let sysconfdir = prefix.join(sysconfdir);
    let datadir = prefix.join(datadir);
    let docdir = prefix.join(docdir);
    let bindir = prefix.join(bindir);
    let libdir = prefix.join(libdir);
    let mandir = prefix.join(mandir);

    let destdir = env::var_os("DESTDIR").map(PathBuf::from);

    let prefix = add_destdir(&prefix, &destdir);
    let sysconfdir = add_destdir(&sysconfdir, &destdir);
    let datadir = add_destdir(&datadir, &destdir);
    let docdir = add_destdir(&docdir, &destdir);
    let bindir = add_destdir(&bindir, &destdir);
    let libdir = add_destdir(&libdir, &destdir);
    let mandir = add_destdir(&mandir, &destdir);

    let empty_dir = builder.out.join("tmp/empty_dir");

    t!(fs::create_dir_all(&empty_dir));
    let package_name = if let Some(host) = host {
        format!("{}-{}", pkgname(builder, name), host)
    } else {
        pkgname(builder, name)
    };

    let mut cmd = Command::new("sh");
    cmd.current_dir(&empty_dir)
        .arg(sanitize_sh(&tmpdir(builder).join(&package_name).join("install.sh")))
        .arg(format!("--prefix={}", sanitize_sh(&prefix)))
        .arg(format!("--sysconfdir={}", sanitize_sh(&sysconfdir)))
        .arg(format!("--datadir={}", sanitize_sh(&datadir)))
        .arg(format!("--docdir={}", sanitize_sh(&docdir)))
        .arg(format!("--bindir={}", sanitize_sh(&bindir)))
        .arg(format!("--libdir={}", sanitize_sh(&libdir)))
        .arg(format!("--mandir={}", sanitize_sh(&mandir)))
        .arg("--disable-ldconfig");
    builder.run(&mut cmd);
    t!(fs::remove_dir_all(&empty_dir));
}

fn add_destdir(path: &Path, destdir: &Option<PathBuf>) -> PathBuf {
    let mut ret = match *destdir {
        Some(ref dest) => dest.clone(),
        None => return path.to_path_buf(),
    };
    for part in path.components() {
        match part {
            Component::Normal(s) => ret.push(s),
            _ => {}
        }
    }
    ret
}

macro_rules! install {
    (($sel:ident, $builder:ident, $_config:ident),
       $($name:ident,
       $path:expr,
       $default_cond:expr,
       only_hosts: $only_hosts:expr,
       $run_item:block $(, $c:ident)*;)+) => {
        $(
            #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
        pub struct $name {
            pub compiler: Compiler,
            pub target: Interned<String>,
        }

        impl $name {
            #[allow(dead_code)]
            fn should_build(config: &Config) -> bool {
                config.extended && config.tools.as_ref()
                    .map_or(true, |t| t.contains($path))
            }

            #[allow(dead_code)]
            fn should_install(builder: &Builder<'_>) -> bool {
                builder.config.tools.as_ref().map_or(false, |t| t.contains($path))
            }
        }

        impl Step for $name {
            type Output = ();
            const DEFAULT: bool = true;
            const ONLY_HOSTS: bool = $only_hosts;
            $(const $c: bool = true;)*

            fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
                let $_config = &run.builder.config;
                run.path($path).default_condition($default_cond)
            }

            fn make_run(run: RunConfig<'_>) {
                run.builder.ensure($name {
                    compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
                    target: run.target,
                });
            }

            fn run($sel, $builder: &Builder<'_>) {
                $run_item
            }
        })+
    }
}

install!((self, builder, _config),
    Docs, "src/doc", _config.docs, only_hosts: false, {
        builder.ensure(dist::Docs { host: self.target });
        install_docs(builder, self.compiler.stage, self.target);
    };
    Std, "src/libstd", true, only_hosts: true, {
        for target in &builder.targets {
            builder.ensure(dist::Std {
                compiler: self.compiler,
                target: *target
            });
            install_std(builder, self.compiler.stage, *target);
        }
    };
    Cargo, "cargo", Self::should_build(_config), only_hosts: true, {
        builder.ensure(dist::Cargo { compiler: self.compiler, target: self.target });
        install_cargo(builder, self.compiler.stage, self.target);
    };
    Rls, "rls", Self::should_build(_config), only_hosts: true, {
        if builder.ensure(dist::Rls { compiler: self.compiler, target: self.target }).is_some() ||
            Self::should_install(builder) {
            install_rls(builder, self.compiler.stage, self.target);
        } else {
            builder.info(
                &format!("skipping Install RLS stage{} ({})", self.compiler.stage, self.target),
            );
        }
    };
    Clippy, "clippy", Self::should_build(_config), only_hosts: true, {
        if builder.ensure(dist::Clippy {
            compiler: self.compiler,
            target: self.target,
        }).is_some() || Self::should_install(builder) {
            install_clippy(builder, self.compiler.stage, self.target);
        } else {
            builder.info(
                &format!("skipping Install clippy stage{} ({})", self.compiler.stage, self.target),
            );
        }
    };
    Miri, "miri", Self::should_build(_config), only_hosts: true, {
        if builder.ensure(dist::Miri { compiler: self.compiler, target: self.target }).is_some() ||
            Self::should_install(builder) {
            install_miri(builder, self.compiler.stage, self.target);
        } else {
            builder.info(
                &format!("skipping Install miri stage{} ({})", self.compiler.stage, self.target),
            );
        }
    };
    Rustfmt, "rustfmt", Self::should_build(_config), only_hosts: true, {
        if builder.ensure(dist::Rustfmt {
            compiler: self.compiler,
            target: self.target
        }).is_some() || Self::should_install(builder) {
            install_rustfmt(builder, self.compiler.stage, self.target);
        } else {
            builder.info(
                &format!("skipping Install Rustfmt stage{} ({})", self.compiler.stage, self.target),
            );
        }
    };
    Analysis, "analysis", Self::should_build(_config), only_hosts: false, {
        builder.ensure(dist::Analysis {
            // Find the actual compiler (handling the full bootstrap option) which
            // produced the save-analysis data because that data isn't copied
            // through the sysroot uplifting.
            compiler: builder.compiler_for(builder.top_stage, builder.config.build, self.target),
            target: self.target
        });
        install_analysis(builder, self.compiler.stage, self.target);
    };
    Rustc, "src/librustc", true, only_hosts: true, {
        builder.ensure(dist::Rustc {
            compiler: self.compiler,
        });
        install_rustc(builder, self.compiler.stage, self.target);
    };
);

#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Src {
    pub stage: u32,
}

impl Step for Src {
    type Output = ();
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;

    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
        let config = &run.builder.config;
        let cond = config.extended && config.tools.as_ref().map_or(true, |t| t.contains("src"));
        run.path("src").default_condition(cond)
    }

    fn make_run(run: RunConfig<'_>) {
        run.builder.ensure(Src { stage: run.builder.top_stage });
    }

    fn run(self, builder: &Builder<'_>) {
        builder.ensure(dist::Src);
        install_src(builder, self.stage);
    }
}
<|endoftext|>


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

#![allow(non_snake_case, non_camel_case_types, non_upper_case_globals)]

extern crate core_foundation_sys;
extern crate libc;

use consts::{FIDO_USAGE_U2FHID, FIDO_USAGE_PAGE};
use core_foundation_sys::base::*;
use core_foundation_sys::dictionary::*;
use core_foundation_sys::runloop::*;
use core_foundation_sys::string::*;
use core_foundation::dictionary::*;
use core_foundation::string::*;
use core_foundation::number::*;
use std::os::raw::c_void;
use std::ops::Deref;

type IOOptionBits = u32;

pub type IOReturn = libc::c_int;

pub type IOHIDManagerRef = *mut __IOHIDManager;
pub type IOHIDManagerOptions = IOOptionBits;

pub type IOHIDDeviceCallback = extern "C" fn(
    context: *mut c_void,
    result: IOReturn,
    sender: *mut c_void,
    device: IOHIDDeviceRef,
);

pub type IOHIDReportType = IOOptionBits;
pub type IOHIDReportCallback = extern "C" fn(
    context: *mut c_void,
    result: IOReturn,
    sender: IOHIDDeviceRef,
    report_type: IOHIDReportType,
    report_id: u32,
    report: *mut u8,
    report_len: CFIndex,
);

pub const kIOHIDManagerOptionNone: IOHIDManagerOptions = 0;

pub const kIOHIDReportTypeOutput: IOHIDReportType = 1;

#[repr(C)]
pub struct __IOHIDManager {
    __private: c_void,
}

#[repr(C)]
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub struct IOHIDDeviceRef(*const c_void);

unsafe impl Send for IOHIDDeviceRef {}
unsafe impl Sync for IOHIDDeviceRef {}

pub struct SendableRunLoop(CFRunLoopRef);

impl SendableRunLoop {
    pub fn new(runloop: CFRunLoopRef) -> Self {
        // Keep the CFRunLoop alive for as long as we are.
        unsafe { CFRetain(runloop as *mut c_void) };

        SendableRunLoop(runloop)
    }
}

unsafe impl Send for SendableRunLoop {}

impl Deref for SendableRunLoop {
    type Target = CFRunLoopRef;

    fn deref(&self) -> &CFRunLoopRef {
        &self.0
    }
}

impl Drop for SendableRunLoop {
    fn drop(&mut self) {
        unsafe { CFRelease(self.0 as *mut c_void) };
    }
}

#[repr(C)]
pub struct CFRunLoopObserverContext {
    pub version: CFIndex,
    pub info: *mut c_void,
    pub retain: Option<extern "C" fn(info: *const c_void) -> *const c_void>,
    pub release: Option<extern "C" fn(info: *const c_void)>,
    pub copyDescription: Option<extern "C" fn(info: *const c_void) -> CFStringRef>,
}

impl CFRunLoopObserverContext {
    pub fn new(context: *mut c_void) -> Self {
        Self {
            version: 0 as CFIndex,
            info: context,
            retain: None,
            release: None,
            copyDescription: None,
        }
    }
}

pub struct CFRunLoopEntryObserver {
    observer: CFRunLoopObserverRef,
    // Keep alive until the observer goes away.
    context_ptr: *mut CFRunLoopObserverContext,
}

impl CFRunLoopEntryObserver {
    pub fn new(callback: CFRunLoopObserverCallBack, context: *mut c_void) -> Self {
        let context = CFRunLoopObserverContext::new(context);
        let context_ptr = Box::into_raw(Box::new(context));

        let observer = unsafe {
            CFRunLoopObserverCreate(
                kCFAllocatorDefault,
                kCFRunLoopEntry,
                false as Boolean,
                0,
                callback,
                context_ptr,
            )
        };

        Self {
            observer,
            context_ptr,
        }
    }

    pub fn add_to_current_runloop(&self) {
        unsafe {
            CFRunLoopAddObserver(CFRunLoopGetCurrent(), self.observer, kCFRunLoopDefaultMode)
        };
    }
}

impl Drop for CFRunLoopEntryObserver {
    fn drop(&mut self) {
        unsafe {
            CFRelease(self.observer as *mut c_void);

            // Drop the CFRunLoopObserverContext.
            let _ = Box::from_raw(self.context_ptr);
        };
    }
}

pub struct IOHIDDeviceMatcher {
    pub dict: CFDictionary<CFString, CFNumber>,
}

impl IOHIDDeviceMatcher {
    pub fn new() -> Self {
        let dict = CFDictionary::<CFString, CFNumber>::from_CFType_pairs(&[
            (
                CFString::from_static_string("DeviceUsage"),
                CFNumber::from(FIDO_USAGE_U2FHID as i32),
            ),
            (
                CFString::from_static_string("DeviceUsagePage"),
                CFNumber::from(FIDO_USAGE_PAGE as i32),
            ),
            ]);
        Self { dict }
    }
}

#[link(name = "IOKit", kind = "framework")]
extern "C" {
    // CFRunLoop
    pub fn CFRunLoopObserverCreate(
        allocator: CFAllocatorRef,
        activities: CFOptionFlags,
        repeats: Boolean,
        order: CFIndex,
        callout: CFRunLoopObserverCallBack,
        context: *mut CFRunLoopObserverContext,
    ) -> CFRunLoopObserverRef;

    // IOHIDManager
    pub fn IOHIDManagerCreate(
        allocator: CFAllocatorRef,
        options: IOHIDManagerOptions,
    ) -> IOHIDManagerRef;
    pub fn IOHIDManagerSetDeviceMatching(manager: IOHIDManagerRef, matching: CFDictionaryRef);
    pub fn IOHIDManagerRegisterDeviceMatchingCallback(
        manager: IOHIDManagerRef,
        callback: IOHIDDeviceCallback,
        context: *mut c_void,
    );
    pub fn IOHIDManagerRegisterDeviceRemovalCallback(
        manager: IOHIDManagerRef,
        callback: IOHIDDeviceCallback,
        context: *mut c_void,
    );
    pub fn IOHIDManagerRegisterInputReportCallback(
        manager: IOHIDManagerRef,
        callback: IOHIDReportCallback,
        context: *mut c_void,
    );
    pub fn IOHIDManagerOpen(manager: IOHIDManagerRef, options: IOHIDManagerOptions) -> IOReturn;
    pub fn IOHIDManagerClose(manager: IOHIDManagerRef, options: IOHIDManagerOptions) -> IOReturn;
    pub fn IOHIDManagerScheduleWithRunLoop(
        manager: IOHIDManagerRef,
        runLoop: CFRunLoopRef,
        runLoopMode: CFStringRef,
    );

    // IOHIDDevice
    pub fn IOHIDDeviceSetReport(
        device: IOHIDDeviceRef,
        reportType: IOHIDReportType,
        reportID: CFIndex,
        report: *const u8,
        reportLength: CFIndex,
    ) -> IOReturn;
}

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use super::*;
    use core_foundation_sys::base::*;
    use core_foundation_sys::runloop::*;
    use std::os::raw::c_void;
    use std::ptr;
    use std::sync::mpsc::{channel, Sender};
    use std::thread;

    extern "C" fn observe(_: CFRunLoopObserverRef, _: CFRunLoopActivity, context: *mut c_void) {
        let tx: &Sender<SendableRunLoop> = unsafe { &*(context as *mut _) };

        // Send the current runloop to the receiver to unblock it.
        let _ = tx.send(SendableRunLoop::new(unsafe { CFRunLoopGetCurrent() }));
    }

    #[test]
    fn test_sendable_runloop() {
        let (tx, rx) = channel();

        let thread = thread::spawn(move || {
            // Send the runloop to the owning thread.
            let context = &tx as *const _ as *mut c_void;
            let obs = CFRunLoopEntryObserver::new(observe, context);
            obs.add_to_current_runloop();

            unsafe {
                // We need some source for the runloop to run.
                let manager = IOHIDManagerCreate(kCFAllocatorDefault, 0);
                assert!(!manager.is_null());

                IOHIDManagerScheduleWithRunLoop(
                    manager,
                    CFRunLoopGetCurrent(),
                    kCFRunLoopDefaultMode,
                );
                IOHIDManagerSetDeviceMatching(manager, ptr::null_mut());

                let rv = IOHIDManagerOpen(manager, 0);
                assert_eq!(rv, 0);

                // This will run until `CFRunLoopStop()` is called.
                CFRunLoopRun();

                let rv = IOHIDManagerClose(manager, 0);
                assert_eq!(rv, 0);

                CFRelease(manager as *mut c_void);
            }
        });

        // Block until we enter the CFRunLoop.
        let runloop: SendableRunLoop = rx.recv().expect("failed to receive runloop");

        // Stop the runloop.
        unsafe { CFRunLoopStop(*runloop) };

        // Stop the thread.
        thread.join().expect("failed to join the thread");

        // Try to stop the runloop again (without crashing).
        unsafe { CFRunLoopStop(*runloop) };
    }
}
<commit_msg>Remove unused imports<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![allow(non_snake_case, non_camel_case_types, non_upper_case_globals)]

extern crate core_foundation_sys;
extern crate libc;

use consts::{FIDO_USAGE_U2FHID, FIDO_USAGE_PAGE};
use core_foundation_sys::base::*;
use core_foundation_sys::dictionary::*;
use core_foundation_sys::runloop::*;
use core_foundation_sys::string::*;
use core_foundation::dictionary::*;
use core_foundation::string::*;
use core_foundation::number::*;
use std::os::raw::c_void;
use std::ops::Deref;

type IOOptionBits = u32;

pub type IOReturn = libc::c_int;

pub type IOHIDManagerRef = *mut __IOHIDManager;
pub type IOHIDManagerOptions = IOOptionBits;

pub type IOHIDDeviceCallback = extern "C" fn(
    context: *mut c_void,
    result: IOReturn,
    sender: *mut c_void,
    device: IOHIDDeviceRef,
);

pub type IOHIDReportType = IOOptionBits;
pub type IOHIDReportCallback = extern "C" fn(
    context: *mut c_void,
    result: IOReturn,
    sender: IOHIDDeviceRef,
    report_type: IOHIDReportType,
    report_id: u32,
    report: *mut u8,
    report_len: CFIndex,
);

pub const kIOHIDManagerOptionNone: IOHIDManagerOptions = 0;

pub const kIOHIDReportTypeOutput: IOHIDReportType = 1;

#[repr(C)]
pub struct __IOHIDManager {
    __private: c_void,
}

#[repr(C)]
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub struct IOHIDDeviceRef(*const c_void);

unsafe impl Send for IOHIDDeviceRef {}
unsafe impl Sync for IOHIDDeviceRef {}

pub struct SendableRunLoop(CFRunLoopRef);

impl SendableRunLoop {
    pub fn new(runloop: CFRunLoopRef) -> Self {
        // Keep the CFRunLoop alive for as long as we are.
        unsafe { CFRetain(runloop as *mut c_void) };

        SendableRunLoop(runloop)
    }
}

unsafe impl Send for SendableRunLoop {}

impl Deref for SendableRunLoop {
    type Target = CFRunLoopRef;

    fn deref(&self) -> &CFRunLoopRef {
        &self.0
    }
}

impl Drop for SendableRunLoop {
    fn drop(&mut self) {
        unsafe { CFRelease(self.0 as *mut c_void) };
    }
}

#[repr(C)]
pub struct CFRunLoopObserverContext {
    pub version: CFIndex,
    pub info: *mut c_void,
    pub retain: Option<extern "C" fn(info: *const c_void) -> *const c_void>,
    pub release: Option<extern "C" fn(info: *const c_void)>,
    pub copyDescription: Option<extern "C" fn(info: *const c_void) -> CFStringRef>,
}

impl CFRunLoopObserverContext {
    pub fn new(context: *mut c_void) -> Self {
        Self {
            version: 0 as CFIndex,
            info: context,
            retain: None,
            release: None,
            copyDescription: None,
        }
    }
}

pub struct CFRunLoopEntryObserver {
    observer: CFRunLoopObserverRef,
    // Keep alive until the observer goes away.
    context_ptr: *mut CFRunLoopObserverContext,
}

impl CFRunLoopEntryObserver {
    pub fn new(callback: CFRunLoopObserverCallBack, context: *mut c_void) -> Self {
        let context = CFRunLoopObserverContext::new(context);
        let context_ptr = Box::into_raw(Box::new(context));

        let observer = unsafe {
            CFRunLoopObserverCreate(
                kCFAllocatorDefault,
                kCFRunLoopEntry,
                false as Boolean,
                0,
                callback,
                context_ptr,
            )
        };

        Self {
            observer,
            context_ptr,
        }
    }

    pub fn add_to_current_runloop(&self) {
        unsafe {
            CFRunLoopAddObserver(CFRunLoopGetCurrent(), self.observer, kCFRunLoopDefaultMode)
        };
    }
}

impl Drop for CFRunLoopEntryObserver {
    fn drop(&mut self) {
        unsafe {
            CFRelease(self.observer as *mut c_void);

            // Drop the CFRunLoopObserverContext.
            let _ = Box::from_raw(self.context_ptr);
        };
    }
}

pub struct IOHIDDeviceMatcher {
    pub dict: CFDictionary<CFString, CFNumber>,
}

impl IOHIDDeviceMatcher {
    pub fn new() -> Self {
        let dict = CFDictionary::<CFString, CFNumber>::from_CFType_pairs(&[
            (
                CFString::from_static_string("DeviceUsage"),
                CFNumber::from(FIDO_USAGE_U2FHID as i32),
            ),
            (
                CFString::from_static_string("DeviceUsagePage"),
                CFNumber::from(FIDO_USAGE_PAGE as i32),
            ),
            ]);
        Self { dict }
    }
}

#[link(name = "IOKit", kind = "framework")]
extern "C" {
    // CFRunLoop
    pub fn CFRunLoopObserverCreate(
        allocator: CFAllocatorRef,
        activities: CFOptionFlags,
        repeats: Boolean,
        order: CFIndex,
        callout: CFRunLoopObserverCallBack,
        context: *mut CFRunLoopObserverContext,
    ) -> CFRunLoopObserverRef;

    // IOHIDManager
    pub fn IOHIDManagerCreate(
        allocator: CFAllocatorRef,
        options: IOHIDManagerOptions,
    ) -> IOHIDManagerRef;
    pub fn IOHIDManagerSetDeviceMatching(manager: IOHIDManagerRef, matching: CFDictionaryRef);
    pub fn IOHIDManagerRegisterDeviceMatchingCallback(
        manager: IOHIDManagerRef,
        callback: IOHIDDeviceCallback,
        context: *mut c_void,
    );
    pub fn IOHIDManagerRegisterDeviceRemovalCallback(
        manager: IOHIDManagerRef,
        callback: IOHIDDeviceCallback,
        context: *mut c_void,
    );
    pub fn IOHIDManagerRegisterInputReportCallback(
        manager: IOHIDManagerRef,
        callback: IOHIDReportCallback,
        context: *mut c_void,
    );
    pub fn IOHIDManagerOpen(manager: IOHIDManagerRef, options: IOHIDManagerOptions) -> IOReturn;
    pub fn IOHIDManagerClose(manager: IOHIDManagerRef, options: IOHIDManagerOptions) -> IOReturn;
    pub fn IOHIDManagerScheduleWithRunLoop(
        manager: IOHIDManagerRef,
        runLoop: CFRunLoopRef,
        runLoopMode: CFStringRef,
    );

    // IOHIDDevice
    pub fn IOHIDDeviceSetReport(
        device: IOHIDDeviceRef,
        reportType: IOHIDReportType,
        reportID: CFIndex,
        report: *const u8,
        reportLength: CFIndex,
    ) -> IOReturn;
}

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use super::*;
    use std::os::raw::c_void;
    use std::ptr;
    use std::sync::mpsc::{channel, Sender};
    use std::thread;

    extern "C" fn observe(_: CFRunLoopObserverRef, _: CFRunLoopActivity, context: *mut c_void) {
        let tx: &Sender<SendableRunLoop> = unsafe { &*(context as *mut _) };

        // Send the current runloop to the receiver to unblock it.
        let _ = tx.send(SendableRunLoop::new(unsafe { CFRunLoopGetCurrent() }));
    }

    #[test]
    fn test_sendable_runloop() {
        let (tx, rx) = channel();

        let thread = thread::spawn(move || {
            // Send the runloop to the owning thread.
            let context = &tx as *const _ as *mut c_void;
            let obs = CFRunLoopEntryObserver::new(observe, context);
            obs.add_to_current_runloop();

            unsafe {
                // We need some source for the runloop to run.
                let manager = IOHIDManagerCreate(kCFAllocatorDefault, 0);
                assert!(!manager.is_null());

                IOHIDManagerScheduleWithRunLoop(
                    manager,
                    CFRunLoopGetCurrent(),
                    kCFRunLoopDefaultMode,
                );
                IOHIDManagerSetDeviceMatching(manager, ptr::null_mut());

                let rv = IOHIDManagerOpen(manager, 0);
                assert_eq!(rv, 0);

                // This will run until `CFRunLoopStop()` is called.
                CFRunLoopRun();

                let rv = IOHIDManagerClose(manager, 0);
                assert_eq!(rv, 0);

                CFRelease(manager as *mut c_void);
            }
        });

        // Block until we enter the CFRunLoop.
        let runloop: SendableRunLoop = rx.recv().expect("failed to receive runloop");

        // Stop the runloop.
        unsafe { CFRunLoopStop(*runloop) };

        // Stop the thread.
        thread.join().expect("failed to join the thread");

        // Try to stop the runloop again (without crashing).
        unsafe { CFRunLoopStop(*runloop) };
    }
}
<|endoftext|>


<commit_before>//!
//! Generic addresses
//!

use std::{fmt, mem};
use std::ops::{Not, BitAnd, BitOr, BitXor};

/// A trait for all addresses
pub trait Address: Copy + Ord + Eq + Not<Output=Self> + BitAnd<Output=Self> + BitOr<Output=Self> + BitXor<Output=Self> + fmt::UpperHex {
    /// Type of address offset
    type Offset;

    /// The zero address
    /// TODO: Use std::num::Zero instead when it becomes stable
    fn zero () -> Self;

    /// The succeeding address (wrapping)
    fn next (self) -> Self;

    /// Calculate new address with given offset (wrapping)
    fn offset (self, offset: Self::Offset) -> Self;

    /// Calculate new address with given offset (wrapping) while protecting the masked part of
    /// the address
    fn offset_masked (&self, offset: Self::Offset, mask: Self) -> Self {
        (*self & mask) | (self.offset(offset) & !mask)
    }

    /// Return an iterator for getting successive addresses
    fn successive (self) -> Iter<Self> {
        Iter { addr: self, done: false }
    }

    /// Return an object for displaying the address
    fn display (&self) -> Display<Self> {
        Display { addr: self }
    }
}

macro_rules! impl_address {
    ($addr_type:ty, $offset_type:ty) => (
        impl Address for $addr_type {
            type Offset = $offset_type;

            fn zero () -> $addr_type { 0 }

            fn next (self) -> $addr_type { self.wrapping_add(1) }

            fn offset (self, offset: $offset_type) -> $addr_type {
                if offset < 0 {
                    self.wrapping_sub((-offset as $addr_type))
                } else {
                    self.wrapping_add(offset as $addr_type)
                }
            }
        }
    );
}

impl_address!( u8,  i8);
impl_address!(u16, i16);
impl_address!(u32, i32);

/// Iterator for getting successive addresses
pub struct Iter<A> {
    addr: A,
    done: bool,
}

impl<A: Address> Iterator for Iter<A> {
    type Item = A;

    fn next (&mut self) -> Option<A> {
        if self.done {
            None
        } else {
            let addr = self.addr;
            self.addr = self.addr.next();
            self.done = self.addr == A::zero();
            Some(addr)
        }
    }
}

/// Helper struct for displaying an address
pub struct Display<'a, A: 'a> {
    addr: &'a A,
}

impl<'a, A: Address> fmt::Display for Display<'a, A> {
    fn fmt (&self, f: &mut fmt::Formatter) -> fmt::Result {
        match mem::size_of::<A>() {
            1 => write!(f, "${:02X}", self.addr),
            2 => write!(f, "${:04X}", self.addr),
            4 => write!(f, "${:08X}", self.addr),
            _ => write!(f, "${:X}", self.addr),
        }
    }
}

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

    #[test]
    fn zero () {
        assert_eq!(u16::zero(), 0x0000);
    }

    #[test]
    fn next () {
        assert_eq!(0x1234_u16.next(), 0x1235);
        assert_eq!(0xffff_u16.next(), 0x0000);
    }

    #[test]
    fn offset () {
        assert_eq!(0x1234_u16.offset( 5), 0x1239);
        assert_eq!(0x1234_u16.offset(-3), 0x1231);
    }

    #[test]
    fn offset_wrapping () {
        assert_eq!(0xffff_u16.offset( 1), 0x0000);
        assert_eq!(0x0000_u16.offset(-1), 0xffff);
    }

    #[test]
    fn offset_masked () {
        assert_eq!(0x12ff_u16.offset_masked( 1, 0x0000), 0x1300);
        assert_eq!(0x12ff_u16.offset_masked( 1, 0xff00), 0x1200);
        assert_eq!(0x1300_u16.offset_masked(-1, 0x0000), 0x12ff);
        assert_eq!(0x1300_u16.offset_masked(-1, 0xff00), 0x13ff);
    }

    #[test]
    fn iterating () {
        let mut it = 0xfffd_u16.successive();
        assert_eq!(it.next(), Some(0xfffd));
        assert_eq!(it.next(), Some(0xfffe));
        assert_eq!(it.next(), Some(0xffff));
        assert_eq!(it.next(), None);
    }

    #[test]
    fn displaying () {
        assert_eq!(format!("{}", 0x0f_u8.display()), "$0F");
        assert_eq!(format!("{}", 0x01ff_u16.display()), "$01FF");
    }
}
<commit_msg>Make address iterator wrap and return addresses endlessly<commit_after>//!
//! Generic addresses
//!

use std::{fmt, mem};
use std::ops::{Not, BitAnd, BitOr, BitXor};

/// A trait for all addresses
pub trait Address: Copy + Ord + Eq + Not<Output=Self> + BitAnd<Output=Self> + BitOr<Output=Self> + BitXor<Output=Self> + fmt::UpperHex {
    /// Type of address offset
    type Offset;

    /// The zero address
    /// TODO: Use std::num::Zero instead when it becomes stable
    fn zero () -> Self;

    /// The succeeding address (wrapping)
    fn next (self) -> Self;

    /// Calculate new address with given offset (wrapping)
    fn offset (self, offset: Self::Offset) -> Self;

    /// Calculate new address with given offset (wrapping) while protecting the masked part of
    /// the address
    fn offset_masked (&self, offset: Self::Offset, mask: Self) -> Self {
        (*self & mask) | (self.offset(offset) & !mask)
    }

    /// Return an iterator for getting successive addresses (wrapping)
    fn successive (self) -> Iter<Self> {
        Iter { addr: self }
    }

    /// Return an object for displaying the address
    fn display (&self) -> Display<Self> {
        Display { addr: self }
    }
}

macro_rules! impl_address {
    ($addr_type:ty, $offset_type:ty) => (
        impl Address for $addr_type {
            type Offset = $offset_type;

            fn zero () -> $addr_type { 0 }

            fn next (self) -> $addr_type { self.wrapping_add(1) }

            fn offset (self, offset: $offset_type) -> $addr_type {
                if offset < 0 {
                    self.wrapping_sub((-offset as $addr_type))
                } else {
                    self.wrapping_add(offset as $addr_type)
                }
            }
        }
    );
}

impl_address!( u8,  i8);
impl_address!(u16, i16);
impl_address!(u32, i32);

/// Iterator for getting successive addresses
pub struct Iter<A> {
    addr: A,
}

impl<A: Address> Iterator for Iter<A> {
    type Item = A;

    fn next (&mut self) -> Option<A> {
        let addr = self.addr;
        self.addr = self.addr.next();
        Some(addr)
    }
}

/// Helper struct for displaying an address
pub struct Display<'a, A: 'a> {
    addr: &'a A,
}

impl<'a, A: Address> fmt::Display for Display<'a, A> {
    fn fmt (&self, f: &mut fmt::Formatter) -> fmt::Result {
        match mem::size_of::<A>() {
            1 => write!(f, "${:02X}", self.addr),
            2 => write!(f, "${:04X}", self.addr),
            4 => write!(f, "${:08X}", self.addr),
            _ => write!(f, "${:X}", self.addr),
        }
    }
}

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

    #[test]
    fn zero () {
        assert_eq!(u16::zero(), 0x0000);
    }

    #[test]
    fn next () {
        assert_eq!(0x1234_u16.next(), 0x1235);
        assert_eq!(0xffff_u16.next(), 0x0000);
    }

    #[test]
    fn offset () {
        assert_eq!(0x1234_u16.offset( 5), 0x1239);
        assert_eq!(0x1234_u16.offset(-3), 0x1231);
    }

    #[test]
    fn offset_wrapping () {
        assert_eq!(0xffff_u16.offset( 1), 0x0000);
        assert_eq!(0x0000_u16.offset(-1), 0xffff);
    }

    #[test]
    fn offset_masked () {
        assert_eq!(0x12ff_u16.offset_masked( 1, 0x0000), 0x1300);
        assert_eq!(0x12ff_u16.offset_masked( 1, 0xff00), 0x1200);
        assert_eq!(0x1300_u16.offset_masked(-1, 0x0000), 0x12ff);
        assert_eq!(0x1300_u16.offset_masked(-1, 0xff00), 0x13ff);
    }

    #[test]
    fn iterating () {
        let mut it = 0xfffe_u16.successive();
        assert_eq!(it.next(), Some(0xfffe));
        assert_eq!(it.next(), Some(0xffff));
        assert_eq!(it.next(), Some(0x0000));
        assert_eq!(it.next(), Some(0x0001));
    }

    #[test]
    fn displaying () {
        assert_eq!(format!("{}", 0x0f_u8.display()), "$0F");
        assert_eq!(format!("{}", 0x01ff_u16.display()), "$01FF");
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use self::libc::{c_char, c_uchar};

/// Creates and saves in secured Wallet identity that can be used to
/// issue and verify Identity Ledger transaction.
///
/// #Params
/// client_id: id of sovrin client instance.
/// command_id: command id to map of callback to user context.
/// identity_json: Identity information as json. For current moment it is NYM transaction
///   data with optional information for creation of sign key (DID, Verkey, Role, Alias, Seed and etc...).
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// String identifier of this Identity.
///
/// #Errors
/// No method specific errors.
/// See `SovrinError` docs for common errors description.
#[no_mangle]
pub  extern fn wallet_sovrin_create_identity(client_id: i32, command_id: i32,
                                             identity_json: *const c_char,
                                             cb: extern fn(xcommand_id: i32, err: i32,
                                                           identity_id: *const c_char)) {
    unimplemented!();
}

/// Returns public information for Identity stored in secured Wallet.
///
/// #Params
/// client_id: id of sovrin client instance.
/// command_id: command id to map of callback to user context.
/// identity_id: Id of Identity stored in secured Wallet.
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// Public Identity information as json (DID, Verkey, Role, Alias and etc...).
///
/// #Errors
/// No method specific errors.
/// See `SovrinError` docs for common errors description.
#[no_mangle]
pub  extern fn wallet_sovrin_get_identity(client_id: i32, command_id: i32,
                                          identity_id: *const c_char,
                                          cb: extern fn(xcommand_id: i32, err: i32,
                                                        identity_json: *const c_char)) {
    unimplemented!();
}

/// Returns list of ids for Identities stored in secured Wallet.
///
/// #Params
/// client_id: id of sovrin client instance.
/// command_id: command id to map of callback to user context.
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// List of stored identity ids.
///
/// #Errors
/// No method specific errors.
/// See `SovrinError` docs for common errors description.
#[no_mangle]
pub  extern fn wallet_sovrin_get_identities(client_id: i32, command_id: i32,
                                            cb: extern fn(xcommand_id: i32, err: i32,
                                                          identity_ids: [*const c_char])) {
    unimplemented!();
}

/// Creates all necessary keys and objects depends on received schema and return schema_id.
///
/// #Params
/// client_id: id of sovrin client instance.
/// command_id: command id to map of callback to user context.
/// schema_json: Schema as a json. Includes name, version, attributes, keys, accumulator and etc.
///     Every empty field in the schema will be filled with the right value.
///     For example: if schema have an empty public key value, function will generate it. If it's
///         not necessary, value for public key field should be None.
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// Returns id of schema.
///
/// #Errors
/// No method specific errors.
/// See `AnoncredsError` docs for common errors description.
#[no_mangle]
pub extern fn wallet_anoncreds_create_schema(client_id: i32, command_id: i32,
                                             schema_json: *const c_char,
                                             cb: extern fn(xcommand_id: i32, err: i32,
                                                           schema_id: *const c_char)) {
    unimplemented!();
}<commit_msg>small changes<commit_after>extern crate libc;

use self::libc::{c_char, c_uchar};

/// Creates and saves in secured Wallet identity that can be used to
/// issue and verify Identity Ledger transaction.
///
/// #Params
/// client_id: id of sovrin client instance.
/// command_id: command id to map of callback to user context.
/// identity_json: Identity information as json. For current moment it is NYM transaction
///   data with optional information for creation of sign key (DID, Verkey, Role, Alias, Seed and etc...).
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// String identifier of this Identity.
///
/// #Errors
/// No method specific errors.
/// See `SovrinError` docs for common errors description.
#[no_mangle]
pub  extern fn wallet_sovrin_create_identity(client_id: i32, command_id: i32,
                                             identity_json: *const c_char,
                                             cb: extern fn(xcommand_id: i32, err: i32,
                                                           identity_id: *const c_char)) {
    unimplemented!();
}

/// Returns public information for Identity stored in secured Wallet.
///
/// #Params
/// client_id: id of sovrin client instance.
/// command_id: command id to map of callback to user context.
/// identity_id: Id of Identity stored in secured Wallet.
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// Public Identity information as json (DID, Verkey, Role, Alias and etc...).
///
/// #Errors
/// No method specific errors.
/// See `SovrinError` docs for common errors description.
#[no_mangle]
pub  extern fn wallet_sovrin_get_identity(client_id: i32, command_id: i32,
                                          identity_id: *const c_char,
                                          cb: extern fn(xcommand_id: i32, err: i32,
                                                        identity_json: *const c_char)) {
    unimplemented!();
}

/// Returns list of ids for Identities stored in secured Wallet.
///
/// #Params
/// client_id: id of sovrin client instance.
/// command_id: command id to map of callback to user context.
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// List of stored identity ids.
///
/// #Errors
/// No method specific errors.
/// See `SovrinError` docs for common errors description.
#[no_mangle]
pub  extern fn wallet_sovrin_get_identities(client_id: i32, command_id: i32,
                                            cb: extern fn(xcommand_id: i32, err: i32,
                                                          identity_ids: [*const c_char])) {
    unimplemented!();
}

/// Creates all necessary keys and objects depends on received schema and returns schema_id.
///
/// #Params
/// client_id: id of sovrin client instance.
/// command_id: command id to map of callback to user context.
/// schema_json: Schema as a json. Includes name, version, attributes, keys, accumulator and etc.
///     Every empty field in the schema will be filled with the right value.
///     For example: if schema have an empty public key value, function will generate it. If it's
///         not necessary, value for public key field should be None.
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// Returns id of schema.
///
/// #Errors
/// No method specific errors.
/// See `AnoncredsError` docs for common errors description.
#[no_mangle]
pub extern fn wallet_anoncreds_create_schema(client_id: i32, command_id: i32,
                                             schema_json: *const c_char,
                                             cb: extern fn(xcommand_id: i32, err: i32,
                                                           schema_id: *const c_char)) {
    unimplemented!();
}<|endoftext|>


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

<%namespace name="helpers" file="/helpers.mako.rs" />

<%helpers:shorthand name="overflow" sub_properties="overflow-x overflow-y"
                    spec="https://drafts.csswg.org/css-overflow/#propdef-overflow">
    use properties::longhands::{overflow_x, overflow_y};

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let overflow = try!(overflow_x::parse(context, input));
        Ok(Longhands {
            overflow_x: overflow,
            overflow_y: overflow_y::SpecifiedValue(overflow),
        })
    }

    impl<'a> ToCss for LonghandsToSerialize<'a>  {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            if *self.overflow_x == self.overflow_y.0 {
                self.overflow_x.to_css(dest)
            } else {
                Ok(())
            }
        }
    }
</%helpers:shorthand>

macro_rules! try_parse_one {
    ($input: expr, $var: ident, $prop_module: ident) => {
        if $var.is_none() {
            if let Ok(value) = $input.try($prop_module::SingleSpecifiedValue::parse) {
                $var = Some(value);
                continue;
            }
        }
    };
    ($context: expr, $input: expr, $var: ident, $prop_module: ident) => {
        if $var.is_none() {
            if let Ok(value) = $input.try(|i| {
                $prop_module::SingleSpecifiedValue::parse($context, i)
            }) {
                $var = Some(value);
                continue;
            }
        }
    };
}

<%helpers:shorthand name="transition" extra_prefixes="moz webkit"
                    sub_properties="transition-property transition-duration
                                    transition-timing-function
                                    transition-delay"
                    spec="https://drafts.csswg.org/css-transitions/#propdef-transition">
    use parser::Parse;
    use properties::longhands::{transition_delay, transition_duration, transition_property};
    use properties::longhands::{transition_timing_function};

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        struct SingleTransition {
            transition_property: transition_property::SingleSpecifiedValue,
            transition_duration: transition_duration::SingleSpecifiedValue,
            transition_timing_function: transition_timing_function::SingleSpecifiedValue,
            transition_delay: transition_delay::SingleSpecifiedValue,
        }

        fn parse_one_transition(context: &ParserContext, input: &mut Parser) -> Result<SingleTransition,()> {
            let (mut property, mut duration) = (None, None);
            let (mut timing_function, mut delay) = (None, None);
            loop {
                try_parse_one!(input, property, transition_property);
                try_parse_one!(context, input, duration, transition_duration);
                try_parse_one!(context, input, timing_function, transition_timing_function);
                try_parse_one!(context, input, delay, transition_delay);

                break
            }

            if let Some(property) = property {
                Ok(SingleTransition {
                    transition_property: property,
                    transition_duration:
                        duration.unwrap_or_else(transition_duration::single_value::get_initial_value),
                    transition_timing_function:
                        timing_function.unwrap_or_else(transition_timing_function::single_value
                                                                                ::get_initial_specified_value),
                    transition_delay:
                        delay.unwrap_or_else(transition_delay::single_value::get_initial_value),
                })
            } else {
                Err(())
            }
        }

        let (mut properties, mut durations) = (Vec::new(), Vec::new());
        let (mut timing_functions, mut delays) = (Vec::new(), Vec::new());

        if input.try(|input| input.expect_ident_matching("none")).is_err() {
            let results = try!(input.parse_comma_separated(|i| parse_one_transition(context, i)));
            for result in results {
                properties.push(result.transition_property);
                durations.push(result.transition_duration);
                timing_functions.push(result.transition_timing_function);
                delays.push(result.transition_delay);
            }
        }

        Ok(Longhands {
            transition_property: transition_property::SpecifiedValue(properties),
            transition_duration: transition_duration::SpecifiedValue(durations),
            transition_timing_function:
                transition_timing_function::SpecifiedValue(timing_functions),
            transition_delay: transition_delay::SpecifiedValue(delays),
        })
    }

    impl<'a> ToCss for LonghandsToSerialize<'a>  {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            let len = self.transition_property.0.len();
            // There should be at least one declared value
            if len == 0 {
                return Ok(());
            }

            // If any value list length is differs then we don't do a shorthand serialization
            // either.
            % for name in "property duration delay timing_function".split():
                if len != self.transition_${name}.0.len() {
                    return Ok(());
                }
            % endfor

            for i in 0..len {
                if i != 0 {
                    write!(dest, ", ")?;
                }
                self.transition_property.0[i].to_css(dest)?;
                % for name in "duration timing_function delay".split():
                    dest.write_str(" ")?;
                    self.transition_${name}.0[i].to_css(dest)?;
                % endfor
            }
            Ok(())
        }
    }
</%helpers:shorthand>

<%helpers:shorthand name="animation" extra_prefixes="moz webkit"
                    sub_properties="animation-name animation-duration
                                    animation-timing-function animation-delay
                                    animation-iteration-count animation-direction
                                    animation-fill-mode animation-play-state"
                    allowed_in_keyframe_block="False"
                    spec="https://drafts.csswg.org/css-animations/#propdef-animation">
    <%
        props = "name duration timing_function delay iteration_count \
                 direction fill_mode play_state".split()
    %>
    use parser::Parse;
    % for prop in props:
    use properties::longhands::animation_${prop};
    % endfor

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        struct SingleAnimation {
            % for prop in props:
            animation_${prop}: animation_${prop}::SingleSpecifiedValue,
            % endfor
        }

        fn parse_one_animation(context: &ParserContext, input: &mut Parser) -> Result<SingleAnimation,()> {
            % for prop in props:
            let mut ${prop} = None;
            % endfor

            // NB: Name must be the last one here so that keywords valid for other
            // longhands are not interpreted as names.
            //
            // Also, duration must be before delay, see
            // https://drafts.csswg.org/css-animations/#typedef-single-animation
            loop {
                try_parse_one!(context, input, duration, animation_duration);
                try_parse_one!(context, input, timing_function, animation_timing_function);
                try_parse_one!(context, input, delay, animation_delay);
                try_parse_one!(context, input, iteration_count, animation_iteration_count);
                try_parse_one!(input, direction, animation_direction);
                try_parse_one!(input, fill_mode, animation_fill_mode);
                try_parse_one!(input, play_state, animation_play_state);
                try_parse_one!(context, input, name, animation_name);

                break
            }

            Ok(SingleAnimation {
                % for prop in props:
                animation_${prop}: ${prop}.unwrap_or_else(animation_${prop}::single_value
                                                          ::get_initial_specified_value),
                % endfor
            })
        }

        % for prop in props:
        let mut ${prop}s = vec![];
        % endfor

        let results = try!(input.parse_comma_separated(|i| parse_one_animation(context, i)));
        for result in results.into_iter() {
            % for prop in props:
            ${prop}s.push(result.animation_${prop});
            % endfor
        }

        Ok(Longhands {
            % for prop in props:
            animation_${prop}: animation_${prop}::SpecifiedValue(${prop}s),
            % endfor
        })
    }

    impl<'a> ToCss for LonghandsToSerialize<'a>  {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            let len = self.animation_name.0.len();
            // There should be at least one declared value
            if len == 0 {
                return Ok(());
            }

            // If any value list length is differs then we don't do a shorthand serialization
            // either.
            % for name in props[1:]:
                if len != self.animation_${name}.0.len() {
                    return Ok(())
                }
            % endfor

            for i in 0..len {
                if i != 0 {
                    try!(write!(dest, ", "));
                }

                % for name in props[1:]:
                    self.animation_${name}.0[i].to_css(dest)?;
                    dest.write_str(" ")?;
                % endfor
                self.animation_name.0[i].to_css(dest)?;
            }
            Ok(())
        }
    }
</%helpers:shorthand>

<%helpers:shorthand name="scroll-snap-type" products="gecko"
                    sub_properties="scroll-snap-type-x scroll-snap-type-y"
                    spec="https://drafts.csswg.org/css-scroll-snap/#propdef-scroll-snap-type">
    use properties::longhands::scroll_snap_type_x;

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let result = try!(scroll_snap_type_x::parse(context, input));
        Ok(Longhands {
            scroll_snap_type_x: result,
            scroll_snap_type_y: result,
        })
    }

    impl<'a> ToCss for LonghandsToSerialize<'a>  {
        // Serializes into the single keyword value if both scroll-snap-type and scroll-snap-type-y are same.
        // Otherwise into an empty string. This is done to match Gecko's behaviour.
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            if self.scroll_snap_type_x == self.scroll_snap_type_y {
                self.scroll_snap_type_x.to_css(dest)
            } else {
                Ok(())
            }
        }
    }
</%helpers:shorthand>
<commit_msg>Treat empty animation entry invalid<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

<%helpers:shorthand name="overflow" sub_properties="overflow-x overflow-y"
                    spec="https://drafts.csswg.org/css-overflow/#propdef-overflow">
    use properties::longhands::{overflow_x, overflow_y};

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let overflow = try!(overflow_x::parse(context, input));
        Ok(Longhands {
            overflow_x: overflow,
            overflow_y: overflow_y::SpecifiedValue(overflow),
        })
    }

    impl<'a> ToCss for LonghandsToSerialize<'a>  {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            if *self.overflow_x == self.overflow_y.0 {
                self.overflow_x.to_css(dest)
            } else {
                Ok(())
            }
        }
    }
</%helpers:shorthand>

macro_rules! try_parse_one {
    ($input: expr, $var: ident, $prop_module: ident) => {
        if $var.is_none() {
            if let Ok(value) = $input.try($prop_module::SingleSpecifiedValue::parse) {
                $var = Some(value);
                continue;
            }
        }
    };
    ($context: expr, $input: expr, $var: ident, $prop_module: ident) => {
        if $var.is_none() {
            if let Ok(value) = $input.try(|i| {
                $prop_module::SingleSpecifiedValue::parse($context, i)
            }) {
                $var = Some(value);
                continue;
            }
        }
    };
}

<%helpers:shorthand name="transition" extra_prefixes="moz webkit"
                    sub_properties="transition-property transition-duration
                                    transition-timing-function
                                    transition-delay"
                    spec="https://drafts.csswg.org/css-transitions/#propdef-transition">
    use parser::Parse;
    use properties::longhands::{transition_delay, transition_duration, transition_property};
    use properties::longhands::{transition_timing_function};

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        struct SingleTransition {
            transition_property: transition_property::SingleSpecifiedValue,
            transition_duration: transition_duration::SingleSpecifiedValue,
            transition_timing_function: transition_timing_function::SingleSpecifiedValue,
            transition_delay: transition_delay::SingleSpecifiedValue,
        }

        fn parse_one_transition(context: &ParserContext, input: &mut Parser) -> Result<SingleTransition,()> {
            let (mut property, mut duration) = (None, None);
            let (mut timing_function, mut delay) = (None, None);
            loop {
                try_parse_one!(input, property, transition_property);
                try_parse_one!(context, input, duration, transition_duration);
                try_parse_one!(context, input, timing_function, transition_timing_function);
                try_parse_one!(context, input, delay, transition_delay);

                break
            }

            if let Some(property) = property {
                Ok(SingleTransition {
                    transition_property: property,
                    transition_duration:
                        duration.unwrap_or_else(transition_duration::single_value::get_initial_value),
                    transition_timing_function:
                        timing_function.unwrap_or_else(transition_timing_function::single_value
                                                                                ::get_initial_specified_value),
                    transition_delay:
                        delay.unwrap_or_else(transition_delay::single_value::get_initial_value),
                })
            } else {
                Err(())
            }
        }

        let (mut properties, mut durations) = (Vec::new(), Vec::new());
        let (mut timing_functions, mut delays) = (Vec::new(), Vec::new());

        if input.try(|input| input.expect_ident_matching("none")).is_err() {
            let results = try!(input.parse_comma_separated(|i| parse_one_transition(context, i)));
            for result in results {
                properties.push(result.transition_property);
                durations.push(result.transition_duration);
                timing_functions.push(result.transition_timing_function);
                delays.push(result.transition_delay);
            }
        }

        Ok(Longhands {
            transition_property: transition_property::SpecifiedValue(properties),
            transition_duration: transition_duration::SpecifiedValue(durations),
            transition_timing_function:
                transition_timing_function::SpecifiedValue(timing_functions),
            transition_delay: transition_delay::SpecifiedValue(delays),
        })
    }

    impl<'a> ToCss for LonghandsToSerialize<'a>  {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            let len = self.transition_property.0.len();
            // There should be at least one declared value
            if len == 0 {
                return Ok(());
            }

            // If any value list length is differs then we don't do a shorthand serialization
            // either.
            % for name in "property duration delay timing_function".split():
                if len != self.transition_${name}.0.len() {
                    return Ok(());
                }
            % endfor

            for i in 0..len {
                if i != 0 {
                    write!(dest, ", ")?;
                }
                self.transition_property.0[i].to_css(dest)?;
                % for name in "duration timing_function delay".split():
                    dest.write_str(" ")?;
                    self.transition_${name}.0[i].to_css(dest)?;
                % endfor
            }
            Ok(())
        }
    }
</%helpers:shorthand>

<%helpers:shorthand name="animation" extra_prefixes="moz webkit"
                    sub_properties="animation-name animation-duration
                                    animation-timing-function animation-delay
                                    animation-iteration-count animation-direction
                                    animation-fill-mode animation-play-state"
                    allowed_in_keyframe_block="False"
                    spec="https://drafts.csswg.org/css-animations/#propdef-animation">
    <%
        props = "name duration timing_function delay iteration_count \
                 direction fill_mode play_state".split()
    %>
    use parser::Parse;
    % for prop in props:
    use properties::longhands::animation_${prop};
    % endfor

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        struct SingleAnimation {
            % for prop in props:
            animation_${prop}: animation_${prop}::SingleSpecifiedValue,
            % endfor
        }

        fn parse_one_animation(context: &ParserContext, input: &mut Parser) -> Result<SingleAnimation,()> {
            % for prop in props:
            let mut ${prop} = None;
            % endfor

            let mut parsed = 0;
            // NB: Name must be the last one here so that keywords valid for other
            // longhands are not interpreted as names.
            //
            // Also, duration must be before delay, see
            // https://drafts.csswg.org/css-animations/#typedef-single-animation
            loop {
                parsed += 1;
                try_parse_one!(context, input, duration, animation_duration);
                try_parse_one!(context, input, timing_function, animation_timing_function);
                try_parse_one!(context, input, delay, animation_delay);
                try_parse_one!(context, input, iteration_count, animation_iteration_count);
                try_parse_one!(input, direction, animation_direction);
                try_parse_one!(input, fill_mode, animation_fill_mode);
                try_parse_one!(input, play_state, animation_play_state);
                try_parse_one!(context, input, name, animation_name);

                parsed -= 1;
                break
            }

            // If nothing is parsed, this is an invalid entry.
            if parsed == 0 {
                Err(())
            } else {
                Ok(SingleAnimation {
                    % for prop in props:
                    animation_${prop}: ${prop}.unwrap_or_else(animation_${prop}::single_value
                                                              ::get_initial_specified_value),
                    % endfor
                })
            }
        }

        % for prop in props:
        let mut ${prop}s = vec![];
        % endfor

        let results = try!(input.parse_comma_separated(|i| parse_one_animation(context, i)));
        for result in results.into_iter() {
            % for prop in props:
            ${prop}s.push(result.animation_${prop});
            % endfor
        }

        Ok(Longhands {
            % for prop in props:
            animation_${prop}: animation_${prop}::SpecifiedValue(${prop}s),
            % endfor
        })
    }

    impl<'a> ToCss for LonghandsToSerialize<'a>  {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            let len = self.animation_name.0.len();
            // There should be at least one declared value
            if len == 0 {
                return Ok(());
            }

            // If any value list length is differs then we don't do a shorthand serialization
            // either.
            % for name in props[1:]:
                if len != self.animation_${name}.0.len() {
                    return Ok(())
                }
            % endfor

            for i in 0..len {
                if i != 0 {
                    try!(write!(dest, ", "));
                }

                % for name in props[1:]:
                    self.animation_${name}.0[i].to_css(dest)?;
                    dest.write_str(" ")?;
                % endfor
                self.animation_name.0[i].to_css(dest)?;
            }
            Ok(())
        }
    }
</%helpers:shorthand>

<%helpers:shorthand name="scroll-snap-type" products="gecko"
                    sub_properties="scroll-snap-type-x scroll-snap-type-y"
                    spec="https://drafts.csswg.org/css-scroll-snap/#propdef-scroll-snap-type">
    use properties::longhands::scroll_snap_type_x;

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let result = try!(scroll_snap_type_x::parse(context, input));
        Ok(Longhands {
            scroll_snap_type_x: result,
            scroll_snap_type_y: result,
        })
    }

    impl<'a> ToCss for LonghandsToSerialize<'a>  {
        // Serializes into the single keyword value if both scroll-snap-type and scroll-snap-type-y are same.
        // Otherwise into an empty string. This is done to match Gecko's behaviour.
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            if self.scroll_snap_type_x == self.scroll_snap_type_y {
                self.scroll_snap_type_x.to_css(dest)
            } else {
                Ok(())
            }
        }
    }
</%helpers:shorthand>
<|endoftext|>


<commit_before>use std::io;
use std::env;
use std::process::{Stdio, exit};

use tokio::{
    runtime,
    io::AsyncWriteExt,
    task::JoinHandle,
    process::{Command, ChildStdin},
};

/// The environment variable that is set to indicate that the current process is a server process
pub const RENDERER_PROCESS_ENV_VAR: &str = "RUN_TURTLE_CANVAS";

#[derive(Debug)]
pub struct RendererServerProcess {
    task_handle: Option<JoinHandle<()>>,
    /// A handle to the stdin of the child process
    child_stdin: ChildStdin,
}

impl RendererServerProcess {
    /// Spawn a new process for the renderer
    pub async fn spawn() -> Self {
        let current_exe = env::current_exe()
            .expect("Could not read path of the currently running executable");

        // The new process is the same executable as this process but with a special environment
        // variable passed in
        let mut child = Command::new(current_exe)
            .env(RENDERER_PROCESS_ENV_VAR, "true")
            // Pipe input so we can communicate with the spawned process
            //
            // stdout/stderr will be inherited from the current process
            .stdin(Stdio::piped())
            .spawn()
            .expect("failed to start separate process for renderer");

        let child_stdin = child.stdin.take()
            .expect("renderer process was not spawned with a handle to stdin");

        // Ensure the child process is spawned in the runtime so it can
        // make progress on its own while we send it input.
        let task_handle = Some(tokio::spawn(async {
            // We want to await in a separate task because otherwise the current task would not
            // make any progress until the child process is complete
            let status = child.await
                .expect("child process encountered an error");

            if status.success() {
                // The window/renderer process was closed normally
                exit(0);
            } else {
                // Something went wrong, likely the other thread panicked
                exit(1);
            }
        }));

        Self {task_handle, child_stdin}
    }

    /// Writes the given bytes followed by a newline b'\n' to the stdin of the process
    ///
    /// Unlike `std::io::Write::write`, this returns an error in the case all of the bytes could
    /// not be written for some reason.
    pub async fn writeln<S: AsRef<[u8]>>(&mut self, data: S) -> io::Result<()> {
        let data = data.as_ref();
        let bytes_written = self.child_stdin.write(data).await?;
        self.child_stdin.write_u8(b'\n').await?;

        if bytes_written == data.len() {
            Ok(())

        } else {
            // From the docs: "This typically means that an operation could only succeed if it
            // wrote a particular number of bytes but only a smaller number of bytes could be
            // written."
            let err_msg = format!("expected to write `{}` bytes, but actually wrote `{}`", data.len(), bytes_written);
            Err(io::Error::new(io::ErrorKind::WriteZero, err_msg))
        }
    }
}

impl Drop for RendererServerProcess {
    fn drop(&mut self) {
        use std::thread;

        // If the current thread is panicking, we want to abort right away
        // because otherwise there is code in the rendering thread that will call
        // process::exit(0) and then the exit code will be 0 instead of 1
        if thread::panicking() {
            exit(1);
        }

        // If this is just a normal ending of the main thread, we want to leave the renderer
        // running so that the user can see their drawing as long as they keep the window open
        let runtime = runtime::Handle::current();
        // This unwrap is safe because no struct gets dropped twice
        let task_handle = self.task_handle.take().unwrap();
        runtime.block_on(task_handle).unwrap_or_else(|_| {
            // If this returns an error, the other thread panicked
            exit(1);
        });
    }
}
<commit_msg>Using write_all instead of write and write_u8. This ensure that entire line is always written or an error occurs.<commit_after>use std::io;
use std::env;
use std::process::{Stdio, exit};

use tokio::{
    runtime,
    io::AsyncWriteExt,
    task::JoinHandle,
    process::{Command, ChildStdin},
};

/// The environment variable that is set to indicate that the current process is a server process
pub const RENDERER_PROCESS_ENV_VAR: &str = "RUN_TURTLE_CANVAS";

#[derive(Debug)]
pub struct RendererServerProcess {
    task_handle: Option<JoinHandle<()>>,
    /// A handle to the stdin of the child process
    child_stdin: ChildStdin,
}

impl RendererServerProcess {
    /// Spawn a new process for the renderer
    pub async fn spawn() -> Self {
        let current_exe = env::current_exe()
            .expect("Could not read path of the currently running executable");

        // The new process is the same executable as this process but with a special environment
        // variable passed in
        let mut child = Command::new(current_exe)
            .env(RENDERER_PROCESS_ENV_VAR, "true")
            // Pipe input so we can communicate with the spawned process
            //
            // stdout/stderr will be inherited from the current process
            .stdin(Stdio::piped())
            .spawn()
            .expect("failed to start separate process for renderer");

        let child_stdin = child.stdin.take()
            .expect("renderer process was not spawned with a handle to stdin");

        // Ensure the child process is spawned in the runtime so it can
        // make progress on its own while we send it input.
        let task_handle = Some(tokio::spawn(async {
            // We want to await in a separate task because otherwise the current task would not
            // make any progress until the child process is complete
            let status = child.await
                .expect("child process encountered an error");

            if status.success() {
                // The window/renderer process was closed normally
                exit(0);
            } else {
                // Something went wrong, likely the other thread panicked
                exit(1);
            }
        }));

        Self {task_handle, child_stdin}
    }

    /// Writes the given bytes followed by a newline b'\n' to the stdin of the process
    ///
    /// Unlike `std::io::Write::write`, this returns an error in the case all of the bytes could
    /// not be written for some reason.
    pub async fn writeln<S: AsRef<[u8]>>(&mut self, data: S) -> io::Result<()> {
        let data = data.as_ref();
        self.child_stdin.write_all(data).await?;
        self.child_stdin.write_all(&[b'\n']).await?;

        Ok(())
    }
}

impl Drop for RendererServerProcess {
    fn drop(&mut self) {
        use std::thread;

        // If the current thread is panicking, we want to abort right away
        // because otherwise there is code in the rendering thread that will call
        // process::exit(0) and then the exit code will be 0 instead of 1
        if thread::panicking() {
            exit(1);
        }

        // If this is just a normal ending of the main thread, we want to leave the renderer
        // running so that the user can see their drawing as long as they keep the window open
        let runtime = runtime::Handle::current();
        // This unwrap is safe because no struct gets dropped twice
        let task_handle = self.task_handle.take().unwrap();
        runtime.block_on(task_handle).unwrap_or_else(|_| {
            // If this returns an error, the other thread panicked
            exit(1);
        });
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(rand, core)]

use std::fs::File;
use std::io::prelude::*;
use std::iter::repeat;
use std::path::Path;
use std::process::Command;
use std::__rand::{thread_rng, Rng};
use std::{char, env};

// creates a file with `fn main() { <random ident> }` and checks the
// compiler emits a span of the appropriate length (for the
// "unresolved name" message); currently just using the number of code
// points, but should be the number of graphemes (FIXME #7043)

fn random_char() -> char {
    let mut rng = thread_rng();
    // a subset of the XID_start Unicode table (ensuring that the
    // compiler doesn't fail with an "unrecognised token" error)
    let (lo, hi): (u32, u32) = match rng.gen_range(1u32, 4u32 + 1) {
        1 => (0x41, 0x5a),
        2 => (0xf8, 0x1ba),
        3 => (0x1401, 0x166c),
        _ => (0x10400, 0x1044f)
    };

    char::from_u32(rng.gen_range(lo, hi + 1)).unwrap()
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let rustc = &args[1];
    let tmpdir = Path::new(&args[2]);
    let main_file = tmpdir.join("span_main.rs");

    for _ in 0..100 {
        let n = thread_rng().gen_range(3, 20);

        {
            let _ = write!(&mut File::create(&main_file).unwrap(),
                           "#![feature(non_ascii_idents)] fn main() {{ {} }}",
                           // random string of length n
                           (0..n).map(|_| random_char()).collect::<String>());
        }

        // rustc is passed to us with --out-dir and -L etc., so we
        // can't exec it directly
        let result = Command::new("sh")
                             .arg("-c")
                             .arg(&format!("{} {}",
                                           rustc,
                                           main_file.to_str()
                                                    .unwrap()))
                             .output().unwrap();

        let err = String::from_utf8_lossy(&result.stderr);

        // the span should end the line (e.g no extra ^'s)
        let expected_span = format!("^{}\n", repeat("^").take(n - 1)
                                                        .collect::<String>());
        assert!(err.contains(&expected_span));
    }

    // Test multi-column characters and tabs
    {
        let _ = write!(&mut File::create(&main_file).unwrap(),
                       r#"extern "路濫狼á́́" fn foo() {{}} extern "路濫狼á́" fn bar() {{}}"#);
    }

    // Extra characters. Every line is preceded by `filename:lineno <actual code>`
    let offset = main_file.to_str().unwrap().len() + 3;

    let result = Command::new("sh")
                         .arg("-c")
                         .arg(format!("{} {}",
                                      rustc,
                                      main_file.display()))
                         .output().unwrap();

    let err = String::from_utf8_lossy(&result.stderr);

    // Test both the length of the snake and the leading spaces up to it

    // First snake is 9 ^s long.
    let expected_1 = r#"
1 |> extern "路濫狼á́́" fn foo() {} extern "路濫狼á́" fn bar() {}
  |>        ^^^^^^^^^
"#;
    assert!(err.contains(&expected_1));

    // Second snake is only 8 ^s long, because rustc counts chars()
    // now rather than width(). This is because width() functions are
    // to be removed from librustc_unicode
    let expected_2 = r#"
1 |> extern "路濫狼á́́" fn foo() {} extern "路濫狼á́" fn bar() {}
  |>                                     ^^^^^^^^
"#;
    assert!(err.contains(&expected_2));
}
<commit_msg>Fix unicode test to use original error format<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(rand, core)]

use std::fs::File;
use std::io::prelude::*;
use std::iter::repeat;
use std::path::Path;
use std::process::Command;
use std::__rand::{thread_rng, Rng};
use std::{char, env};

// creates a file with `fn main() { <random ident> }` and checks the
// compiler emits a span of the appropriate length (for the
// "unresolved name" message); currently just using the number of code
// points, but should be the number of graphemes (FIXME #7043)

fn random_char() -> char {
    let mut rng = thread_rng();
    // a subset of the XID_start Unicode table (ensuring that the
    // compiler doesn't fail with an "unrecognised token" error)
    let (lo, hi): (u32, u32) = match rng.gen_range(1u32, 4u32 + 1) {
        1 => (0x41, 0x5a),
        2 => (0xf8, 0x1ba),
        3 => (0x1401, 0x166c),
        _ => (0x10400, 0x1044f)
    };

    char::from_u32(rng.gen_range(lo, hi + 1)).unwrap()
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let rustc = &args[1];
    let tmpdir = Path::new(&args[2]);
    let main_file = tmpdir.join("span_main.rs");

    for _ in 0..100 {
        let n = thread_rng().gen_range(3, 20);

        {
            let _ = write!(&mut File::create(&main_file).unwrap(),
                           "#![feature(non_ascii_idents)] fn main() {{ {} }}",
                           // random string of length n
                           (0..n).map(|_| random_char()).collect::<String>());
        }

        // rustc is passed to us with --out-dir and -L etc., so we
        // can't exec it directly
        let result = Command::new("sh")
                             .arg("-c")
                             .arg(&format!("{} {}",
                                           rustc,
                                           main_file.to_str()
                                                    .unwrap()))
                             .output().unwrap();

        let err = String::from_utf8_lossy(&result.stderr);

        // the span should end the line (e.g no extra ~'s)
        let expected_span = format!("^{}\n", repeat("~").take(n - 1)
                                                        .collect::<String>());
        assert!(err.contains(&expected_span));
    }

    // Test multi-column characters and tabs
    {
        let _ = write!(&mut File::create(&main_file).unwrap(),
                       r#"extern "路濫狼á́́" fn foo() {{}} extern "路濫狼á́" fn bar() {{}}"#);
    }

    // Extra characters. Every line is preceded by `filename:lineno <actual code>`
    let offset = main_file.to_str().unwrap().len() + 3;

    let result = Command::new("sh")
                         .arg("-c")
                         .arg(format!("{} {}",
                                      rustc,
                                      main_file.display()))
                         .output().unwrap();

    let err = String::from_utf8_lossy(&result.stderr);

    // Test both the length of the snake and the leading spaces up to it

    // First snake is 8 ~s long, with 7 preceding spaces (excluding file name/line offset)
    let expected_span = format!("\n{}^{}\n",
                                repeat(" ").take(offset + 7).collect::<String>(),
                                repeat("~").take(8).collect::<String>());
    assert!(err.contains(&expected_span));
    // Second snake is only 7 ~s long, with 36 preceding spaces,
    // because rustc counts chars() now rather than width(). This
    // is because width() functions are to be removed from
    // librustc_unicode
    let expected_span = format!("\n{}^{}\n",
                                repeat(" ").take(offset + 36).collect::<String>(),
                                repeat("~").take(7).collect::<String>());
    assert!(err.contains(&expected_span));
}
<|endoftext|>