<commit_before>//! `protoc` binary downloaded and stored inside the crate.
//!
//! Can be used to avoid downloading and installing `protoc` binary.

#![deny(missing_docs)]
#![deny(broken_intra_doc_links)]

use std::env;
use std::fmt;
use std::path::Path;
use std::path::PathBuf;

/// Error returned when a binary is not available.
#[derive(Debug)]
pub struct Error {
    os: &'static str,
    arch: &'static str,
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "protoc binary cannot be found for platform {}-{}",
            self.os, self.arch
        )
    }
}

impl std::error::Error for Error {}

/// Return a path to `protoc` binary.
///
/// This function returns an error when binary is not available for
/// the current operating system and architecture.
pub fn protoc_bin_path() -> Result<PathBuf, Error> {
    let protoc_bin_name = match (env::consts::OS, env::consts::ARCH) {
        ("linux", "x86") => "protoc-linux-x86_32",
        ("linux", "x86_64") => "protoc-linux-x86_64",
        ("linux", "aarch64") => "protoc-linux-aarch_64",
        ("linux", "powerpc64") => "protoc-linux-ppcle_64",
        ("macos", "x86_64") => "protoc-osx-x86_64",
        ("windows", _) => "protoc-win32.exe",
        (os, arch) => return Err(Error { os, arch }),
    };
    let protoc_bin_path = Path::new(env!("CARGO_MANIFEST_DIR"))
        .join("bin")
        .join(protoc_bin_name);
    assert!(
        protoc_bin_path.exists(),
        "internal: protoc not found {}",
        protoc_bin_name
    );
    Ok(protoc_bin_path)
}

#[cfg(test)]
mod test {
    use std::io::Read;
    use std::process;

    #[test]
    fn smoke() {
        let process = process::Command::new(super::protoc_bin_path().unwrap())
            .arg("--version")
            .stdin(process::Stdio::null())
            .stdout(process::Stdio::piped())
            .spawn()
            .unwrap();
        let mut stdout = String::new();
        process.stdout.unwrap().read_to_string(&mut stdout).unwrap();
        assert!(stdout.contains("libprotoc"), "stdout is: {:?}", stdout)
    }
}
<commit_msg>Add stopgap support for Apple M1 to protoc-bin-vendored<commit_after>//! `protoc` binary downloaded and stored inside the crate.
//!
//! Can be used to avoid downloading and installing `protoc` binary.

#![deny(missing_docs)]
#![deny(broken_intra_doc_links)]

use std::env;
use std::fmt;
use std::path::Path;
use std::path::PathBuf;

/// Error returned when a binary is not available.
#[derive(Debug)]
pub struct Error {
    os: &'static str,
    arch: &'static str,
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "protoc binary cannot be found for platform {}-{}",
            self.os, self.arch
        )
    }
}

impl std::error::Error for Error {}

/// Return a path to `protoc` binary.
///
/// This function returns an error when binary is not available for
/// the current operating system and architecture.
pub fn protoc_bin_path() -> Result<PathBuf, Error> {
    let protoc_bin_name = match (env::consts::OS, env::consts::ARCH) {
        ("linux", "x86") => "protoc-linux-x86_32",
        ("linux", "x86_64") => "protoc-linux-x86_64",
        ("linux", "aarch64") => "protoc-linux-aarch_64",
        ("linux", "powerpc64") => "protoc-linux-ppcle_64",
        ("macos", "x86_64") => "protoc-osx-x86_64",
        // Stopgap support for Apple M1.
        // Since M1 macs can run the x86_64 binary using Rosetta emulation,
        // this updates protoc_bin_path to reuse the protoc-osx-x86_64 binary for macos aarch64.
        // Once Google provides precompiled binaries for Apple ARM,
        // this should be updated to use that instead.
        ("macos", "aarch64") => "protoc-osx-x86_64",
        ("windows", _) => "protoc-win32.exe",
        (os, arch) => return Err(Error { os, arch }),
    };
    let protoc_bin_path = Path::new(env!("CARGO_MANIFEST_DIR"))
        .join("bin")
        .join(protoc_bin_name);
    assert!(
        protoc_bin_path.exists(),
        "internal: protoc not found {}",
        protoc_bin_name
    );
    Ok(protoc_bin_path)
}

#[cfg(test)]
mod test {
    use std::io::Read;
    use std::process;

    #[test]
    fn smoke() {
        let process = process::Command::new(super::protoc_bin_path().unwrap())
            .arg("--version")
            .stdin(process::Stdio::null())
            .stdout(process::Stdio::piped())
            .spawn()
            .unwrap();
        let mut stdout = String::new();
        process.stdout.unwrap().read_to_string(&mut stdout).unwrap();
        assert!(stdout.contains("libprotoc"), "stdout is: {:?}", stdout)
    }
}
<|endoftext|>


<commit_before>use gl;
use glutin;
use native::NativeTaskBuilder;
use std::sync::atomic::{AtomicUint, Relaxed};
use std::sync::{Arc, Mutex};
use std::task::TaskBuilder;
use time;

enum Message {
    EndFrame,
    Execute(proc(&gl::Gl, &mut GLState):Send),
}

pub struct Context {
    commands: Mutex<Sender<Message>>,
    events: Mutex<Receiver<glutin::Event>>,

    /// Dimensions of the frame buffer.
    dimensions: Arc<(AtomicUint, AtomicUint)>,
}

/// Represents the current OpenGL state.
/// The current state is passed to each function and can be freely updated.
pub struct GLState {
    // The latest value passed to `glUseProgram`.
    pub program: gl::types::GLuint,

    // The latest value passed to `glClearColor`.
    pub clear_color: (gl::types::GLclampf, gl::types::GLclampf,
                      gl::types::GLclampf, gl::types::GLclampf),

    // The latest value passed to `glClearDepthf`.
    pub clear_depth: gl::types::GLclampf,

    // The latest value passed to `glClearStencil`.
    pub clear_stencil: gl::types::GLint,

    /// The latest buffer bound to `GL_ARRAY_BUFFER`.
    pub array_buffer_binding: Option<gl::types::GLuint>,

    /// The latest buffer bound to `GL_ELEMENT_ARRAY_BUFFER`.
    pub element_array_buffer_binding: Option<gl::types::GLuint>,

    /// The latest value passed to `glDepthFunc`.
    pub depth_func: gl::types::GLenum,

    /// The latest values passed to `glViewport`.
    pub viewport: (gl::types::GLint, gl::types::GLint, gl::types::GLsizei, gl::types::GLsizei),

}

impl Context {
    pub fn new(window: glutin::Window) -> Context {
        let (tx_events, rx_events) = channel();
        let (tx_commands, rx_commands) = channel();

        let dimensions = Arc::new((AtomicUint::new(800), AtomicUint::new(600)));

        let context = Context {
            commands: Mutex::new(tx_commands),
            events: Mutex::new(rx_events),
            dimensions: dimensions.clone(),
        };

        TaskBuilder::new().native().spawn(proc() {
            unsafe { window.make_current(); }

            let gl = gl::Gl::load_with(|symbol| window.get_proc_address(symbol));

            // building the GLState and modifying to GL state to match it
            let mut gl_state = {
                gl.DepthFunc(gl::ALWAYS);
                gl.Enable(gl::DEPTH_TEST);

                let viewport = {
                    let dim = window.get_inner_size().unwrap();
                    dimensions.0.store(dim.0, Relaxed);
                    dimensions.1.store(dim.1, Relaxed);
                    (0, 0, dim.0 as gl::types::GLsizei, dim.1 as gl::types::GLsizei)
                };

                GLState {
                    program: 0,
                    clear_color: (0.0, 0.0, 0.0, 0.0),
                    clear_depth: 1.0,
                    clear_stencil: 0,
                    array_buffer_binding: None,
                    element_array_buffer_binding: None,
                    depth_func: gl::ALWAYS,
                    viewport: viewport,
                }
            };

            let mut next_loop = time::precise_time_ns();
            'main: loop {
                // sleeping until next frame must be drawn
                use std::io::timer;
                timer::sleep({
                    use std::time::Duration;

                    let now = time::precise_time_ns();
                    if next_loop < now {
                        Duration::nanoseconds(0)
                    } else {
                        Duration::nanoseconds((next_loop - now) as i64)
                    }
                });

                // calling glViewport
                {
                    match window.get_inner_size() {
                        Some(dim) => {
                            dimensions.0.store(dim.0, Relaxed);
                            dimensions.1.store(dim.1, Relaxed);

                            // TODO: this should not be here
                            if gl_state.viewport != (0, 0, dim.0 as gl::types::GLsizei,
                                                     dim.0 as gl::types::GLsizei)
                            {
                                gl.Viewport(0, 0, *dim.ref0() as gl::types::GLsizei,
                                    *dim.ref1() as gl::types::GLsizei);
                                gl_state.viewport = (0, 0, dim.0 as gl::types::GLsizei,
                                    dim.1 as gl::types::GLsizei);
                            }
                        },
                        None => ()
                    };
                }

                // processing commands
                loop {
                    match rx_commands.recv_opt() {
                        Ok(EndFrame) => break,
                        Ok(Execute(cmd)) => cmd(&gl, &mut gl_state),
                        Err(_) => break 'main
                    }
                }

                // swapping
                window.swap_buffers();

                // getting events
                for event in window.poll_events() {
                    if tx_events.send_opt(event.clone()).is_err() {
                        break 'main;
                    }
                }

                // finding time to next loop
                next_loop += 16666667;
            }
        });

        context
    }

    pub fn get_framebuffer_dimensions(&self) -> (uint, uint) {
        (
            self.dimensions.0.load(Relaxed),
            self.dimensions.1.load(Relaxed),
        )
    }

    pub fn exec(&self, f: proc(&gl::Gl, &mut GLState): Send) {
        self.commands.lock().send(Execute(f));
    }

    pub fn swap_buffers(&self) {
        self.commands.lock().send(EndFrame);
    }

    pub fn recv(&self) -> Vec<glutin::Event> {
        let mut events = self.events.lock();

        let mut result = Vec::new();
        loop {
            match events.try_recv() {
                Ok(ev) => result.push(ev),
                Err(_) => break
            }
        }
        result
    }
}
<commit_msg>Fix viewport not being cached properly<commit_after>use gl;
use glutin;
use native::NativeTaskBuilder;
use std::sync::atomic::{AtomicUint, Relaxed};
use std::sync::{Arc, Mutex};
use std::task::TaskBuilder;
use time;

enum Message {
    EndFrame,
    Execute(proc(&gl::Gl, &mut GLState):Send),
}

pub struct Context {
    commands: Mutex<Sender<Message>>,
    events: Mutex<Receiver<glutin::Event>>,

    /// Dimensions of the frame buffer.
    dimensions: Arc<(AtomicUint, AtomicUint)>,
}

/// Represents the current OpenGL state.
/// The current state is passed to each function and can be freely updated.
pub struct GLState {
    // The latest value passed to `glUseProgram`.
    pub program: gl::types::GLuint,

    // The latest value passed to `glClearColor`.
    pub clear_color: (gl::types::GLclampf, gl::types::GLclampf,
                      gl::types::GLclampf, gl::types::GLclampf),

    // The latest value passed to `glClearDepthf`.
    pub clear_depth: gl::types::GLclampf,

    // The latest value passed to `glClearStencil`.
    pub clear_stencil: gl::types::GLint,

    /// The latest buffer bound to `GL_ARRAY_BUFFER`.
    pub array_buffer_binding: Option<gl::types::GLuint>,

    /// The latest buffer bound to `GL_ELEMENT_ARRAY_BUFFER`.
    pub element_array_buffer_binding: Option<gl::types::GLuint>,

    /// The latest value passed to `glDepthFunc`.
    pub depth_func: gl::types::GLenum,

    /// The latest values passed to `glViewport`.
    pub viewport: (gl::types::GLint, gl::types::GLint, gl::types::GLsizei, gl::types::GLsizei),

}

impl Context {
    pub fn new(window: glutin::Window) -> Context {
        let (tx_events, rx_events) = channel();
        let (tx_commands, rx_commands) = channel();

        let dimensions = Arc::new((AtomicUint::new(800), AtomicUint::new(600)));

        let context = Context {
            commands: Mutex::new(tx_commands),
            events: Mutex::new(rx_events),
            dimensions: dimensions.clone(),
        };

        TaskBuilder::new().native().spawn(proc() {
            unsafe { window.make_current(); }

            let gl = gl::Gl::load_with(|symbol| window.get_proc_address(symbol));

            // building the GLState and modifying to GL state to match it
            let mut gl_state = {
                gl.DepthFunc(gl::ALWAYS);
                gl.Enable(gl::DEPTH_TEST);

                let viewport = {
                    let dim = window.get_inner_size().unwrap();
                    dimensions.0.store(dim.0, Relaxed);
                    dimensions.1.store(dim.1, Relaxed);
                    (0, 0, dim.0 as gl::types::GLsizei, dim.1 as gl::types::GLsizei)
                };

                GLState {
                    program: 0,
                    clear_color: (0.0, 0.0, 0.0, 0.0),
                    clear_depth: 1.0,
                    clear_stencil: 0,
                    array_buffer_binding: None,
                    element_array_buffer_binding: None,
                    depth_func: gl::ALWAYS,
                    viewport: viewport,
                }
            };

            let mut next_loop = time::precise_time_ns();
            'main: loop {
                // sleeping until next frame must be drawn
                use std::io::timer;
                timer::sleep({
                    use std::time::Duration;

                    let now = time::precise_time_ns();
                    if next_loop < now {
                        Duration::nanoseconds(0)
                    } else {
                        Duration::nanoseconds((next_loop - now) as i64)
                    }
                });

                // calling glViewport
                {
                    match window.get_inner_size() {
                        Some(dim) => {
                            dimensions.0.store(dim.0, Relaxed);
                            dimensions.1.store(dim.1, Relaxed);

                            // TODO: this should not be here
                            if gl_state.viewport != (0, 0, dim.0 as gl::types::GLsizei,
                                                     dim.1 as gl::types::GLsizei)
                            {
                                gl.Viewport(0, 0, *dim.ref0() as gl::types::GLsizei,
                                    *dim.ref1() as gl::types::GLsizei);
                                gl_state.viewport = (0, 0, dim.0 as gl::types::GLsizei,
                                    dim.1 as gl::types::GLsizei);
                            }
                        },
                        None => ()
                    };
                }

                // processing commands
                loop {
                    match rx_commands.recv_opt() {
                        Ok(EndFrame) => break,
                        Ok(Execute(cmd)) => cmd(&gl, &mut gl_state),
                        Err(_) => break 'main
                    }
                }

                // swapping
                window.swap_buffers();

                // getting events
                for event in window.poll_events() {
                    if tx_events.send_opt(event.clone()).is_err() {
                        break 'main;
                    }
                }

                // finding time to next loop
                next_loop += 16666667;
            }
        });

        context
    }

    pub fn get_framebuffer_dimensions(&self) -> (uint, uint) {
        (
            self.dimensions.0.load(Relaxed),
            self.dimensions.1.load(Relaxed),
        )
    }

    pub fn exec(&self, f: proc(&gl::Gl, &mut GLState): Send) {
        self.commands.lock().send(Execute(f));
    }

    pub fn swap_buffers(&self) {
        self.commands.lock().send(EndFrame);
    }

    pub fn recv(&self) -> Vec<glutin::Event> {
        let mut events = self.events.lock();

        let mut result = Vec::new();
        loop {
            match events.try_recv() {
                Ok(ev) => result.push(ev),
                Err(_) => break
            }
        }
        result
    }
}
<|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/. */

use font::{Font, FontGroup};
use font::SpecifiedFontStyle;
use platform::font_context::FontContextHandle;
use style::computed_values::font_style;

use font_cache_task::FontCacheTask;
use font_template::FontTemplateDescriptor;
use platform::font_template::FontTemplateData;
use font::FontHandleMethods;
use platform::font::FontHandle;
use servo_util::cache::HashCache;

use std::rc::{Rc, Weak};
use std::cell::RefCell;
use sync::Arc;

use azure::AzFloat;
use azure::azure_hl::BackendType;
use azure::scaled_font::ScaledFont;

#[cfg(target_os="linux")]
#[cfg(target_os="android")]
use azure::scaled_font::FontData;

#[cfg(target_os="linux")]
#[cfg(target_os="android")]
fn create_scaled_font(backend: BackendType, template: &Arc<FontTemplateData>, pt_size: f64) -> ScaledFont {
    ScaledFont::new(backend, FontData(&template.bytes), pt_size as AzFloat)
}

#[cfg(target_os="macos")]
fn create_scaled_font(backend: BackendType, template: &Arc<FontTemplateData>, pt_size: f64) -> ScaledFont {
    let cgfont = template.ctfont.get_ref().copy_to_CGFont();
    ScaledFont::new(backend, &cgfont, pt_size as AzFloat)
}

/// A cached azure font (per render task) that
/// can be shared by multiple text runs.
struct RenderFontCacheEntry {
    pt_size: f64,
    identifier: String,
    font: Rc<RefCell<ScaledFont>>,
}

/// The FontContext represents the per-thread/task state necessary for
/// working with fonts. It is the public API used by the layout and
/// render code. It talks directly to the font cache task where
/// required.
pub struct FontContext {
    platform_handle: FontContextHandle,
    font_cache_task: FontCacheTask,

    /// Weak reference as the layout FontContext is persistent.
    layout_font_cache: Vec<Weak<RefCell<Font>>>,

    /// Strong reference as the render FontContext is (for now) recycled
    /// per frame. TODO: Make this weak when incremental redraw is done.
    render_font_cache: Vec<RenderFontCacheEntry>,
}

impl FontContext {
    pub fn new(font_cache_task: FontCacheTask) -> FontContext {
        let handle = FontContextHandle::new();
        FontContext {
            platform_handle: handle,
            font_cache_task: font_cache_task,
            layout_font_cache: vec!(),
            render_font_cache: vec!(),
        }
    }

    /// Create a font for use in layout calculations.
    fn create_layout_font(&self, template: Arc<FontTemplateData>,
                            descriptor: FontTemplateDescriptor, pt_size: f64) -> Font {

        let handle: FontHandle = FontHandleMethods::new_from_template(&self.platform_handle, template, Some(pt_size)).unwrap();
        let metrics = handle.get_metrics();

        Font {
            handle: handle,
            shaper: None,
            descriptor: descriptor,
            pt_size: pt_size,
            metrics: metrics,
            shape_cache: HashCache::new(),
            glyph_advance_cache: HashCache::new(),
        }
    }

    /// Create a group of fonts for use in layout calculations. May return
    /// a cached font if this font instance has already been used by
    /// this context.
    pub fn get_layout_font_group_for_style(&mut self, style: &SpecifiedFontStyle) -> FontGroup {
        // Remove all weak pointers that have been dropped.
        self.layout_font_cache.retain(|maybe_font| {
            maybe_font.upgrade().is_some()
        });

        let mut fonts: Vec<Rc<RefCell<Font>>> = vec!();

        for family in style.families.iter() {
            let desc = FontTemplateDescriptor::new(style.weight, style.style == font_style::italic);

            // GWTODO: Check on real pages if this is faster as Vec() or HashMap().
            let mut cache_hit = false;
            for maybe_cached_font in self.layout_font_cache.iter() {
                let cached_font = maybe_cached_font.upgrade().unwrap();
                if cached_font.borrow().descriptor == desc {
                    fonts.push(cached_font.clone());
                    cache_hit = true;
                    break;
                }
            }

            if !cache_hit {
                let font_template = self.font_cache_task.get_font_template(family.clone(), desc.clone());
                let layout_font = Rc::new(RefCell::new(self.create_layout_font(font_template, desc.clone(), style.pt_size)));
                self.layout_font_cache.push(layout_font.downgrade());
                fonts.push(layout_font);
            }
        }

        FontGroup::new(fonts)
    }

    /// Create a render font for use with azure. May return a cached
    /// reference if already used by this font context.
    pub fn get_render_font_from_template(&mut self, template: &Arc<FontTemplateData>, pt_size: f64, backend: BackendType) -> Rc<RefCell<ScaledFont>> {
        for cached_font in self.render_font_cache.iter() {
            if cached_font.pt_size == pt_size &&
               cached_font.identifier == template.identifier {
                return cached_font.font.clone();
            }
        }

        let render_font = Rc::new(RefCell::new(create_scaled_font(backend, template, pt_size)));
        self.render_font_cache.push(RenderFontCacheEntry{
            font: render_font.clone(),
            pt_size: pt_size,
            identifier: template.identifier.clone(),
        });
        render_font
    }
}
<commit_msg>Reduce number of font instances and shaper structures created.<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/. */

use font::{Font, FontGroup};
use font::SpecifiedFontStyle;
use platform::font_context::FontContextHandle;
use style::computed_values::font_style;

use font_cache_task::FontCacheTask;
use font_template::FontTemplateDescriptor;
use platform::font_template::FontTemplateData;
use font::FontHandleMethods;
use platform::font::FontHandle;
use servo_util::cache::HashCache;

use std::rc::{Rc, Weak};
use std::cell::RefCell;
use sync::Arc;

use azure::AzFloat;
use azure::azure_hl::BackendType;
use azure::scaled_font::ScaledFont;

#[cfg(target_os="linux")]
#[cfg(target_os="android")]
use azure::scaled_font::FontData;

#[cfg(target_os="linux")]
#[cfg(target_os="android")]
fn create_scaled_font(backend: BackendType, template: &Arc<FontTemplateData>, pt_size: f64) -> ScaledFont {
    ScaledFont::new(backend, FontData(&template.bytes), pt_size as AzFloat)
}

#[cfg(target_os="macos")]
fn create_scaled_font(backend: BackendType, template: &Arc<FontTemplateData>, pt_size: f64) -> ScaledFont {
    let cgfont = template.ctfont.get_ref().copy_to_CGFont();
    ScaledFont::new(backend, &cgfont, pt_size as AzFloat)
}

/// A cached azure font (per render task) that
/// can be shared by multiple text runs.
struct RenderFontCacheEntry {
    pt_size: f64,
    identifier: String,
    font: Rc<RefCell<ScaledFont>>,
}

/// The FontContext represents the per-thread/task state necessary for
/// working with fonts. It is the public API used by the layout and
/// render code. It talks directly to the font cache task where
/// required.
pub struct FontContext {
    platform_handle: FontContextHandle,
    font_cache_task: FontCacheTask,

    /// Weak reference as the layout FontContext is persistent.
    layout_font_cache: Vec<Rc<RefCell<Font>>>,

    /// Strong reference as the render FontContext is (for now) recycled
    /// per frame. TODO: Make this weak when incremental redraw is done.
    render_font_cache: Vec<RenderFontCacheEntry>,
}

impl FontContext {
    pub fn new(font_cache_task: FontCacheTask) -> FontContext {
        let handle = FontContextHandle::new();
        FontContext {
            platform_handle: handle,
            font_cache_task: font_cache_task,
            layout_font_cache: vec!(),
            render_font_cache: vec!(),
        }
    }

    /// Create a font for use in layout calculations.
    fn create_layout_font(&self, template: Arc<FontTemplateData>,
                            descriptor: FontTemplateDescriptor, pt_size: f64) -> Font {

        let handle: FontHandle = FontHandleMethods::new_from_template(&self.platform_handle, template, Some(pt_size)).unwrap();
        let metrics = handle.get_metrics();

        Font {
            handle: handle,
            shaper: None,
            descriptor: descriptor,
            pt_size: pt_size,
            metrics: metrics,
            shape_cache: HashCache::new(),
            glyph_advance_cache: HashCache::new(),
        }
    }

    /// Create a group of fonts for use in layout calculations. May return
    /// a cached font if this font instance has already been used by
    /// this context.
    pub fn get_layout_font_group_for_style(&mut self, style: &SpecifiedFontStyle) -> FontGroup {
        // TODO: The font context holds a strong ref to the cached fonts
        // so they will never be released. Find out a good time to drop them.

        let mut fonts: Vec<Rc<RefCell<Font>>> = vec!();

        for family in style.families.iter() {
            let desc = FontTemplateDescriptor::new(style.weight, style.style == font_style::italic);

            // GWTODO: Check on real pages if this is faster as Vec() or HashMap().
            let mut cache_hit = false;
            for cached_font in self.layout_font_cache.iter() {
                if cached_font.borrow().descriptor == desc &&
                   cached_font.borrow().pt_size == style.pt_size {
                    fonts.push(cached_font.clone());
                    cache_hit = true;
                    break;
                }
            }

            if !cache_hit {
                let font_template = self.font_cache_task.get_font_template(family.clone(), desc.clone());
                let layout_font = Rc::new(RefCell::new(self.create_layout_font(font_template, desc.clone(), style.pt_size)));
                self.layout_font_cache.push(layout_font.clone());
                fonts.push(layout_font);
            }
        }

        FontGroup::new(fonts)
    }

    /// Create a render font for use with azure. May return a cached
    /// reference if already used by this font context.
    pub fn get_render_font_from_template(&mut self, template: &Arc<FontTemplateData>, pt_size: f64, backend: BackendType) -> Rc<RefCell<ScaledFont>> {
        for cached_font in self.render_font_cache.iter() {
            if cached_font.pt_size == pt_size &&
               cached_font.identifier == template.identifier {
                return cached_font.font.clone();
            }
        }

        let render_font = Rc::new(RefCell::new(create_scaled_font(backend, template, pt_size)));
        self.render_font_cache.push(RenderFontCacheEntry{
            font: render_font.clone(),
            pt_size: pt_size,
            identifier: template.identifier.clone(),
        });
        render_font
    }
}
<|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/. */

//! Implements sequential traversal over the DOM tree.

use dom::TNode;
use traversal::{DomTraversalContext, PerLevelTraversalData};

pub fn traverse_dom<N, C>(root: N,
                          shared: &C::SharedContext)
    where N: TNode,
          C: DomTraversalContext<N>
{
    fn doit<'a, N, C>(context: &'a C, node: N, data: &mut PerLevelTraversalData)
        where N: TNode,
              C: DomTraversalContext<N>
    {
        context.process_preorder(node, data);
        if let Some(el) = node.as_element() {
            if let Some(ref mut depth) = data.current_dom_depth {
                *depth += 1;
            }

            C::traverse_children(el, |kid| doit::<N, C>(context, kid, data));

            // NB: Data is unused now, but we can always decrement the count
            // here if we need it for the post-order one :)
        }

        if context.needs_postorder_traversal() {
            context.process_postorder(node);
        }
    }

    let mut data = PerLevelTraversalData {
        current_dom_depth: None,
    };
    let context = C::new(shared, root.opaque());
    doit::<N, C>(&context, root, &mut data);

    // Clear the local LRU cache since we store stateful elements inside.
    context.local_context().style_sharing_candidate_cache.borrow_mut().clear();
}
<commit_msg>Auto merge of #14459 - heycam:seq-dom-depth, r=emilio<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/. */

//! Implements sequential traversal over the DOM tree.

use dom::TNode;
use traversal::{DomTraversalContext, PerLevelTraversalData};

pub fn traverse_dom<N, C>(root: N,
                          shared: &C::SharedContext)
    where N: TNode,
          C: DomTraversalContext<N>
{
    fn doit<'a, N, C>(context: &'a C, node: N, data: &mut PerLevelTraversalData)
        where N: TNode,
              C: DomTraversalContext<N>
    {
        context.process_preorder(node, data);
        if let Some(el) = node.as_element() {
            if let Some(ref mut depth) = data.current_dom_depth {
                *depth += 1;
            }

            C::traverse_children(el, |kid| doit::<N, C>(context, kid, data));

            if let Some(ref mut depth) = data.current_dom_depth {
                *depth -= 1;
            }
        }

        if context.needs_postorder_traversal() {
            context.process_postorder(node);
        }
    }

    let mut data = PerLevelTraversalData {
        current_dom_depth: None,
    };
    let context = C::new(shared, root.opaque());
    doit::<N, C>(&context, root, &mut data);

    // Clear the local LRU cache since we store stateful elements inside.
    context.local_context().style_sharing_candidate_cache.borrow_mut().clear();
}
<|endoftext|>


<commit_before>//!
//! The API for communicating with devices.
//!
//! This API is provided as Traits to be implemented:
//!
//! - by the low-level layers of the FoxBox, including the adapters;
//! - by test suites and tools that need to simulate connected devices.
//!
//! In turn, this API is used to implement:
//!
//! - the public-facing REST and WebSocket API;
//! - the rules API (ThinkerBell).
//!
//!

use services::*;
use selector::*;
use values::{Value, Range, TypeError};
use util::{Exactly, Id};

use std::boxed::FnBox;

/// An error that took place while communicating with either an adapter or the mechanism that
/// handles registeration of adapters.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum AdapterError {
    DuplicateGetter(Id<Getter>),
    NoSuchGetter(Id<Getter>),
    GetterDoesNotSupportPolling(Id<Getter>),
    GetterDoesNotSupportWatching(Id<Getter>),
    GetterRequiresThresholdForWatching(Id<Getter>),

    DuplicateSetter(Id<Setter>),
    NoSuchSetter(Id<Setter>),

    DuplicateService(Id<ServiceId>),
    NoSuchService(Id<ServiceId>),
    TypeError(TypeError),

    DuplicateAdapter(Id<AdapterId>),
    ConflictingAdapter(Id<AdapterId>, Id<AdapterId>),
    NoSuchAdapter(Id<AdapterId>),
    InvalidValue
}

/// An error produced by one of the APIs in this module.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum Error {
    /// There is no such service connected to the Foxbox, even indirectly.
    NoSuchService(Id<ServiceId>),

    /// There is no such getter channel connected to the Foxbox, even indirectly.
    NoSuchGetter(Id<Getter>),

    /// There is no such setter channel connected to the Foxbox, even indirectly.
    NoSuchSetter(Id<Setter>),

    /// Attempting to set a value with the wrong type.{}
    TypeError,

    /// An error arose when talking to the adapter.
    AdapterError(AdapterError),
}

/// An event during watching.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum WatchEvent {
    /// A new value is available.
    Value {
        /// The channel that sent the value.
        from: Id<Getter>,

        /// The actual value.
        value: Value
    },

    /// The set of devices being watched has changed, typically either
    /// because a tag was edited or because a device was
    /// removed. Payload is the id of the device that was removed.
    GetterRemoved(Id<Getter>),

    /// The set of devices being watched has changed, typically either
    /// because a tag was edited or because a device was
    /// added. Payload is the id of the device that was added.
    GetterAdded(Id<Getter>),
}

pub type Callback<T, E> = Box<FnBox(Result<T, E>) + Send>;
pub type Infallible<T> = Box<FnBox(T) + Send>;
pub type ResultMap<K, T, E> = Vec<(K, Result<T, E>)>;
pub type FnResultMap<K, T, E> = Box<FnBox(ResultMap<K, T, E>) + Send>;

/// A handle to the public API.
pub trait APIHandle: Send {
    /// Get the metadata on services matching some conditions.
    ///
    /// A call to `API::get_services(vec![req1, req2, ...])` will return
    /// the metadata on all services matching _either_ `req1` or `req2`
    /// or ...
    ///
    /// # REST API
    ///
    /// `GET /api/v1/services`
    ///
    /// ## Requests
    ///
    /// Any JSON that can be deserialized to a `Vec<ServiceSelector>`. See
    /// the implementation of `ServiceSelector` for details.
    ///
    /// ### Example
    ///
    /// Selector all doors in the entrance (tags `door`, `entrance`)
    /// that support setter channel `OpenClose`
    ///
    /// ```json
    /// [{
    ///   "tags": ["entrance", "door"],
    ///   "getters": [
    ///     {
    ///       "kind": {
    ///         "Exactly": {
    ///           "OpenClose": []
    ///         }
    ///       }
    ///     }
    ///   ]
    /// }]
    /// ```
    ///
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing an array of `Service`. See the implementation
    /// of `Service` for details.
    ///
    /// ### Example
    ///
    /// ```json
    /// [{
    ///   "tags": ["entrance", "door", "somevendor"],
    ///   "id: "some-service-id",
    ///   "getters": [],
    ///   "setters": [
    ///     "tags": [...],
    ///     "id": "some-channel-id",
    ///     "service": "some-service-id",
    ///     "last_seen": "some-date",
    ///     "mechanism": {
    ///       "Setter":  {
    ///         "kind": {
    ///           "OnOff": []
    ///         },
    ///         "push": [5000],
    ///         "updated": "some-date",
    ///       }
    ///     }
    ///   ]
    /// }]
    /// ```
    fn get_services(&self, Vec<ServiceSelector>, Infallible<Vec<Service>>);

    /// Label a set of services with a set of tags.
    ///
    /// A call to `API::put_service_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will label all the services matching _either_ `req1` or
    /// `req2` or ... with `tag1`, ... and return the number of services
    /// matching any of the selectors.
    ///
    /// Some of the services may already be labelled with `tag1`, or
    /// `tag2`, ... They will not change state. They are counted in
    /// the resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if services
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `POST /api/v1/services/tag`
    ///
    /// ## Getters
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```ignore
    /// {
    ///   set: Vec<ServiceSelector>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON string representing a number.
    fn add_service_tag(&self, set: Vec<ServiceSelector>, tags: Vec<String>, Infallible<usize>);

    /// Remove a set of tags from a set of services.
    ///
    /// A call to `API::delete_service_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will remove from all the services matching _either_ `req1` or
    /// `req2` or ... all of the tags `tag1`, ... and return the number of services
    /// matching any of the selectors.
    ///
    /// Some of the services may not be labelled with `tag1`, or `tag2`,
    /// ... They will not change state. They are counted in the
    /// resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if services
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `DELETE /api/v1/services/tag`
    ///
    /// ## Getters
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```ignore
    /// {
    ///   set: Vec<ServiceSelector>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn remove_service_tag(&self, set: Vec<ServiceSelector>, tags: Vec<String>, Infallible<usize>);

    /// Get a list of getters matching some conditions
    ///
    /// # REST API
    ///
    /// `GET /api/v1/channels`
    fn get_getter_channels(&self, Vec<GetterSelector>, Infallible<Vec<Channel<Getter>>>);
    fn get_setter_channels(&self, Vec<SetterSelector>, Infallible<Vec<Channel<Setter>>>);

    /// Label a set of channels with a set of tags.
    ///
    /// A call to `API::put_{getter, setter}_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will label all the channels matching _either_ `req1` or
    /// `req2` or ... with `tag1`, ... and return the number of channels
    /// matching any of the selectors.
    ///
    /// Some of the channels may already be labelled with `tag1`, or
    /// `tag2`, ... They will not change state. They are counted in
    /// the resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if channels
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `POST /api/v1/channels/tag`
    ///
    /// ## Requests
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```ignore
    /// {
    ///   set: Vec<GetterSelector>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    /// or
    /// ```ignore
    /// {
    ///   set: Vec<SetterSelector>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn add_getter_tag(&self, Vec<GetterSelector>, Vec<String>, Infallible<usize>);
    fn add_setter_tag(&self, Vec<SetterSelector>, Vec<String>, Infallible<usize>);

    /// Remove a set of tags from a set of channels.
    ///
    /// A call to `API::delete_{getter, setter}_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will remove from all the channels matching _either_ `req1` or
    /// `req2` or ... all of the tags `tag1`, ... and return the number of channels
    /// matching any of the selectors.
    ///
    /// Some of the channels may not be labelled with `tag1`, or `tag2`,
    /// ... They will not change state. They are counted in the
    /// resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if channels
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `DELETE /api/v1/channels/tag`
    ///
    /// ## Requests
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```ignore
    /// {
    ///   set: Vec<GetterSelector>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    /// or
    /// ```ignore
    /// {
    ///   set: Vec<SetterSelector>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn remove_getter_tag(&self, Vec<GetterSelector>, Vec<String>, Infallible<usize>);
    fn remove_setter_tag(&self, Vec<SetterSelector>, Vec<String>, Infallible<usize>);

    /// Read the latest value from a set of channels
    ///
    /// # REST API
    ///
    /// `GET /api/v1/channels/value`
    fn fetch_channel_values(&self, Vec<GetterSelector>, FnResultMap<Id<Getter>, Option<Value>, Error>);

    /// Send a bunch of values to a set of channels
    ///
    /// # REST API
    ///
    /// `POST /api/v1/channels/value`
    fn send_channel_values(&self, Vec<(Vec<SetterSelector>, Value)>, FnResultMap<Id<Setter>, (), Error>);

    /// Watch for any change
    ///
    /// # WebSocket API
    ///
    /// `/api/v1/channels/watch`
    fn register_channel_watch(&self, Vec<GetterSelector>, range: Exactly<Range>, cb: Box<Fn(WatchEvent) + Send + 'static>) -> Self::WatchGuard;

    /// A value that causes a disconnection once it is dropped.
    type WatchGuard;
}

<commit_msg>[fxbox/taxonomy] API::register_channel_watch is now async<commit_after>//!
//! The API for communicating with devices.
//!
//! This API is provided as Traits to be implemented:
//!
//! - by the low-level layers of the FoxBox, including the adapters;
//! - by test suites and tools that need to simulate connected devices.
//!
//! In turn, this API is used to implement:
//!
//! - the public-facing REST and WebSocket API;
//! - the rules API (ThinkerBell).
//!
//!

use services::*;
use selector::*;
use values::{Value, Range, TypeError};
use util::{Exactly, Id};

use std::boxed::FnBox;

/// An error that took place while communicating with either an adapter or the mechanism that
/// handles registeration of adapters.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum AdapterError {
    DuplicateGetter(Id<Getter>),
    NoSuchGetter(Id<Getter>),
    GetterDoesNotSupportPolling(Id<Getter>),
    GetterDoesNotSupportWatching(Id<Getter>),
    GetterRequiresThresholdForWatching(Id<Getter>),

    DuplicateSetter(Id<Setter>),
    NoSuchSetter(Id<Setter>),

    DuplicateService(Id<ServiceId>),
    NoSuchService(Id<ServiceId>),
    TypeError(TypeError),

    DuplicateAdapter(Id<AdapterId>),
    ConflictingAdapter(Id<AdapterId>, Id<AdapterId>),
    NoSuchAdapter(Id<AdapterId>),
    InvalidValue
}

/// An error produced by one of the APIs in this module.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum Error {
    /// There is no such service connected to the Foxbox, even indirectly.
    NoSuchService(Id<ServiceId>),

    /// There is no such getter channel connected to the Foxbox, even indirectly.
    NoSuchGetter(Id<Getter>),

    /// There is no such setter channel connected to the Foxbox, even indirectly.
    NoSuchSetter(Id<Setter>),

    /// Attempting to set a value with the wrong type.{}
    TypeError,

    /// An error arose when talking to the adapter.
    AdapterError(AdapterError),
}

/// An event during watching.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum WatchEvent {
    /// A new value is available.
    Value {
        /// The channel that sent the value.
        from: Id<Getter>,

        /// The actual value.
        value: Value
    },

    /// The set of devices being watched has changed, typically either
    /// because a tag was edited or because a device was
    /// removed. Payload is the id of the device that was removed.
    GetterRemoved(Id<Getter>),

    /// The set of devices being watched has changed, typically either
    /// because a tag was edited or because a device was
    /// added. Payload is the id of the device that was added.
    GetterAdded(Id<Getter>),
}

pub type Callback<T, E> = Box<FnBox(Result<T, E>) + Send>;
pub type Infallible<T> = Box<FnBox(T) + Send>;
pub type ResultMap<K, T, E> = Vec<(K, Result<T, E>)>;
pub type FnResultMap<K, T, E> = Box<FnBox(ResultMap<K, T, E>) + Send>;

/// A handle to the public API.
pub trait APIHandle: Send {
    /// Get the metadata on services matching some conditions.
    ///
    /// A call to `API::get_services(vec![req1, req2, ...])` will return
    /// the metadata on all services matching _either_ `req1` or `req2`
    /// or ...
    ///
    /// # REST API
    ///
    /// `GET /api/v1/services`
    ///
    /// ## Requests
    ///
    /// Any JSON that can be deserialized to a `Vec<ServiceSelector>`. See
    /// the implementation of `ServiceSelector` for details.
    ///
    /// ### Example
    ///
    /// Selector all doors in the entrance (tags `door`, `entrance`)
    /// that support setter channel `OpenClose`
    ///
    /// ```json
    /// [{
    ///   "tags": ["entrance", "door"],
    ///   "getters": [
    ///     {
    ///       "kind": {
    ///         "Exactly": {
    ///           "OpenClose": []
    ///         }
    ///       }
    ///     }
    ///   ]
    /// }]
    /// ```
    ///
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing an array of `Service`. See the implementation
    /// of `Service` for details.
    ///
    /// ### Example
    ///
    /// ```json
    /// [{
    ///   "tags": ["entrance", "door", "somevendor"],
    ///   "id: "some-service-id",
    ///   "getters": [],
    ///   "setters": [
    ///     "tags": [...],
    ///     "id": "some-channel-id",
    ///     "service": "some-service-id",
    ///     "last_seen": "some-date",
    ///     "mechanism": {
    ///       "Setter":  {
    ///         "kind": {
    ///           "OnOff": []
    ///         },
    ///         "push": [5000],
    ///         "updated": "some-date",
    ///       }
    ///     }
    ///   ]
    /// }]
    /// ```
    fn get_services(&self, Vec<ServiceSelector>, Infallible<Vec<Service>>);

    /// Label a set of services with a set of tags.
    ///
    /// A call to `API::put_service_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will label all the services matching _either_ `req1` or
    /// `req2` or ... with `tag1`, ... and return the number of services
    /// matching any of the selectors.
    ///
    /// Some of the services may already be labelled with `tag1`, or
    /// `tag2`, ... They will not change state. They are counted in
    /// the resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if services
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `POST /api/v1/services/tag`
    ///
    /// ## Getters
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```ignore
    /// {
    ///   set: Vec<ServiceSelector>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON string representing a number.
    fn add_service_tag(&self, set: Vec<ServiceSelector>, tags: Vec<String>, Infallible<usize>);

    /// Remove a set of tags from a set of services.
    ///
    /// A call to `API::delete_service_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will remove from all the services matching _either_ `req1` or
    /// `req2` or ... all of the tags `tag1`, ... and return the number of services
    /// matching any of the selectors.
    ///
    /// Some of the services may not be labelled with `tag1`, or `tag2`,
    /// ... They will not change state. They are counted in the
    /// resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if services
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `DELETE /api/v1/services/tag`
    ///
    /// ## Getters
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```ignore
    /// {
    ///   set: Vec<ServiceSelector>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn remove_service_tag(&self, set: Vec<ServiceSelector>, tags: Vec<String>, Infallible<usize>);

    /// Get a list of getters matching some conditions
    ///
    /// # REST API
    ///
    /// `GET /api/v1/channels`
    fn get_getter_channels(&self, Vec<GetterSelector>, Infallible<Vec<Channel<Getter>>>);
    fn get_setter_channels(&self, Vec<SetterSelector>, Infallible<Vec<Channel<Setter>>>);

    /// Label a set of channels with a set of tags.
    ///
    /// A call to `API::put_{getter, setter}_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will label all the channels matching _either_ `req1` or
    /// `req2` or ... with `tag1`, ... and return the number of channels
    /// matching any of the selectors.
    ///
    /// Some of the channels may already be labelled with `tag1`, or
    /// `tag2`, ... They will not change state. They are counted in
    /// the resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if channels
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `POST /api/v1/channels/tag`
    ///
    /// ## Requests
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```ignore
    /// {
    ///   set: Vec<GetterSelector>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    /// or
    /// ```ignore
    /// {
    ///   set: Vec<SetterSelector>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn add_getter_tag(&self, Vec<GetterSelector>, Vec<String>, Infallible<usize>);
    fn add_setter_tag(&self, Vec<SetterSelector>, Vec<String>, Infallible<usize>);

    /// Remove a set of tags from a set of channels.
    ///
    /// A call to `API::delete_{getter, setter}_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will remove from all the channels matching _either_ `req1` or
    /// `req2` or ... all of the tags `tag1`, ... and return the number of channels
    /// matching any of the selectors.
    ///
    /// Some of the channels may not be labelled with `tag1`, or `tag2`,
    /// ... They will not change state. They are counted in the
    /// resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if channels
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `DELETE /api/v1/channels/tag`
    ///
    /// ## Requests
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```ignore
    /// {
    ///   set: Vec<GetterSelector>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    /// or
    /// ```ignore
    /// {
    ///   set: Vec<SetterSelector>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn remove_getter_tag(&self, Vec<GetterSelector>, Vec<String>, Infallible<usize>);
    fn remove_setter_tag(&self, Vec<SetterSelector>, Vec<String>, Infallible<usize>);

    /// Read the latest value from a set of channels
    ///
    /// # REST API
    ///
    /// `GET /api/v1/channels/value`
    fn fetch_channel_values(&self, Vec<GetterSelector>, FnResultMap<Id<Getter>, Option<Value>, Error>);

    /// Send a bunch of values to a set of channels
    ///
    /// # REST API
    ///
    /// `POST /api/v1/channels/value`
    fn send_channel_values(&self, Vec<(Vec<SetterSelector>, Value)>, FnResultMap<Id<Setter>, (), Error>);

    /// Watch for any change
    ///
    /// # WebSocket API
    ///
    /// `/api/v1/channels/watch`
    fn register_channel_watch(&self, selectors: Vec<GetterSelector>, range: Exactly<Range>, on_event: Box<Fn(WatchEvent) + Send + 'static>, cb: Infallible<Self::WatchGuard>);

    /// A value that causes a disconnection once it is dropped.
    type WatchGuard;
}

<|endoftext|>


<commit_before>use std::time::Duration;

extern crate chrono;
use chrono::{DateTime, UTC};

///
/// Hubs
///

pub type HubId = String;

/// Metadata on a hub
#[derive(Debug)]
pub struct Hub {
    tags: Vec<String>,

    /// An id unique to this hub.
    id: HubId,
}

///
/// Endpoints
///

pub type EndPointId = String;

#[derive(Debug)]
pub enum IO {
    /// This endpoint supports inputs.
    Input {
        /// If `Some(duration)`, this endpoint can be polled, i.e. it
        /// will respond when the FoxBox requests the latest value.
        /// Parameter `duration` indicates the smallest interval
        /// between two updates.
        ///
        /// Otherwise, the endpoint cannot be polled and will push
        /// data to the FoxBox when it is available.
        ///
        /// # Examples
        ///
        /// - Long-running pollution or humidity sensors typically
        ///   do not accept requests and rather send batches of
        ///   data every 24h.
        poll: Option<Duration>,

        /// If `Some(duration)`, this endpoint can send the data to
        /// the FoxBox whenever it is updated. Parameter `duration`
        /// indicates the smallest interval between two updates.
        ///
        /// Otherwise, the endpoint cannot send data to the FoxBox
        /// and needs to be polled.
        trigger: Option<Duration>,

        /// Date at which the latest value was received, whether through
        /// polling or through a trigger.
        updated: DateTime<UTC>,
    },
    Output {
        /// If `Some(duration)`, this endpoint supports pushing,
        /// i.e. the FoxBox can send values.
        push: Option<Duration>,

        /// Date at which the latest value was sent to the endpoint.
        updated: DateTime<UTC>,
    }
}

/// An endpoint represents a single place where data can enter or
/// leave a device.
#[derive(Debug)]
pub struct Endpoint {
    /// Tags describing the endpoint.
    ///
    /// These tags can be set by the user, adapters or
    /// applications. They are used to regroup endpoints for rules.
    ///
    /// For instance "entrance".
    tags: Vec<String>,

    /// An id unique to this endpoint.
    id: EndPointId,

    io: IO,
}
<commit_msg>[fxbox/taxonomy] Adding kinds<commit_after>extern crate chrono;

///
/// Hubs
///

pub type HubId = String;

/// A hub represents a node to which several endpoints, as well as
/// other hubs can be connected. The FoxBox is the root hub. Simple
/// devices that can do a single thing (e.g. a button) are endpoints,
/// while complex devices containing several sensors or effectors are
/// also hubs, in which each sensor and each effector is an endpoint.
#[derive(Debug, Clone)]
pub struct Hub {
    /// Tags describing the hub.
    ///
    /// These tags can be set by the user, adapters or
    /// applications. They are used by applications.
    ///
    /// For instance "entrance".
    tags: Vec<String>,

    /// An id unique to this hub.
    id: HubId,

    /// Hubs depending on this hub.
    subhubs: Vec<Hub>,

    /// Endpoints connected directly to this hub.
    endpoints: Vec<EndPoint>,
}

///
/// Endpoints
///

pub type EndPointId = String;

/// The kind of value provided by an endpoint.
#[derive(Debug, Clone)]
pub struct ValueKind {
    /// The vendor. An empty string for standardized value kinds,
    /// otherwise a string identifying the owner of this non-standard
    /// value (e.g. "Mozilla")
    vendor: String,

    /// Identification of the adapter providing this kind of value.
    adapter: String,

    /// The nature of the value.
    ///
    /// For instance: "is-on", "is-open".
    nature: String,

    /// The data type of the value.
    typ: Type
}

#[derive(Debug, Clone)]
pub enum IO {
    /// This endpoint supports inputs.
    Input {
        /// The kind of value that can be obtained from this endpoint.
        kind: ValueKind,

        /// If `Some(duration)`, this endpoint can be polled, i.e. it
        /// will respond when the FoxBox requests the latest value.
        /// Parameter `duration` indicates the smallest interval
        /// between two updates.
        ///
        /// Otherwise, the endpoint cannot be polled and will push
        /// data to the FoxBox when it is available.
        ///
        /// # Examples
        ///
        /// - Long-running pollution or humidity sensors typically
        ///   do not accept requests and rather send batches of
        ///   data every 24h.
        poll: Option<std::time::Duration>,

        /// If `Some(duration)`, this endpoint can send the data to
        /// the FoxBox whenever it is updated. Parameter `duration`
        /// indicates the smallest interval between two updates.
        ///
        /// Otherwise, the endpoint cannot send data to the FoxBox
        /// and needs to be polled.
        trigger: Option<std::time::Duration>,

        /// Date at which the latest value was received, whether through
        /// polling or through a trigger.
        updated: chrono::DateTime<chrono::UTC>,
    },
    Output {
        /// The kind of value that can be sent to this endpoint.
        kind: ValueKind,

        /// If `Some(duration)`, this endpoint supports pushing,
        /// i.e. the FoxBox can send values.
        push: Option<std::time::Duration>,

        /// Date at which the latest value was sent to the endpoint.
        updated: chrono::DateTime<chrono::UTC>,
    }
}

/// An endpoint represents a single place where data can enter or
/// leave a device. Note that endpoints support either a single kind
/// of input or a single kind of output. Devices that support both
/// inputs or outputs, or several kinds of inputs, or several kinds of
/// outputs, are represented as hubs containing several endpoints.
#[derive(Debug, Clone)]
pub struct EndPoint {
    /// Tags describing the endpoint.
    ///
    /// These tags can be set by the user, adapters or
    /// applications. They are used to regroup endpoints for rules.
    ///
    /// For instance "entrance".
    tags: Vec<String>,

    /// An id unique to this endpoint.
    id: EndPointId,

    /// The update mechanism for this endpoint.
    mechanism: IO,

    /// The last time the device was seen.
    last_seen: chrono::DateTime<chrono::UTC>,
}

///
/// Values
///

#[derive(Debug, Clone)]
pub enum Type {
    ///
    /// # Trivial values
    ///

    /// An empty value. Used for instance to inform that a countdown
    /// has reached 0 or that a device is ready.
    Unit,

    /// A boolean. Used for instance for on-off switches, presence
    /// detectors, etc.
    Bool,

    ///
    /// # Time
    ///

    /// A duration. Used for instance in countdowns.
    Duration,

    /// A precise timestamp. Used for instance to determine when an
    /// event has taken place.
    TimeStamp,

    ///
    /// ...
    ///
    Color,
}

<|endoftext|>


<commit_before>// Copyright 2018 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.

use session::config::Options;

use std::fs;
use std::io::{self, StdoutLock, Write};
use std::time::Instant;

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum ProfileCategory {
    Parsing,
    Expansion,
    TypeChecking,
    BorrowChecking,
    Codegen,
    Linking,
    Other,
}

struct Categories<T> {
    parsing: T,
    expansion: T,
    type_checking: T,
    borrow_checking: T,
    codegen: T,
    linking: T,
    other: T,
}

impl<T: Default> Categories<T> {
    fn new() -> Categories<T> {
        Categories {
            parsing: T::default(),
            expansion: T::default(),
            type_checking: T::default(),
            borrow_checking: T::default(),
            codegen: T::default(),
            linking: T::default(),
            other: T::default(),
        }
    }
}

impl<T> Categories<T> {
    fn get(&self, category: ProfileCategory) -> &T {
        match category {
            ProfileCategory::Parsing => &self.parsing,
            ProfileCategory::Expansion => &self.expansion,
            ProfileCategory::TypeChecking => &self.type_checking,
            ProfileCategory::BorrowChecking => &self.borrow_checking,
            ProfileCategory::Codegen => &self.codegen,
            ProfileCategory::Linking => &self.linking,
            ProfileCategory::Other => &self.other,
        }
    }

    fn set(&mut self, category: ProfileCategory, value: T) {
        match category {
            ProfileCategory::Parsing => self.parsing = value,
            ProfileCategory::Expansion => self.expansion = value,
            ProfileCategory::TypeChecking => self.type_checking = value,
            ProfileCategory::BorrowChecking => self.borrow_checking = value,
            ProfileCategory::Codegen => self.codegen = value,
            ProfileCategory::Linking => self.linking = value,
            ProfileCategory::Other => self.other = value,
        }
    }
}

struct CategoryData {
    times: Categories<u64>,
    query_counts: Categories<(u64, u64)>,
}

impl CategoryData {
    fn new() -> CategoryData {
        CategoryData {
            times: Categories::new(),
            query_counts: Categories::new(),
        }
    }

    fn print(&self, lock: &mut StdoutLock) {
        macro_rules! p {
            ($name:tt, $rustic_name:ident) => {
                let (hits, total) = self.query_counts.$rustic_name;
                let (hits, total) = if total > 0 {
                    (format!("{:.2}",
                     (((hits as f32) / (total as f32)) * 100.0)), total.to_string())
                } else {
                    ("".into(), "".into())
                };

                writeln!(
                   lock,
                   "| {0: <16} | {1: <14} | {2: <14} | {3: <8} |",
                   $name,
                   self.times.$rustic_name / 1_000_000,
                   total,
                   hits
                ).unwrap();
            };
        }

        writeln!(lock, "| Phase            | Time (ms)      | Queries        | Hits (%) |")
            .unwrap();
        writeln!(lock, "| ---------------- | -------------- | -------------- | -------- |")
            .unwrap();

        p!("Parsing", parsing);
        p!("Expansion", expansion);
        p!("TypeChecking", type_checking);
        p!("BorrowChecking", borrow_checking);
        p!("Codegen", codegen);
        p!("Linking", linking);
        p!("Other", other);
    }

    fn json(&self) -> String {
        macro_rules! j {
            ($category:tt, $rustic_name:ident) => {{
                let (hits, total) = self.query_counts.$rustic_name;

                format!(
                    "{{ \"category\": {}, \"time_ms\": {},
                        \"query_count\": {}, \"query_hits\": {} }}",
                    stringify!($category),
                    self.times.$rustic_name / 1_000_000,
                    total,
                    format!("{:.2}", (((hits as f32) / (total as f32)) * 100.0))
                )
            }}
        }

        format!("[
            {},
            {},
            {},
            {},
            {},
            {},
            {}
        ]",
            j!("Parsing", parsing),
            j!("Expansion", expansion),
            j!("TypeChecking", type_checking),
            j!("BorrowChecking", borrow_checking),
            j!("Codegen", codegen),
            j!("Linking", linking),
            j!("Other", other)
        )
    }
}

pub struct SelfProfiler {
    timer_stack: Vec<ProfileCategory>,
    data: CategoryData,
    current_timer: Instant,
}

impl SelfProfiler {
    pub fn new() -> SelfProfiler {
        let mut profiler = SelfProfiler {
            timer_stack: Vec::new(),
            data: CategoryData::new(),
            current_timer: Instant::now(),
        };

        profiler.start_activity(ProfileCategory::Other);

        profiler
    }

    pub fn start_activity(&mut self, category: ProfileCategory) {
        match self.timer_stack.last().cloned() {
            None => {
                self.current_timer = Instant::now();
            },
            Some(current_category) if current_category == category => {
                //since the current category is the same as the new activity's category,
                //we don't need to do anything with the timer, we just need to push it on the stack
            }
            Some(current_category) => {
                let elapsed = self.stop_timer();

                //record the current category's time
                let new_time = self.data.times.get(current_category) + elapsed;
                self.data.times.set(current_category, new_time);
            }
        }

        //push the new category
        self.timer_stack.push(category);
    }

    pub fn record_query(&mut self, category: ProfileCategory) {
        let (hits, total) = *self.data.query_counts.get(category);
        self.data.query_counts.set(category, (hits, total + 1));
    }

    pub fn record_query_hit(&mut self, category: ProfileCategory) {
        let (hits, total) = *self.data.query_counts.get(category);
        self.data.query_counts.set(category, (hits + 1, total));
    }

    pub fn end_activity(&mut self, category: ProfileCategory) {
        match self.timer_stack.pop() {
            None => bug!("end_activity() was called but there was no running activity"),
            Some(c) =>
                assert!(
                    c == category,
                    "end_activity() was called but a different activity was running"),
        }

        //check if the new running timer is in the same category as this one
        //if it is, we don't need to do anything
        if let Some(c) = self.timer_stack.last() {
            if *c == category {
                return;
            }
        }

        //the new timer is different than the previous,
        //so record the elapsed time and start a new timer
        let elapsed = self.stop_timer();
        let new_time = self.data.times.get(category) + elapsed;
        self.data.times.set(category, new_time);
    }

    fn stop_timer(&mut self) -> u64 {
        let elapsed = self.current_timer.elapsed();

        self.current_timer = Instant::now();

        (elapsed.as_secs() * 1_000_000_000) + (elapsed.subsec_nanos() as u64)
    }

    pub fn print_results(&mut self, opts: &Options) {
        self.end_activity(ProfileCategory::Other);

        assert!(
            self.timer_stack.is_empty(),
            "there were timers running when print_results() was called");

        let out = io::stdout();
        let mut lock = out.lock();

        let crate_name =
            opts.crate_name
            .as_ref()
            .map(|n| format!(" for {}", n))
            .unwrap_or_default();

        writeln!(lock, "Self profiling results{}:", crate_name).unwrap();
        writeln!(lock).unwrap();

        self.data.print(&mut lock);

        writeln!(lock).unwrap();
        writeln!(lock, "Optimization level: {:?}", opts.optimize).unwrap();

        let incremental = if opts.incremental.is_some() { "on" } else { "off" };
        writeln!(lock, "Incremental: {}", incremental).unwrap();
    }

    pub fn save_results(&self, opts: &Options) {
        let category_data = self.data.json();
        let compilation_options =
            format!("{{ \"optimization_level\": \"{:?}\", \"incremental\": {} }}",
                    opts.optimize,
                    if opts.incremental.is_some() { "true" } else { "false" });

        let json = format!("{{ \"category_data\": {}, \"compilation_options\": {} }}",
                        category_data,
                        compilation_options);

        fs::write("self_profiler_results.json", json).unwrap();
    }
}
<commit_msg>Generate self-profiler types with macros<commit_after>// Copyright 2018 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.

use session::config::Options;

use std::fs;
use std::io::{self, StdoutLock, Write};
use std::time::Instant;

macro_rules! define_categories {
    ($($name:ident,)*) => {
        #[derive(Clone, Copy, Debug, PartialEq, Eq)]
        pub enum ProfileCategory {
            $($name),*
        }

        #[allow(bad_style)]
        struct Categories<T> {
            $($name: T),*
        }

        impl<T: Default> Categories<T> {
            fn new() -> Categories<T> {
                Categories {
                    $($name: T::default()),*
                }
            }
        }

        impl<T> Categories<T> {
            fn get(&self, category: ProfileCategory) -> &T {
                match category {
                    $(ProfileCategory::$name => &self.$name),*
                }
            }

            fn set(&mut self, category: ProfileCategory, value: T) {
                match category {
                    $(ProfileCategory::$name => self.$name = value),*
                }
            }
        }

        struct CategoryData {
            times: Categories<u64>,
            query_counts: Categories<(u64, u64)>,
        }

        impl CategoryData {
            fn new() -> CategoryData {
                CategoryData {
                    times: Categories::new(),
                    query_counts: Categories::new(),
                }
            }

            fn print(&self, lock: &mut StdoutLock) {
                writeln!(lock, "| Phase            | Time (ms)      | Queries        | Hits (%) |")
                    .unwrap();
                writeln!(lock, "| ---------------- | -------------- | -------------- | -------- |")
                    .unwrap();

                $(
                    let (hits, total) = self.query_counts.$name;
                    let (hits, total) = if total > 0 {
                        (format!("{:.2}",
                        (((hits as f32) / (total as f32)) * 100.0)), total.to_string())
                    } else {
                        ("".into(), "".into())
                    };

                    writeln!(
                        lock,
                        "| {0: <16} | {1: <14} | {2: <14} | {3: <8} |",
                        stringify!($name),
                        self.times.$name / 1_000_000,
                        total,
                        hits
                    ).unwrap();
                )*
            }

            fn json(&self) -> String {
                let mut json = String::from("[");

                $(
                    let (hits, total) = self.query_counts.$name;

                    json.push_str(&format!(
                        "{{ \"category\": {}, \"time_ms\": {},
                            \"query_count\": {}, \"query_hits\": {} }}",
                        stringify!($name),
                        self.times.$name / 1_000_000,
                        total,
                        format!("{:.2}", (((hits as f32) / (total as f32)) * 100.0))
                    ));
                )*

                json.push(']');

                json
            }
        }
    }
}

define_categories! {
    Parsing,
    Expansion,
    TypeChecking,
    BorrowChecking,
    Codegen,
    Linking,
    Other,
}

pub struct SelfProfiler {
    timer_stack: Vec<ProfileCategory>,
    data: CategoryData,
    current_timer: Instant,
}

impl SelfProfiler {
    pub fn new() -> SelfProfiler {
        let mut profiler = SelfProfiler {
            timer_stack: Vec::new(),
            data: CategoryData::new(),
            current_timer: Instant::now(),
        };

        profiler.start_activity(ProfileCategory::Other);

        profiler
    }

    pub fn start_activity(&mut self, category: ProfileCategory) {
        match self.timer_stack.last().cloned() {
            None => {
                self.current_timer = Instant::now();
            },
            Some(current_category) if current_category == category => {
                //since the current category is the same as the new activity's category,
                //we don't need to do anything with the timer, we just need to push it on the stack
            }
            Some(current_category) => {
                let elapsed = self.stop_timer();

                //record the current category's time
                let new_time = self.data.times.get(current_category) + elapsed;
                self.data.times.set(current_category, new_time);
            }
        }

        //push the new category
        self.timer_stack.push(category);
    }

    pub fn record_query(&mut self, category: ProfileCategory) {
        let (hits, total) = *self.data.query_counts.get(category);
        self.data.query_counts.set(category, (hits, total + 1));
    }

    pub fn record_query_hit(&mut self, category: ProfileCategory) {
        let (hits, total) = *self.data.query_counts.get(category);
        self.data.query_counts.set(category, (hits + 1, total));
    }

    pub fn end_activity(&mut self, category: ProfileCategory) {
        match self.timer_stack.pop() {
            None => bug!("end_activity() was called but there was no running activity"),
            Some(c) =>
                assert!(
                    c == category,
                    "end_activity() was called but a different activity was running"),
        }

        //check if the new running timer is in the same category as this one
        //if it is, we don't need to do anything
        if let Some(c) = self.timer_stack.last() {
            if *c == category {
                return;
            }
        }

        //the new timer is different than the previous,
        //so record the elapsed time and start a new timer
        let elapsed = self.stop_timer();
        let new_time = self.data.times.get(category) + elapsed;
        self.data.times.set(category, new_time);
    }

    fn stop_timer(&mut self) -> u64 {
        let elapsed = self.current_timer.elapsed();

        self.current_timer = Instant::now();

        (elapsed.as_secs() * 1_000_000_000) + (elapsed.subsec_nanos() as u64)
    }

    pub fn print_results(&mut self, opts: &Options) {
        self.end_activity(ProfileCategory::Other);

        assert!(
            self.timer_stack.is_empty(),
            "there were timers running when print_results() was called");

        let out = io::stdout();
        let mut lock = out.lock();

        let crate_name =
            opts.crate_name
            .as_ref()
            .map(|n| format!(" for {}", n))
            .unwrap_or_default();

        writeln!(lock, "Self profiling results{}:", crate_name).unwrap();
        writeln!(lock).unwrap();

        self.data.print(&mut lock);

        writeln!(lock).unwrap();
        writeln!(lock, "Optimization level: {:?}", opts.optimize).unwrap();

        let incremental = if opts.incremental.is_some() { "on" } else { "off" };
        writeln!(lock, "Incremental: {}", incremental).unwrap();
    }

    pub fn save_results(&self, opts: &Options) {
        let category_data = self.data.json();
        let compilation_options =
            format!("{{ \"optimization_level\": \"{:?}\", \"incremental\": {} }}",
                    opts.optimize,
                    if opts.incremental.is_some() { "true" } else { "false" });

        let json = format!("{{ \"category_data\": {}, \"compilation_options\": {} }}",
                        category_data,
                        compilation_options);

        fs::write("self_profiler_results.json", json).unwrap();
    }
}
<|endoftext|>


<commit_before>//! Platform-specific extensions to `std` for Unix platforms.
//!
//! Provides access to platform-level information on Unix platforms, and
//! exposes Unix-specific functions that would otherwise be inappropriate as
//! part of the core `std` library.
//!
//! It exposes more ways to deal with platform-specific strings (`OsStr`,
//! `OsString`), allows to set permissions more granularly, extract low-level
//! file descriptors from files and sockets, and has platform-specific helpers
//! for spawning processes.
//!
//! # Examples
//!
//! ```no_run
//! use std::fs::File;
//! use std::os::unix::prelude::*;
//!
//! fn main() {
//!     let f = File::create("foo.txt")?;
//!     let fd = f.as_raw_fd();
//!
//!     // use fd with native unix bindings
//! }
//! ```

#![stable(feature = "rust1", since = "1.0.0")]
#![doc(cfg(unix))]
#![allow(missing_docs)]

pub mod io;
pub mod ffi;
pub mod fs;
pub mod process;
pub mod raw;
pub mod thread;
pub mod net;

/// A prelude for conveniently writing platform-specific code.
///
/// Includes all extension traits, and some important type definitions.
#[stable(feature = "rust1", since = "1.0.0")]
pub mod prelude {
    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd};
    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::ffi::{OsStrExt, OsStringExt};
    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::fs::{PermissionsExt, OpenOptionsExt, MetadataExt, FileTypeExt};
    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::fs::DirEntryExt;
    #[doc(no_inline)] #[stable(feature = "file_offset", since = "1.15.0")]
    pub use super::fs::FileExt;
    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::thread::JoinHandleExt;
    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::process::{CommandExt, ExitStatusExt};
}
<commit_msg>Also fix the signature of main in std::sys::unix::ext<commit_after>//! Platform-specific extensions to `std` for Unix platforms.
//!
//! Provides access to platform-level information on Unix platforms, and
//! exposes Unix-specific functions that would otherwise be inappropriate as
//! part of the core `std` library.
//!
//! It exposes more ways to deal with platform-specific strings (`OsStr`,
//! `OsString`), allows to set permissions more granularly, extract low-level
//! file descriptors from files and sockets, and has platform-specific helpers
//! for spawning processes.
//!
//! # Examples
//!
//! ```no_run
//! use std::fs::File;
//! use std::os::unix::prelude::*;
//!
//! fn main() -> std::io::Result<()> {
//!     let f = File::create("foo.txt")?;
//!     let fd = f.as_raw_fd();
//!
//!     // use fd with native unix bindings
//!
//!     Ok(())
//! }
//! ```

#![stable(feature = "rust1", since = "1.0.0")]
#![doc(cfg(unix))]
#![allow(missing_docs)]

pub mod io;
pub mod ffi;
pub mod fs;
pub mod process;
pub mod raw;
pub mod thread;
pub mod net;

/// A prelude for conveniently writing platform-specific code.
///
/// Includes all extension traits, and some important type definitions.
#[stable(feature = "rust1", since = "1.0.0")]
pub mod prelude {
    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd};
    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::ffi::{OsStrExt, OsStringExt};
    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::fs::{PermissionsExt, OpenOptionsExt, MetadataExt, FileTypeExt};
    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::fs::DirEntryExt;
    #[doc(no_inline)] #[stable(feature = "file_offset", since = "1.15.0")]
    pub use super::fs::FileExt;
    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::thread::JoinHandleExt;
    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::process::{CommandExt, ExitStatusExt};
}
<|endoftext|>


<commit_before>//! # Daemon abstraction
//! This is documentation for the `daemon` module.
//!
//! Lorem Ipsum
//! functionality for building portable Rust software.

extern crate syslog;

use ::probing::Probe;
use std::thread::{spawn, sleep};
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::Duration;
use std::sync::{Arc};
use ::logging::{Logger};
use ::base::{Config};
use logging::logger::syslog::Severity as Severity;
static CPU_ANTI_HOG_MILLIS_OFFSET: u64 = 100;

#[derive(Debug)]
pub struct Worker {
    logger: Logger,
    ops: Arc<Vec<Box<Probe>>>,
    config: Config,
    should_stop: Arc<AtomicBool>,
}

impl Worker {
    pub fn new(
        logger: Logger,
        operations: Arc<Vec<Box<Probe>>>,
        c: Config
    ) -> Worker {
        Worker {
            logger: logger,
            ops: operations,
            config: c,
            should_stop: Arc::new(AtomicBool::new(false))
        }
    }

    pub fn stop(&self) -> () {
        self.should_stop.store(true, Ordering::SeqCst);
    }

    pub fn start(&self) -> () {
        let a_len = self.ops.len();
        for i in 0..a_len {
            let ops = self.ops.clone();
            let logger = self.logger.clone();
            let timeout = self.config.get_timeout() + CPU_ANTI_HOG_MILLIS_OFFSET;
            let stop_bool = self.should_stop.clone();
            spawn(move || {
                loop {
                    if stop_bool.load(Ordering::SeqCst) {
                        let msg = format!("@Thread: {} - terminating", ops[i].get_thread_id());
                        logger.log(Severity::LOG_INFO, &msg);
                        break
                    }
                    ops[i].exec();
                    sleep(Duration::from_millis(timeout));
                }
            });
        }
    }
}

impl Drop for Worker {
    fn drop(&mut self) {

        let msg = format!("Worker drop, <free({:?}>)", self);
        self.logger.log(Severity::LOG_INFO, &msg);
    }
}<commit_msg>you know TODO<commit_after>//! # Daemon abstraction
//! This is documentation for the `daemon` module.
//!
//! Lorem Ipsum
//! functionality for building portable Rust software.

extern crate syslog;

use ::probing::Probe;
use std::thread::{spawn, sleep};
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::Duration;
use std::sync::{Arc};
use ::logging::{Logger};
use ::base::{Config};
use logging::logger::syslog::Severity as Severity;
static CPU_ANTI_HOG_MILLIS_OFFSET: u64 = 100;

#[derive(Debug)]
pub struct Worker {
    logger: Logger,
    ops: Arc<Vec<Box<Probe>>>,
    config: Config,
    should_stop: Arc<AtomicBool>,
}

impl Worker {
    pub fn new(
        logger: Logger,
        operations: Arc<Vec<Box<Probe>>>,
        c: Config
    ) -> Worker {
        Worker {
            logger: logger,
            ops: operations,
            config: c,
            should_stop: Arc::new(AtomicBool::new(false))
        }
    }

    pub fn stop(&self) -> () {
        self.should_stop.store(true, Ordering::SeqCst);
    }

    pub fn start(&self) -> () {
        let a_len = self.ops.len();
        for i in 0..a_len {
            let ops = self.ops.clone();
            let logger = self.logger.clone();
            let timeout = self.config.get_timeout() + CPU_ANTI_HOG_MILLIS_OFFSET;
            let stop_bool = self.should_stop.clone();
            spawn(move || {
                loop {
                    if stop_bool.load(Ordering::SeqCst) {
                        let msg = format!("@Thread: {} - terminating", ops[i].get_thread_id());
                        logger.log(Severity::LOG_INFO, &msg);
                        break
                    }
                    //TODO timeout warn, probes without loops check?
                    ops[i].exec();
                    sleep(Duration::from_millis(timeout));
                }
            });
        }
    }
}

impl Drop for Worker {
    fn drop(&mut self) {

        let msg = format!("Worker drop, <free({:?}>)", self);
        self.logger.log(Severity::LOG_INFO, &msg);
    }
}<|endoftext|>


<commit_before>// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

use lazy_static::lazy_static;
use parking_lot::Mutex;
use std::borrow::Cow;
use std::mem;
use std::ptr::NonNull;
use std::sync::atomic::AtomicIsize;
use std::sync::atomic::Ordering::SeqCst;

const NB_BUCKETS: usize = 1 << 12; // 4096
const BUCKET_MASK: u32 = (1 << 12) - 1;

pub(crate) struct Set {
    buckets: Box<[Option<Box<Entry>>; NB_BUCKETS]>,
}

pub(crate) struct Entry {
    pub(crate) string: Box<str>,
    pub(crate) hash: u32,
    pub(crate) ref_count: AtomicIsize,
    next_in_bucket: Option<Box<Entry>>,
}

// Addresses are a multiples of this,
// and therefore have have TAG_MASK bits unset, available for tagging.
pub(crate) const ENTRY_ALIGNMENT: usize = 4;

#[test]
fn entry_alignment_is_sufficient() {
    assert!(mem::align_of::<Entry>() >= ENTRY_ALIGNMENT);
}

lazy_static! {
    pub(crate) static ref DYNAMIC_SET: Mutex<Set> = Mutex::new({
        type T = Option<Box<Entry>>;
        let _static_assert_size_eq = std::mem::transmute::<T, usize>;
        let vec = std::mem::ManuallyDrop::new(vec![0_usize; NB_BUCKETS]);
        Set {
            buckets: unsafe { Box::from_raw(vec.as_ptr() as *mut [T; NB_BUCKETS]) },
        }
    });
}

impl Set {
    pub(crate) fn insert(&mut self, string: Cow<str>, hash: u32) -> NonNull<Entry> {
        let bucket_index = (hash & BUCKET_MASK) as usize;
        {
            let mut ptr: Option<&mut Box<Entry>> = self.buckets[bucket_index].as_mut();

            while let Some(entry) = ptr.take() {
                if entry.hash == hash && *entry.string == *string {
                    if entry.ref_count.fetch_add(1, SeqCst) > 0 {
                        return NonNull::from(&mut **entry);
                    }
                    // Uh-oh. The pointer's reference count was zero, which means someone may try
                    // to free it. (Naive attempts to defend against this, for example having the
                    // destructor check to see whether the reference count is indeed zero, don't
                    // work due to ABA.) Thus we need to temporarily add a duplicate string to the
                    // list.
                    entry.ref_count.fetch_sub(1, SeqCst);
                    break;
                }
                ptr = entry.next_in_bucket.as_mut();
            }
        }
        debug_assert!(mem::align_of::<Entry>() >= ENTRY_ALIGNMENT);
        let string = string.into_owned();
        let mut entry = Box::new(Entry {
            next_in_bucket: self.buckets[bucket_index].take(),
            hash,
            ref_count: AtomicIsize::new(1),
            string: string.into_boxed_str(),
        });
        let ptr = NonNull::from(&mut *entry);
        self.buckets[bucket_index] = Some(entry);

        ptr
    }

    pub(crate) fn remove(&mut self, ptr: *mut Entry) {
        let bucket_index = {
            let value: &Entry = unsafe { &*ptr };
            debug_assert!(value.ref_count.load(SeqCst) == 0);
            (value.hash & BUCKET_MASK) as usize
        };

        let mut current: &mut Option<Box<Entry>> = &mut self.buckets[bucket_index];

        loop {
            let entry_ptr: *mut Entry = match current.as_mut() {
                Some(entry) => &mut **entry,
                None => break,
            };
            if entry_ptr == ptr {
                mem::drop(mem::replace(current, unsafe {
                    (*entry_ptr).next_in_bucket.take()
                }));
                break;
            }
            current = unsafe { &mut (*entry_ptr).next_in_bucket };
        }
    }
}
<commit_msg>Convert manual loop to `while let`<commit_after>// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

use lazy_static::lazy_static;
use parking_lot::Mutex;
use std::borrow::Cow;
use std::mem;
use std::ptr::NonNull;
use std::sync::atomic::AtomicIsize;
use std::sync::atomic::Ordering::SeqCst;

const NB_BUCKETS: usize = 1 << 12; // 4096
const BUCKET_MASK: u32 = (1 << 12) - 1;

pub(crate) struct Set {
    buckets: Box<[Option<Box<Entry>>; NB_BUCKETS]>,
}

pub(crate) struct Entry {
    pub(crate) string: Box<str>,
    pub(crate) hash: u32,
    pub(crate) ref_count: AtomicIsize,
    next_in_bucket: Option<Box<Entry>>,
}

// Addresses are a multiples of this,
// and therefore have have TAG_MASK bits unset, available for tagging.
pub(crate) const ENTRY_ALIGNMENT: usize = 4;

#[test]
fn entry_alignment_is_sufficient() {
    assert!(mem::align_of::<Entry>() >= ENTRY_ALIGNMENT);
}

lazy_static! {
    pub(crate) static ref DYNAMIC_SET: Mutex<Set> = Mutex::new({
        type T = Option<Box<Entry>>;
        let _static_assert_size_eq = std::mem::transmute::<T, usize>;
        let vec = std::mem::ManuallyDrop::new(vec![0_usize; NB_BUCKETS]);
        Set {
            buckets: unsafe { Box::from_raw(vec.as_ptr() as *mut [T; NB_BUCKETS]) },
        }
    });
}

impl Set {
    pub(crate) fn insert(&mut self, string: Cow<str>, hash: u32) -> NonNull<Entry> {
        let bucket_index = (hash & BUCKET_MASK) as usize;
        {
            let mut ptr: Option<&mut Box<Entry>> = self.buckets[bucket_index].as_mut();

            while let Some(entry) = ptr.take() {
                if entry.hash == hash && *entry.string == *string {
                    if entry.ref_count.fetch_add(1, SeqCst) > 0 {
                        return NonNull::from(&mut **entry);
                    }
                    // Uh-oh. The pointer's reference count was zero, which means someone may try
                    // to free it. (Naive attempts to defend against this, for example having the
                    // destructor check to see whether the reference count is indeed zero, don't
                    // work due to ABA.) Thus we need to temporarily add a duplicate string to the
                    // list.
                    entry.ref_count.fetch_sub(1, SeqCst);
                    break;
                }
                ptr = entry.next_in_bucket.as_mut();
            }
        }
        debug_assert!(mem::align_of::<Entry>() >= ENTRY_ALIGNMENT);
        let string = string.into_owned();
        let mut entry = Box::new(Entry {
            next_in_bucket: self.buckets[bucket_index].take(),
            hash,
            ref_count: AtomicIsize::new(1),
            string: string.into_boxed_str(),
        });
        let ptr = NonNull::from(&mut *entry);
        self.buckets[bucket_index] = Some(entry);

        ptr
    }

    pub(crate) fn remove(&mut self, ptr: *mut Entry) {
        let bucket_index = {
            let value: &Entry = unsafe { &*ptr };
            debug_assert!(value.ref_count.load(SeqCst) == 0);
            (value.hash & BUCKET_MASK) as usize
        };

        let mut current: &mut Option<Box<Entry>> = &mut self.buckets[bucket_index];

        while let Some(entry_ptr) = current.as_mut() {
            let entry_ptr: *mut Entry = &mut **entry_ptr;
            if entry_ptr == ptr {
                mem::drop(mem::replace(current, unsafe {
                    (*entry_ptr).next_in_bucket.take()
                }));
                break;
            }
            current = unsafe { &mut (*entry_ptr).next_in_bucket };
        }
    }
}
<|endoftext|>


<commit_before>extern crate portmidi as pm;

extern crate rustc_serialize;
extern crate docopt;

const USAGE: &'static str = r#"
portmidi-rs: monitor-device example

Usage:
    monitor-device <id>

Options:
    -h --help   Show this screen.

Omitting <id> will list the available devices.
"#;

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_id: i32,
}

fn print_devices(pm: &pm::PortMidi) {
    for dev in pm.devices().unwrap() {
        println!("{}", dev);
    }
}

fn main() {
    let context = pm::PortMidi::new(1024).unwrap();
    let args: Args = docopt::Docopt::new(USAGE).and_then(|d| d.decode()).unwrap_or_else(|err| {
        print_devices(&context);
        err.exit();
    });
    let info = context.device(args.arg_id).unwrap();
    println!("Listening on: {}) {}", info.id(), info.name());

    let mut in_port = context.input_port(info).unwrap();
    while let Ok(_) = in_port.poll() {
        if let Ok(Some(event)) = in_port.read() {
            println!("{:?}", event);
        }
    }
}
<commit_msg>Read at most `buffer_size` events<commit_after>extern crate portmidi as pm;

extern crate rustc_serialize;
extern crate docopt;

const USAGE: &'static str = r#"
portmidi-rs: monitor-device example

Usage:
    monitor-device <id>

Options:
    -h --help   Show this screen.

Omitting <id> will list the available devices.
"#;

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_id: i32,
}

fn print_devices(pm: &pm::PortMidi) {
    for dev in pm.devices().unwrap() {
        println!("{}", dev);
    }
}

fn main() {
    let context = pm::PortMidi::new(1024).unwrap();
    let args: Args = docopt::Docopt::new(USAGE).and_then(|d| d.decode()).unwrap_or_else(|err| {
        print_devices(&context);
        err.exit();
    });
    let info = context.device(args.arg_id).unwrap();
    println!("Listening on: {}) {}", info.id(), info.name());

    let mut in_port = context.input_port(info).unwrap();
    while let Ok(_) = in_port.poll() {
        if let Ok(Some(event)) = in_port.read_n(1024) {
            println!("{:?}", event);
        }
    }
}
<|endoftext|>