<commit_before>// Copyright 2017 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 Span;

use rustc_errors as errors;
use syntax_pos::MultiSpan;

/// An enum representing a diagnostic level.
#[unstable(feature = "proc_macro_diagnostic", issue = "38356")]
#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
pub enum Level {
    /// An error.
    Error,
    /// A warning.
    Warning,
    /// A note.
    Note,
    /// A help message.
    Help,
}

/// A structure representing a diagnostic message and associated children
/// messages.
#[unstable(feature = "proc_macro_diagnostic", issue = "38356")]
#[derive(Clone, Debug)]
pub struct Diagnostic {
    level: Level,
    message: String,
    span: Option<Span>,
    children: Vec<Diagnostic>
}

macro_rules! diagnostic_child_methods {
    ($spanned:ident, $regular:ident, $level:expr) => (
        /// Add a new child diagnostic message to `self` with the level
        /// identified by this methods name with the given `span` and `message`.
        #[unstable(feature = "proc_macro_diagnostic", issue = "38356")]
        pub fn $spanned<T: Into<String>>(mut self, span: Span, message: T) -> Diagnostic {
            self.children.push(Diagnostic::spanned(span, $level, message));
            self
        }

        /// Add a new child diagnostic message to `self` with the level
        /// identified by this method's name with the given `message`.
        #[unstable(feature = "proc_macro_diagnostic", issue = "38356")]
        pub fn $regular<T: Into<String>>(mut self, message: T) -> Diagnostic {
            self.children.push(Diagnostic::new($level, message));
            self
        }
    )
}

impl Diagnostic {
    /// Create a new diagnostic with the given `level` and `message`.
    #[unstable(feature = "proc_macro_diagnostic", issue = "38356")]
    pub fn new<T: Into<String>>(level: Level, message: T) -> Diagnostic {
        Diagnostic {
            level: level,
            message: message.into(),
            span: None,
            children: vec![]
        }
    }

    /// Create a new diagnostic with the given `level` and `message` pointing to
    /// the given `span`.
    #[unstable(feature = "proc_macro_diagnostic", issue = "38356")]
    pub fn spanned<T: Into<String>>(span: Span, level: Level, message: T) -> Diagnostic {
        Diagnostic {
            level: level,
            message: message.into(),
            span: Some(span),
            children: vec![]
        }
    }

    diagnostic_child_methods!(span_error, error, Level::Error);
    diagnostic_child_methods!(span_warning, warning, Level::Warning);
    diagnostic_child_methods!(span_note, note, Level::Note);
    diagnostic_child_methods!(span_help, help, Level::Help);

    /// Returns the diagnostic `level` for `self`.
    #[unstable(feature = "proc_macro_diagnostic", issue = "38356")]
    pub fn level(&self) -> Level {
        self.level
    }

    /// Emit the diagnostic.
    #[unstable(feature = "proc_macro_diagnostic", issue = "38356")]
    pub fn emit(self) {
        let level = self.level.to_internal();
        let mut diag = errors::Diagnostic::new(level, &*self.message);

        if let Some(span) = self.span {
            diag.set_span(span.0);
        }

        for child in self.children {
            let span = child.span.map_or(MultiSpan::new(), |s| s.0.into());
            let level = child.level.to_internal();
            diag.sub(level, &*child.message, span, None);
        }

        ::__internal::with_sess(move |sess, _| {
            errors::DiagnosticBuilder::new_diagnostic(&sess.span_diagnostic, diag).emit();
        });
    }
}
<commit_msg>Add inspection and setter methods to proc_macro::Diagnostic.<commit_after>// Copyright 2017 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 Span;

use rustc_errors as errors;
use syntax_pos::MultiSpan;

/// An enum representing a diagnostic level.
#[unstable(feature = "proc_macro_diagnostic", issue = "38356")]
#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
pub enum Level {
    /// An error.
    Error,
    /// A warning.
    Warning,
    /// A note.
    Note,
    /// A help message.
    Help,
}

/// A structure representing a diagnostic message and associated children
/// messages.
#[unstable(feature = "proc_macro_diagnostic", issue = "38356")]
#[derive(Clone, Debug)]
pub struct Diagnostic {
    level: Level,
    message: String,
    span: Option<Span>,
    children: Vec<Diagnostic>
}

macro_rules! diagnostic_child_methods {
    ($spanned:ident, $regular:ident, $level:expr) => (
        /// Add a new child diagnostic message to `self` with the level
        /// identified by this methods name with the given `span` and `message`.
        #[unstable(feature = "proc_macro_diagnostic", issue = "38356")]
        pub fn $spanned<T: Into<String>>(mut self, span: Span, message: T) -> Diagnostic {
            self.children.push(Diagnostic::spanned(span, $level, message));
            self
        }

        /// Add a new child diagnostic message to `self` with the level
        /// identified by this method's name with the given `message`.
        #[unstable(feature = "proc_macro_diagnostic", issue = "38356")]
        pub fn $regular<T: Into<String>>(mut self, message: T) -> Diagnostic {
            self.children.push(Diagnostic::new($level, message));
            self
        }
    )
}

#[derive(Debug, Clone)]
#[unstable(feature = "proc_macro_diagnostic", issue = "38356")]
/// Iterator over the children diagnostics of a `Diagnostic`.
pub struct Children<'a>(::std::slice::Iter<'a, Diagnostic>);

#[unstable(feature = "proc_macro_diagnostic", issue = "38356")]
impl<'a> Iterator for Children<'a> {
    type Item = &'a Diagnostic;

    fn next(&mut self) -> Option<Self::Item> {
        self.0.next()
    }
}

#[unstable(feature = "proc_macro_diagnostic", issue = "38356")]
impl Diagnostic {
    /// Create a new diagnostic with the given `level` and `message`.
    #[unstable(feature = "proc_macro_diagnostic", issue = "38356")]
    pub fn new<T: Into<String>>(level: Level, message: T) -> Diagnostic {
        Diagnostic {
            level: level,
            message: message.into(),
            span: None,
            children: vec![]
        }
    }

    /// Create a new diagnostic with the given `level` and `message` pointing to
    /// the given `span`.
    #[unstable(feature = "proc_macro_diagnostic", issue = "38356")]
    pub fn spanned<T: Into<String>>(span: Span, level: Level, message: T) -> Diagnostic {
        Diagnostic {
            level: level,
            message: message.into(),
            span: Some(span),
            children: vec![]
        }
    }

    diagnostic_child_methods!(span_error, error, Level::Error);
    diagnostic_child_methods!(span_warning, warning, Level::Warning);
    diagnostic_child_methods!(span_note, note, Level::Note);
    diagnostic_child_methods!(span_help, help, Level::Help);

    /// Returns the diagnostic `level` for `self`.
    #[unstable(feature = "proc_macro_diagnostic", issue = "38356")]
    pub fn level(&self) -> Level {
        self.level
    }

    /// Sets the level in `self` to `level`.
    #[unstable(feature = "proc_macro_diagnostic", issue = "38356")]
    pub fn set_level(&mut self, level: Level) {
        self.level = level;
    }

    /// Returns the message in `self`.
    #[unstable(feature = "proc_macro_diagnostic", issue = "38356")]
    pub fn message(&self) -> &str {
        &self.message
    }

    /// Sets the message in `self` to `message`.
    #[unstable(feature = "proc_macro_diagnostic", issue = "38356")]
    pub fn set_message<T: Into<String>>(&mut self, message: T) {
        self.message = message.into();
    }

    /// Returns the `Span` in `self`.
    #[unstable(feature = "proc_macro_diagnostic", issue = "38356")]
    pub fn span(&self) -> Option<Span> {
        self.span
    }

    /// Sets the `Span` in `self` to `span`.
    #[unstable(feature = "proc_macro_diagnostic", issue = "38356")]
    pub fn set_span(&mut self, span: Span) {
        self.span = Some(span);
    }

    /// Returns an iterator over the children diagnostics of `self`.
    #[unstable(feature = "proc_macro_diagnostic", issue = "38356")]
    pub fn children(&self) -> Children {
        Children(self.children.iter())
    }

    /// Emit the diagnostic.
    #[unstable(feature = "proc_macro_diagnostic", issue = "38356")]
    pub fn emit(self) {
        let level = self.level.to_internal();
        let mut diag = errors::Diagnostic::new(level, &*self.message);

        if let Some(span) = self.span {
            diag.set_span(span.0);
        }

        for child in self.children {
            let span = child.span.map_or(MultiSpan::new(), |s| s.0.into());
            let level = child.level.to_internal();
            diag.sub(level, &*child.message, span, None);
        }

        ::__internal::with_sess(move |sess, _| {
            errors::DiagnosticBuilder::new_diagnostic(&sess.span_diagnostic, diag).emit();
        });
    }
}
<|endoftext|>


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

//! Support for serializing the dep-graph and reloading it.

#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
      html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
      html_root_url = "https://doc.rust-lang.org/nightly/")]

#![feature(specialization)]

#![recursion_limit="256"]

extern crate graphviz;
#[macro_use] extern crate rustc;
extern crate rustc_data_structures;
extern crate serialize as rustc_serialize;
extern crate rand;

#[macro_use] extern crate log;
extern crate syntax;
extern crate syntax_pos;

mod assert_dep_graph;
pub mod assert_module_sources;
mod persist;

pub use assert_dep_graph::assert_dep_graph;
pub use persist::dep_graph_tcx_init;
pub use persist::load_dep_graph;
pub use persist::load_query_result_cache;
pub use persist::LoadResult;
pub use persist::copy_cgu_workproducts_to_incr_comp_cache_dir;
pub use persist::save_dep_graph;
pub use persist::save_work_product_index;
pub use persist::in_incr_comp_dir;
pub use persist::prepare_session_directory;
pub use persist::finalize_session_directory;
pub use persist::delete_workproduct_files;
pub use persist::garbage_collect_session_directories;
<commit_msg>[nll] librustc_incremental: enable feature(nll) for bootstrap<commit_after>// Copyright 2012-2013 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.

//! Support for serializing the dep-graph and reloading it.

#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
      html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
      html_root_url = "https://doc.rust-lang.org/nightly/")]

#![cfg_attr(not(stage0), feature(nll))]
#![feature(specialization)]

#![recursion_limit="256"]

extern crate graphviz;
#[macro_use] extern crate rustc;
extern crate rustc_data_structures;
extern crate serialize as rustc_serialize;
extern crate rand;

#[macro_use] extern crate log;
extern crate syntax;
extern crate syntax_pos;

mod assert_dep_graph;
pub mod assert_module_sources;
mod persist;

pub use assert_dep_graph::assert_dep_graph;
pub use persist::dep_graph_tcx_init;
pub use persist::load_dep_graph;
pub use persist::load_query_result_cache;
pub use persist::LoadResult;
pub use persist::copy_cgu_workproducts_to_incr_comp_cache_dir;
pub use persist::save_dep_graph;
pub use persist::save_work_product_index;
pub use persist::in_incr_comp_dir;
pub use persist::prepare_session_directory;
pub use persist::finalize_session_directory;
pub use persist::delete_workproduct_files;
pub use persist::garbage_collect_session_directories;
<|endoftext|>


<commit_before>use types::{OscPacket, OscType, OscResult, OscMessage, OscBundle};
use errors::OscError;
use utils;

use std::io;
use std::io::{Read, BufRead};

use byteorder::{BigEndian, ReadBytesExt};

/// Common MTP size for ethernet
pub const MTP: usize = 1536;

pub fn decode(msg: &[u8]) -> OscResult<OscPacket> {
    match msg[0] as char {
        '/' => {
            decode_message(msg)
        }
        '#' => {
            decode_bundle(msg)
        }
        _ => Err(OscError::BadPacket("Unknown message format.".to_string())),
    }
}

fn decode_message(msg: &[u8]) -> OscResult<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let addr: String = try!(read_osc_string(&mut cursor));
    let type_tags: String = try!(read_osc_string(&mut cursor));

    if type_tags.len() > 1 {
        let args: Vec<OscType> = try!(read_osc_args(&mut cursor, type_tags));

        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: Some(args),
        }))
    } else {
        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: None,
        }))
    }
}

fn decode_bundle(msg: &[u8]) -> OscResult<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let b = try!(read_osc_string(&mut cursor));
    if b != "bundle" {
        return Err(OscError::BadBundle);
    }

    let time_tag = try!(read_time_tag(&mut cursor));
    let mut bundle: Vec<OscPacket> = Vec::new();
    let size: usize = try!(cursor.read_u32::<BigEndian>()
                                 .map_err(OscError::ByteOrderError)) as usize;
    let mut buf: Vec<u8> = Vec::new();
    let cnt: usize = try!(cursor.take(size as u64)
                                .read_to_end(&mut buf)
                                .map_err(OscError::ReadError));
    if cnt == size {
        try!(decode(&mut buf).map(|p| bundle.push(p)));
    } else {
        return Err(OscError::BadBundle);
    }

    Ok(OscPacket::Bundle(OscBundle {
        timetag: time_tag,
        content: bundle,
    }))
}

fn read_osc_string(cursor: &mut io::Cursor<&[u8]>) -> OscResult<String> {
    let mut str_buf: Vec<u8> = Vec::new();
    try!(cursor.read_until(0, &mut str_buf)
               .map_err(OscError::ReadError)); // ignore returned byte count
    pad_cursor(cursor);
    // convert to String and remove nul bytes
    String::from_utf8(str_buf)
        .map_err(|e| OscError::StringError(e))
        .map(|s| {
            s.trim_matches(0u8 as char)
             .to_string()
        })
}

fn read_osc_args(cursor: &mut io::Cursor<&[u8]>, raw_type_tags: String) -> OscResult<Vec<OscType>> {
    let type_tags: Vec<char> = raw_type_tags.chars()
                                            .skip(1)
                                            .map(|c| c as char)
                                            .collect();
    let mut args: Vec<OscType> = Vec::with_capacity(type_tags.len());
    for tag in type_tags {
        let arg: OscType = try!(read_osc_arg(cursor, tag));
        args.push(arg);
    }
    Ok(args)
}

fn read_osc_arg(cursor: &mut io::Cursor<&[u8]>, tag: char) -> OscResult<OscType> {
    match tag {
        'f' => {
            cursor.read_f32::<BigEndian>()
                  .map(OscType::Float)
                  .map_err(OscError::ByteOrderError)
        }
        'd' => {
            cursor.read_f64::<BigEndian>()
                  .map(OscType::Double)
                  .map_err(OscError::ByteOrderError)
        }
        'i' => {
            cursor.read_i32::<BigEndian>()
                  .map(OscType::Int)
                  .map_err(OscError::ByteOrderError)
        }
        'h' => {
            cursor.read_i64::<BigEndian>()
                  .map(OscType::Long)
                  .map_err(OscError::ByteOrderError)
        }
        's' => {
            read_osc_string(cursor).map(|s| OscType::String(s))
        }
        't' => {
            // http://opensoundcontrol.org/node/3/#timetags
            read_time_tag(cursor)
        }
        'b' => {
            let size: usize =
                try!(cursor.read_u32::<BigEndian>()
                           .map_err(OscError::ByteOrderError)) as usize;
            let mut byte_buf: Vec<u8> = Vec::with_capacity(size);
            try!(cursor.take(size as u64)
                       .read_to_end(&mut byte_buf)
                       .map_err(OscError::ReadError));
            pad_cursor(cursor);
            Ok(OscType::Blob(byte_buf))

        }
        _ => Err(OscError::BadArg(format!("Type tag \"{}\" is not implemented!", tag))),
    }
}

fn read_time_tag(cursor: &mut io::Cursor<&[u8]>) -> OscResult<OscType> {
    match cursor.read_u32::<BigEndian>() {
        Ok(date) => {
            match cursor.read_u32::<BigEndian>() {
                Ok(frac) => Ok(OscType::Time(date, frac)),
                Err(e) => Err(OscError::ByteOrderError(e)),
            }
        }
        Err(e) => Err(OscError::ByteOrderError(e)),
    }
}

fn pad_cursor(cursor: &mut io::Cursor<&[u8]>) {
    let pos = cursor.position();
    cursor.set_position(utils::pad(pos));
}
<commit_msg>Decode OSC char<commit_after>use types::{OscPacket, OscType, OscResult, OscMessage, OscBundle};
use errors::OscError;
use utils;

use std::{io, char};
use std::io::{Read, BufRead};

use byteorder::{BigEndian, ReadBytesExt};

/// Common MTP size for ethernet
pub const MTP: usize = 1536;

pub fn decode(msg: &[u8]) -> OscResult<OscPacket> {
    match msg[0] as char {
        '/' => {
            decode_message(msg)
        }
        '#' => {
            decode_bundle(msg)
        }
        _ => Err(OscError::BadPacket("Unknown message format.".to_string())),
    }
}

fn decode_message(msg: &[u8]) -> OscResult<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let addr: String = try!(read_osc_string(&mut cursor));
    let type_tags: String = try!(read_osc_string(&mut cursor));

    if type_tags.len() > 1 {
        let args: Vec<OscType> = try!(read_osc_args(&mut cursor, type_tags));

        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: Some(args),
        }))
    } else {
        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: None,
        }))
    }
}

fn decode_bundle(msg: &[u8]) -> OscResult<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let b = try!(read_osc_string(&mut cursor));
    if b != "bundle" {
        return Err(OscError::BadBundle);
    }

    let time_tag = try!(read_time_tag(&mut cursor));
    let mut bundle: Vec<OscPacket> = Vec::new();
    let size: usize = try!(cursor.read_u32::<BigEndian>()
                                 .map_err(OscError::ByteOrderError)) as usize;
    let mut buf: Vec<u8> = Vec::new();
    let cnt: usize = try!(cursor.take(size as u64)
                                .read_to_end(&mut buf)
                                .map_err(OscError::ReadError));
    if cnt == size {
        try!(decode(&mut buf).map(|p| bundle.push(p)));
    } else {
        return Err(OscError::BadBundle);
    }

    Ok(OscPacket::Bundle(OscBundle {
        timetag: time_tag,
        content: bundle,
    }))
}

fn read_osc_string(cursor: &mut io::Cursor<&[u8]>) -> OscResult<String> {
    let mut str_buf: Vec<u8> = Vec::new();
    try!(cursor.read_until(0, &mut str_buf)
               .map_err(OscError::ReadError)); // ignore returned byte count
    pad_cursor(cursor);
    // convert to String and remove nul bytes
    String::from_utf8(str_buf)
        .map_err(|e| OscError::StringError(e))
        .map(|s| {
            s.trim_matches(0u8 as char)
             .to_string()
        })
}

fn read_osc_args(cursor: &mut io::Cursor<&[u8]>, raw_type_tags: String) -> OscResult<Vec<OscType>> {
    let type_tags: Vec<char> = raw_type_tags.chars()
                                            .skip(1)
                                            .map(|c| c as char)
                                            .collect();
    let mut args: Vec<OscType> = Vec::with_capacity(type_tags.len());
    for tag in type_tags {
        let arg: OscType = try!(read_osc_arg(cursor, tag));
        args.push(arg);
    }
    Ok(args)
}

fn read_osc_arg(cursor: &mut io::Cursor<&[u8]>, tag: char) -> OscResult<OscType> {
    match tag {
        'f' => {
            cursor.read_f32::<BigEndian>()
                  .map(OscType::Float)
                  .map_err(OscError::ByteOrderError)
        }
        'd' => {
            cursor.read_f64::<BigEndian>()
                  .map(OscType::Double)
                  .map_err(OscError::ByteOrderError)
        }
        'i' => {
            cursor.read_i32::<BigEndian>()
                  .map(OscType::Int)
                  .map_err(OscError::ByteOrderError)
        }
        'h' => {
            cursor.read_i64::<BigEndian>()
                  .map(OscType::Long)
                  .map_err(OscError::ByteOrderError)
        }
        's' => {
            read_osc_string(cursor).map(|s| OscType::String(s))
        }
        't' => {
            // http://opensoundcontrol.org/node/3/#timetags
            read_time_tag(cursor)
        }
        'b' => {
            let size: usize =
                try!(cursor.read_u32::<BigEndian>()
                           .map_err(OscError::ByteOrderError)) as usize;
            let mut byte_buf: Vec<u8> = Vec::with_capacity(size);
            try!(cursor.take(size as u64)
                       .read_to_end(&mut byte_buf)
                       .map_err(OscError::ReadError));
            pad_cursor(cursor);
            Ok(OscType::Blob(byte_buf))

        }
        'c' => {
            let opt_char = try!(cursor.read_u32::<BigEndian>()
                                      .map(char::from_u32)
                                      .map_err(OscError::ByteOrderError));
            match opt_char {
                Some(c) => Ok(OscType::Char(c)),
                None => Err(OscError::BadArg("Argument is not a char!".to_string())),
            }
        }
        _ => Err(OscError::BadArg(format!("Type tag \"{}\" is not implemented!", tag))),
    }
}

fn read_time_tag(cursor: &mut io::Cursor<&[u8]>) -> OscResult<OscType> {
    match cursor.read_u32::<BigEndian>() {
        Ok(date) => {
            match cursor.read_u32::<BigEndian>() {
                Ok(frac) => Ok(OscType::Time(date, frac)),
                Err(e) => Err(OscError::ByteOrderError(e)),
            }
        }
        Err(e) => Err(OscError::ByteOrderError(e)),
    }
}

fn pad_cursor(cursor: &mut io::Cursor<&[u8]>) {
    let pos = cursor.position();
    cursor.set_position(utils::pad(pos));
}
<|endoftext|>


<commit_before>//! The implementation for Version 1 UUIDs.
//!
//! Note that you need feature `v1` in order to use these features.

use crate::{Uuid, Version};

use atomic::Atomic;

/// The number of 100 ns ticks between the UUID epoch
/// `1582-10-15 00:00:00` and the Unix epoch `1970-01-01 00:00:00`.
const UUID_TICKS_BETWEEN_EPOCHS: u64 = 0x01B2_1DD2_1381_4000;

/// A thread-safe, stateful context for the v1 generator to help ensure
/// process-wide uniqueness.
#[derive(Debug)]
pub struct Context {
    count: Atomic<usize>,
}

/// Stores the number of nanoseconds from an epoch and a counter for ensuring
/// V1 ids generated on the same host are unique.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Timestamp {
    ticks: u64,
    counter: u16,
}

impl Timestamp {
    /// Construct a `Timestamp` from its raw component values: an RFC4122
    /// timestamp and counter.
    ///
    /// RFC4122, which defines the V1 UUID, specifies a 60-byte timestamp format
    /// as the number of 100-nanosecond intervals elapsed since 00:00:00.00,
    /// 15 Oct 1582, "the date of the Gregorian reform of the Christian
    /// calendar."
    ///
    /// The counter value is used to differentiate between ids generated by
    /// the same host computer in rapid succession (i.e. with the same observed
    /// time). See the [`ClockSequence`] trait for a generic interface to any
    /// counter generators that might be used.
    ///
    /// Internally, the timestamp is stored as a `u64`. For this reason, dates
    /// prior to October 1582 are not supported.
    ///
    /// [`ClockSequence`]: trait.ClockSequence.html
    pub const fn from_rfc4122(ticks: u64, counter: u16) -> Self {
        Timestamp { ticks, counter }
    }

    /// Construct a `Timestamp` from a unix timestamp and sequence-generating
    /// `context`.
    ///
    /// A unix timestamp represents the elapsed time since Jan 1 1970. Libc's
    /// `clock_gettime` and other popular implementations traditionally
    /// represent this duration as a `timespec`: a struct with `u64` and
    /// `u32` fields representing the seconds, and "subsecond" or fractional
    /// nanoseconds elapsed since the timestamp's second began,
    /// respectively.
    ///
    /// This constructs a `Timestamp` from the seconds and fractional
    /// nanoseconds of a unix timestamp, converting the duration since 1970
    /// into the number of 100-nanosecond intervals since 00:00:00.00, 15
    /// Oct 1582 specified by RFC4122 and used internally by `Timestamp`.
    ///
    /// The function is not guaranteed to produce monotonically increasing
    /// values however. There is a slight possibility that two successive
    /// equal time values could be supplied and the sequence counter wraps back
    /// over to 0.
    ///
    /// If uniqueness and monotonicity is required, the user is responsible for
    /// ensuring that the time value always increases between calls (including
    /// between restarts of the process and device).
    pub fn from_unix(
        context: impl ClockSequence,
        seconds: u64,
        subsec_nanos: u32,
    ) -> Self {
        let counter = context.generate_sequence(seconds, subsec_nanos);
        let ticks = UUID_TICKS_BETWEEN_EPOCHS
            + seconds * 10_000_000
            + u64::from(subsec_nanos) / 100;

        Timestamp { ticks, counter }
    }

    /// Returns the raw RFC4122 timestamp and counter values stored by the
    /// `Timestamp`.
    ///
    /// The timestamp (the first, `u64` element in the tuple) represents the
    /// number of 100-nanosecond intervals since 00:00:00.00, 15 Oct 1582.
    /// The counter is used to differentiate between ids generated on the
    /// same host computer with the same observed time.
    pub const fn to_rfc4122(&self) -> (u64, u16) {
        (self.ticks, self.counter)
    }

    /// Returns the timestamp converted to the seconds and fractional
    /// nanoseconds since Jan 1 1970.
    ///
    /// Internally, the time is stored in 100-nanosecond intervals,
    /// thus the maximum precision represented by the fractional nanoseconds
    /// value is less than its unit size (100 ns vs. 1 ns).
    pub const fn to_unix(&self) -> (u64, u32) {
        (
            (self.ticks - UUID_TICKS_BETWEEN_EPOCHS) / 10_000_000,
            ((self.ticks - UUID_TICKS_BETWEEN_EPOCHS) % 10_000_000) as u32
                * 100,
        )
    }

    /// Returns the timestamp converted into nanoseconds elapsed since Jan 1
    /// 1970. Internally, the time is stored in 100-nanosecond intervals,
    /// thus the maximum precision represented is less than the units it is
    /// measured in (100 ns vs. 1 ns). The value returned represents the
    /// same duration as [`Timestamp::to_unix`]; this provides it in nanosecond
    /// units for convenience.
    pub const fn to_unix_nanos(&self) -> u64 {
        (self.ticks - UUID_TICKS_BETWEEN_EPOCHS) * 100
    }
}

/// A trait that abstracts over generation of UUID v1 "Clock Sequence" values.
pub trait ClockSequence {
    /// Return a 16-bit number that will be used as the "clock sequence" in
    /// the UUID. The number must be different if the time has changed since
    /// the last time a clock sequence was requested.
    fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> u16;
}

impl<'a, T: ClockSequence + ?Sized> ClockSequence for &'a T {
    fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> u16 {
        (**self).generate_sequence(seconds, subsec_nanos)
    }
}

impl Uuid {
    /// Create a new UUID (version 1) using a time value + sequence +
    /// *NodeId*.
    ///
    /// When generating [`Timestamp`]s using a [`ClockSequence`], this function
    /// is only guaranteed to produce unique values if the following conditions
    /// hold:
    ///
    /// 1. The *NodeId* is unique for this process,
    /// 2. The *Context* is shared across all threads which are generating v1
    ///    UUIDs,
    /// 3. The [`ClockSequence`] implementation reliably returns unique
    ///    clock sequences (this crate provides [`Context`] for this
    ///    purpose. However you can create your own [`ClockSequence`]
    ///    implementation, if [`Context`] does not meet your needs).
    ///
    /// The NodeID must be exactly 6 bytes long.
    ///
    /// Note that usage of this method requires the `v1` feature of this crate
    /// to be enabled.
    ///
    /// # Examples
    ///
    /// A UUID can be created from a unix [`Timestamp`] with a
    /// [`ClockSequence`]:
    ///
    /// ```rust
    /// use uuid::v1::{Timestamp, Context};
    /// use uuid::Uuid;
    ///
    /// let context = Context::new(42);
    /// let ts = Timestamp::from_unix(&context, 1497624119, 1234);
    /// let uuid = Uuid::new_v1(ts, &[1, 2, 3, 4, 5, 6]);
    ///
    /// assert_eq!(
    ///     uuid.to_hyphenated().to_string(),
    ///     "f3b4958c-52a1-11e7-802a-010203040506"
    /// );
    /// ```
    ///
    /// The timestamp can also be created manually as per RFC4122:
    ///
    /// ```
    /// use uuid::v1::{Timestamp, Context};
    /// use uuid::Uuid;
    ///
    /// let context = Context::new(42);
    /// let ts = Timestamp::from_rfc4122(1497624119, 0);
    /// let uuid = Uuid::new_v1(ts, &[1, 2, 3, 4, 5, 6]);
    ///
    /// assert_eq!(
    ///     uuid.to_hyphenated().to_string(),
    ///     "5943ee37-0000-1000-8000-010203040506"
    /// );
    /// ```
    ///
    /// [`Timestamp`]: v1/struct.Timestamp.html
    /// [`ClockSequence`]: v1/struct.ClockSequence.html
    /// [`Context`]: v1/struct.Context.html
    pub const fn new_v1(ts: Timestamp, node_id: &[u8; 6]) -> Self {
        let time_low = (ts.ticks & 0xFFFF_FFFF) as u32;
        let time_mid = ((ts.ticks >> 32) & 0xFFFF) as u16;
        let time_high_and_version =
            (((ts.ticks >> 48) & 0x0FFF) as u16) | (1 << 12);

        let mut d4 = [0; 8];

        d4[0] = (((ts.counter & 0x3F00) >> 8) as u8) | 0x80;
        d4[1] = (ts.counter & 0xFF) as u8;
        d4[2] = node_id[0];
        d4[3] = node_id[1];
        d4[4] = node_id[2];
        d4[5] = node_id[3];
        d4[6] = node_id[4];
        d4[7] = node_id[5];

        Uuid::from_fields(time_low, time_mid, time_high_and_version, &d4)
    }

    /// Returns an optional [`Timestamp`] storing the timestamp and
    /// counter portion parsed from a V1 UUID.
    ///
    /// Returns `None` if the supplied UUID is not V1.
    ///
    /// The V1 timestamp format defined in RFC4122 specifies a 60-bit
    /// integer representing the number of 100-nanosecond intervals
    /// since 00:00:00.00, 15 Oct 1582.
    ///
    /// [`Timestamp`] offers several options for converting the raw RFC4122
    /// value into more commonly-used formats, such as a unix timestamp.
    ///
    /// [`Timestamp`]: v1/struct.Timestamp.html
    pub const fn to_timestamp(&self) -> Option<Timestamp> {
        match self.get_version() {
            Some(Version::Mac) => {
                let ticks: u64 = ((self.as_bytes()[6] & 0x0F) as u64) << 56
                    | ((self.as_bytes()[7]) as u64) << 48
                    | ((self.as_bytes()[4]) as u64) << 40
                    | ((self.as_bytes()[5]) as u64) << 32
                    | ((self.as_bytes()[0]) as u64) << 24
                    | ((self.as_bytes()[1]) as u64) << 16
                    | ((self.as_bytes()[2]) as u64) << 8
                    | (self.as_bytes()[3] as u64);

                let counter: u16 = ((self.as_bytes()[8] & 0x3F) as u16) << 8
                    | (self.as_bytes()[9] as u16);

                Some(Timestamp::from_rfc4122(ticks, counter))
            }
            _ => None,
        }
    }
}

impl Context {
    /// Creates a thread-safe, internally mutable context to help ensure
    /// uniqueness.
    ///
    /// This is a context which can be shared across threads. It maintains an
    /// internal counter that is incremented at every request, the value ends
    /// up in the clock_seq portion of the UUID (the fourth group). This
    /// will improve the probability that the UUID is unique across the
    /// process.
    pub const fn new(count: u16) -> Self {
        Self {
            count: Atomic::new(count as usize),
        }
    }
}

impl ClockSequence for Context {
    fn generate_sequence(&self, _: u64, _: u32) -> u16 {
        (self.count.fetch_add(1, atomic::Ordering::SeqCst) & 0xffff) as u16
    }
}

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

    #[cfg(target_arch = "wasm32")]
    use wasm_bindgen_test::*;

    use crate::{std::string::ToString, Variant};

    #[test]
    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
    fn test_new_v1() {
        let time: u64 = 1_496_854_535;
        let time_fraction: u32 = 812_946_000;
        let node = [1, 2, 3, 4, 5, 6];
        let context = Context::new(0);

        {
            let uuid = Uuid::new_v1(
                Timestamp::from_unix(&context, time, time_fraction),
                &node,
            );

            assert_eq!(uuid.get_version(), Some(Version::Mac));
            assert_eq!(uuid.get_variant(), Variant::RFC4122);
            assert_eq!(
                uuid.to_hyphenated().to_string(),
                "20616934-4ba2-11e7-8000-010203040506"
            );

            let ts = uuid.to_timestamp().unwrap().to_rfc4122();

            assert_eq!(ts.0 - 0x01B2_1DD2_1381_4000, 14_968_545_358_129_460);
            assert_eq!(ts.1, 0);
        };

        {
            let uuid2 = Uuid::new_v1(
                Timestamp::from_unix(&context, time, time_fraction),
                &node,
            );

            assert_eq!(
                uuid2.to_hyphenated().to_string(),
                "20616934-4ba2-11e7-8001-010203040506"
            );
            assert_eq!(uuid2.to_timestamp().unwrap().to_rfc4122().1, 1)
        };
    }
}
<commit_msg>rename to_timestamp to get_timestamp<commit_after>//! The implementation for Version 1 UUIDs.
//!
//! Note that you need feature `v1` in order to use these features.

use crate::{Uuid, Version};

use atomic::Atomic;

/// The number of 100 ns ticks between the UUID epoch
/// `1582-10-15 00:00:00` and the Unix epoch `1970-01-01 00:00:00`.
const UUID_TICKS_BETWEEN_EPOCHS: u64 = 0x01B2_1DD2_1381_4000;

/// A thread-safe, stateful context for the v1 generator to help ensure
/// process-wide uniqueness.
#[derive(Debug)]
pub struct Context {
    count: Atomic<usize>,
}

/// Stores the number of nanoseconds from an epoch and a counter for ensuring
/// V1 ids generated on the same host are unique.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Timestamp {
    ticks: u64,
    counter: u16,
}

impl Timestamp {
    /// Construct a `Timestamp` from its raw component values: an RFC4122
    /// timestamp and counter.
    ///
    /// RFC4122, which defines the V1 UUID, specifies a 60-byte timestamp format
    /// as the number of 100-nanosecond intervals elapsed since 00:00:00.00,
    /// 15 Oct 1582, "the date of the Gregorian reform of the Christian
    /// calendar."
    ///
    /// The counter value is used to differentiate between ids generated by
    /// the same host computer in rapid succession (i.e. with the same observed
    /// time). See the [`ClockSequence`] trait for a generic interface to any
    /// counter generators that might be used.
    ///
    /// Internally, the timestamp is stored as a `u64`. For this reason, dates
    /// prior to October 1582 are not supported.
    ///
    /// [`ClockSequence`]: trait.ClockSequence.html
    pub const fn from_rfc4122(ticks: u64, counter: u16) -> Self {
        Timestamp { ticks, counter }
    }

    /// Construct a `Timestamp` from a unix timestamp and sequence-generating
    /// `context`.
    ///
    /// A unix timestamp represents the elapsed time since Jan 1 1970. Libc's
    /// `clock_gettime` and other popular implementations traditionally
    /// represent this duration as a `timespec`: a struct with `u64` and
    /// `u32` fields representing the seconds, and "subsecond" or fractional
    /// nanoseconds elapsed since the timestamp's second began,
    /// respectively.
    ///
    /// This constructs a `Timestamp` from the seconds and fractional
    /// nanoseconds of a unix timestamp, converting the duration since 1970
    /// into the number of 100-nanosecond intervals since 00:00:00.00, 15
    /// Oct 1582 specified by RFC4122 and used internally by `Timestamp`.
    ///
    /// The function is not guaranteed to produce monotonically increasing
    /// values however. There is a slight possibility that two successive
    /// equal time values could be supplied and the sequence counter wraps back
    /// over to 0.
    ///
    /// If uniqueness and monotonicity is required, the user is responsible for
    /// ensuring that the time value always increases between calls (including
    /// between restarts of the process and device).
    pub fn from_unix(
        context: impl ClockSequence,
        seconds: u64,
        subsec_nanos: u32,
    ) -> Self {
        let counter = context.generate_sequence(seconds, subsec_nanos);
        let ticks = UUID_TICKS_BETWEEN_EPOCHS
            + seconds * 10_000_000
            + u64::from(subsec_nanos) / 100;

        Timestamp { ticks, counter }
    }

    /// Returns the raw RFC4122 timestamp and counter values stored by the
    /// `Timestamp`.
    ///
    /// The timestamp (the first, `u64` element in the tuple) represents the
    /// number of 100-nanosecond intervals since 00:00:00.00, 15 Oct 1582.
    /// The counter is used to differentiate between ids generated on the
    /// same host computer with the same observed time.
    pub const fn to_rfc4122(&self) -> (u64, u16) {
        (self.ticks, self.counter)
    }

    /// Returns the timestamp converted to the seconds and fractional
    /// nanoseconds since Jan 1 1970.
    ///
    /// Internally, the time is stored in 100-nanosecond intervals,
    /// thus the maximum precision represented by the fractional nanoseconds
    /// value is less than its unit size (100 ns vs. 1 ns).
    pub const fn to_unix(&self) -> (u64, u32) {
        (
            (self.ticks - UUID_TICKS_BETWEEN_EPOCHS) / 10_000_000,
            ((self.ticks - UUID_TICKS_BETWEEN_EPOCHS) % 10_000_000) as u32
                * 100,
        )
    }

    /// Returns the timestamp converted into nanoseconds elapsed since Jan 1
    /// 1970. Internally, the time is stored in 100-nanosecond intervals,
    /// thus the maximum precision represented is less than the units it is
    /// measured in (100 ns vs. 1 ns). The value returned represents the
    /// same duration as [`Timestamp::to_unix`]; this provides it in nanosecond
    /// units for convenience.
    pub const fn to_unix_nanos(&self) -> u64 {
        (self.ticks - UUID_TICKS_BETWEEN_EPOCHS) * 100
    }
}

/// A trait that abstracts over generation of UUID v1 "Clock Sequence" values.
pub trait ClockSequence {
    /// Return a 16-bit number that will be used as the "clock sequence" in
    /// the UUID. The number must be different if the time has changed since
    /// the last time a clock sequence was requested.
    fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> u16;
}

impl<'a, T: ClockSequence + ?Sized> ClockSequence for &'a T {
    fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> u16 {
        (**self).generate_sequence(seconds, subsec_nanos)
    }
}

impl Uuid {
    /// Create a new UUID (version 1) using a time value + sequence +
    /// *NodeId*.
    ///
    /// When generating [`Timestamp`]s using a [`ClockSequence`], this function
    /// is only guaranteed to produce unique values if the following conditions
    /// hold:
    ///
    /// 1. The *NodeId* is unique for this process,
    /// 2. The *Context* is shared across all threads which are generating v1
    ///    UUIDs,
    /// 3. The [`ClockSequence`] implementation reliably returns unique
    ///    clock sequences (this crate provides [`Context`] for this
    ///    purpose. However you can create your own [`ClockSequence`]
    ///    implementation, if [`Context`] does not meet your needs).
    ///
    /// The NodeID must be exactly 6 bytes long.
    ///
    /// Note that usage of this method requires the `v1` feature of this crate
    /// to be enabled.
    ///
    /// # Examples
    ///
    /// A UUID can be created from a unix [`Timestamp`] with a
    /// [`ClockSequence`]:
    ///
    /// ```rust
    /// use uuid::v1::{Timestamp, Context};
    /// use uuid::Uuid;
    ///
    /// let context = Context::new(42);
    /// let ts = Timestamp::from_unix(&context, 1497624119, 1234);
    /// let uuid = Uuid::new_v1(ts, &[1, 2, 3, 4, 5, 6]);
    ///
    /// assert_eq!(
    ///     uuid.to_hyphenated().to_string(),
    ///     "f3b4958c-52a1-11e7-802a-010203040506"
    /// );
    /// ```
    ///
    /// The timestamp can also be created manually as per RFC4122:
    ///
    /// ```
    /// use uuid::v1::{Timestamp, Context};
    /// use uuid::Uuid;
    ///
    /// let context = Context::new(42);
    /// let ts = Timestamp::from_rfc4122(1497624119, 0);
    /// let uuid = Uuid::new_v1(ts, &[1, 2, 3, 4, 5, 6]);
    ///
    /// assert_eq!(
    ///     uuid.to_hyphenated().to_string(),
    ///     "5943ee37-0000-1000-8000-010203040506"
    /// );
    /// ```
    ///
    /// [`Timestamp`]: v1/struct.Timestamp.html
    /// [`ClockSequence`]: v1/struct.ClockSequence.html
    /// [`Context`]: v1/struct.Context.html
    pub const fn new_v1(ts: Timestamp, node_id: &[u8; 6]) -> Self {
        let time_low = (ts.ticks & 0xFFFF_FFFF) as u32;
        let time_mid = ((ts.ticks >> 32) & 0xFFFF) as u16;
        let time_high_and_version =
            (((ts.ticks >> 48) & 0x0FFF) as u16) | (1 << 12);

        let mut d4 = [0; 8];

        d4[0] = (((ts.counter & 0x3F00) >> 8) as u8) | 0x80;
        d4[1] = (ts.counter & 0xFF) as u8;
        d4[2] = node_id[0];
        d4[3] = node_id[1];
        d4[4] = node_id[2];
        d4[5] = node_id[3];
        d4[6] = node_id[4];
        d4[7] = node_id[5];

        Uuid::from_fields(time_low, time_mid, time_high_and_version, &d4)
    }

    /// Returns an optional [`Timestamp`] storing the timestamp and
    /// counter portion parsed from a V1 UUID.
    ///
    /// Returns `None` if the supplied UUID is not V1.
    ///
    /// The V1 timestamp format defined in RFC4122 specifies a 60-bit
    /// integer representing the number of 100-nanosecond intervals
    /// since 00:00:00.00, 15 Oct 1582.
    ///
    /// [`Timestamp`] offers several options for converting the raw RFC4122
    /// value into more commonly-used formats, such as a unix timestamp.
    ///
    /// [`Timestamp`]: v1/struct.Timestamp.html
    pub const fn get_timestamp(&self) -> Option<Timestamp> {
        match self.get_version() {
            Some(Version::Mac) => {
                let ticks: u64 = ((self.as_bytes()[6] & 0x0F) as u64) << 56
                    | ((self.as_bytes()[7]) as u64) << 48
                    | ((self.as_bytes()[4]) as u64) << 40
                    | ((self.as_bytes()[5]) as u64) << 32
                    | ((self.as_bytes()[0]) as u64) << 24
                    | ((self.as_bytes()[1]) as u64) << 16
                    | ((self.as_bytes()[2]) as u64) << 8
                    | (self.as_bytes()[3] as u64);

                let counter: u16 = ((self.as_bytes()[8] & 0x3F) as u16) << 8
                    | (self.as_bytes()[9] as u16);

                Some(Timestamp::from_rfc4122(ticks, counter))
            }
            _ => None,
        }
    }
}

impl Context {
    /// Creates a thread-safe, internally mutable context to help ensure
    /// uniqueness.
    ///
    /// This is a context which can be shared across threads. It maintains an
    /// internal counter that is incremented at every request, the value ends
    /// up in the clock_seq portion of the UUID (the fourth group). This
    /// will improve the probability that the UUID is unique across the
    /// process.
    pub const fn new(count: u16) -> Self {
        Self {
            count: Atomic::new(count as usize),
        }
    }
}

impl ClockSequence for Context {
    fn generate_sequence(&self, _: u64, _: u32) -> u16 {
        (self.count.fetch_add(1, atomic::Ordering::SeqCst) & 0xffff) as u16
    }
}

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

    #[cfg(target_arch = "wasm32")]
    use wasm_bindgen_test::*;

    use crate::{std::string::ToString, Variant};

    #[test]
    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
    fn test_new_v1() {
        let time: u64 = 1_496_854_535;
        let time_fraction: u32 = 812_946_000;
        let node = [1, 2, 3, 4, 5, 6];
        let context = Context::new(0);

        {
            let uuid = Uuid::new_v1(
                Timestamp::from_unix(&context, time, time_fraction),
                &node,
            );

            assert_eq!(uuid.get_version(), Some(Version::Mac));
            assert_eq!(uuid.get_variant(), Variant::RFC4122);
            assert_eq!(
                uuid.to_hyphenated().to_string(),
                "20616934-4ba2-11e7-8000-010203040506"
            );

            let ts = uuid.get_timestamp().unwrap().to_rfc4122();

            assert_eq!(ts.0 - 0x01B2_1DD2_1381_4000, 14_968_545_358_129_460);
            assert_eq!(ts.1, 0);
        };

        {
            let uuid2 = Uuid::new_v1(
                Timestamp::from_unix(&context, time, time_fraction),
                &node,
            );

            assert_eq!(
                uuid2.to_hyphenated().to_string(),
                "20616934-4ba2-11e7-8001-010203040506"
            );
            assert_eq!(uuid2.get_timestamp().unwrap().to_rfc4122().1, 1)
        };
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! The display subsystem including window management, font rasterization, and
//! GPU drawing.
use std::sync::mpsc;

use parking_lot::{MutexGuard};

use Rgb;
use cli;
use config::Config;
use font::{self, Rasterize};
use meter::Meter;
use renderer::{self, GlyphCache, QuadRenderer};
use selection::Selection;
use term::{Term, SizeInfo};

use window::{self, Size, Pixels, Window, SetInnerSize};

#[derive(Debug)]
pub enum Error {
    /// Error with window management
    Window(window::Error),

    /// Error dealing with fonts
    Font(font::Error),

    /// Error in renderer
    Render(renderer::Error),
}

impl ::std::error::Error for Error {
    fn cause(&self) -> Option<&::std::error::Error> {
        match *self {
            Error::Window(ref err) => Some(err),
            Error::Font(ref err) => Some(err),
            Error::Render(ref err) => Some(err),
        }
    }

    fn description(&self) -> &str {
        match *self {
            Error::Window(ref err) => err.description(),
            Error::Font(ref err) => err.description(),
            Error::Render(ref err) => err.description(),
        }
    }
}

impl ::std::fmt::Display for Error {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        match *self {
            Error::Window(ref err) => err.fmt(f),
            Error::Font(ref err) => err.fmt(f),
            Error::Render(ref err) => err.fmt(f),
        }
    }
}

impl From<window::Error> for Error {
    fn from(val: window::Error) -> Error {
        Error::Window(val)
    }
}

impl From<font::Error> for Error {
    fn from(val: font::Error) -> Error {
        Error::Font(val)
    }
}

impl From<renderer::Error> for Error {
    fn from(val: renderer::Error) -> Error {
        Error::Render(val)
    }
}

/// The display wraps a window, font rasterizer, and GPU renderer
pub struct Display {
    window: Window,
    renderer: QuadRenderer,
    glyph_cache: GlyphCache,
    render_timer: bool,
    rx: mpsc::Receiver<(u32, u32)>,
    tx: mpsc::Sender<(u32, u32)>,
    meter: Meter,
    font_size_modifier: i8,
    size_info: SizeInfo,
    last_background_color: Rgb,
}

/// Can wakeup the render loop from other threads
pub struct Notifier(window::Proxy);

/// Types that are interested in when the display is resized
pub trait OnResize {
    fn on_resize(&mut self, size: &SizeInfo);
}

impl Notifier {
    pub fn notify(&self) {
        self.0.wakeup_event_loop();
    }
}

impl Display {
    pub fn notifier(&self) -> Notifier {
        Notifier(self.window.create_window_proxy())
    }

    pub fn update_config(&mut self, config: &Config) {
        self.render_timer = config.render_timer();
    }

    /// Get size info about the display
    pub fn size(&self) -> &SizeInfo {
        &self.size_info
    }

    pub fn new(
        config: &Config,
        options: &cli::Options,
    ) -> Result<Display, Error> {
        // Extract some properties from config
        let render_timer = config.render_timer();

        // Create the window where Alacritty will be displayed
        let mut window = Window::new(&options.title)?;

        // get window properties for initializing the other subsytems
        let size = window.inner_size_pixels()
            .expect("glutin returns window size");
        let dpr = window.hidpi_factor();

        info!("device_pixel_ratio: {}", dpr);

        // Create renderer
        let mut renderer = QuadRenderer::new(&config, size)?;

        let (glyph_cache, cell_width, cell_height) =
            Self::new_glyph_cache(&window, &mut renderer, config, 0)?;

        // Resize window to specified dimensions
        let dimensions = options.dimensions()
            .unwrap_or_else(|| config.dimensions());
        let width = cell_width as u32 * dimensions.columns_u32();
        let height = cell_height as u32 * dimensions.lines_u32();
        let size = Size { width: Pixels(width), height: Pixels(height) };
        info!("set_inner_size: {}", size);

        let viewport_size = Size {
            width: Pixels(width + 2 * config.padding().x as u32),
            height: Pixels(height + 2 * config.padding().y as u32),
        };
        window.set_inner_size(&viewport_size);
        renderer.resize(viewport_size.width.0 as _, viewport_size.height.0 as _);
        info!("Cell Size: ({} x {})", cell_width, cell_height);

        let size_info = SizeInfo {
            width: viewport_size.width.0 as f32,
            height: viewport_size.height.0 as f32,
            cell_width: cell_width as f32,
            cell_height: cell_height as f32,
            padding_x: config.padding().x.floor(),
            padding_y: config.padding().y.floor(),
        };

        // Channel for resize events
        //
        // macOS has a callback for getting resize events, the channel is used
        // to queue resize events until the next draw call. Unfortunately, it
        // seems that the event loop is blocked until the window is done
        // resizing. If any drawing were to happen during a resize, it would
        // need to be in the callback.
        let (tx, rx) = mpsc::channel();

        // Clear screen
        let background_color = config.colors().primary.background;
        renderer.with_api(config, &size_info, 0. /* visual bell intensity */, |api| {
            api.clear(background_color);
        });

        Ok(Display {
            window: window,
            renderer: renderer,
            glyph_cache: glyph_cache,
            render_timer: render_timer,
            tx: tx,
            rx: rx,
            meter: Meter::new(),
            font_size_modifier: 0,
            size_info: size_info,
            last_background_color: background_color,
        })
    }

    fn new_glyph_cache(window : &Window, renderer : &mut QuadRenderer,
                       config: &Config, font_size_delta: i8)
        -> Result<(GlyphCache, f32, f32), Error>
    {
        let font = config.font().clone().with_size_delta(font_size_delta as f32);
        let dpr = window.hidpi_factor();
        let rasterizer = font::Rasterizer::new(dpr, config.use_thin_strokes())?;

        // Initialize glyph cache
        let glyph_cache = {
            info!("Initializing glyph cache");
            let init_start = ::std::time::Instant::now();

            let cache = renderer.with_loader(|mut api| {
                GlyphCache::new(rasterizer, &font, &mut api)
            })?;

            let stop = init_start.elapsed();
            let stop_f = stop.as_secs() as f64 + stop.subsec_nanos() as f64 / 1_000_000_000f64;
            info!("Finished initializing glyph cache in {}", stop_f);

            cache
        };

        // Need font metrics to resize the window properly. This suggests to me the
        // font metrics should be computed before creating the window in the first
        // place so that a resize is not needed.
        let metrics = glyph_cache.font_metrics();
        let cell_width = (metrics.average_advance + font.offset().x as f64) as u32;
        let cell_height = (metrics.line_height + font.offset().y as f64) as u32;

        return Ok((glyph_cache, cell_width as f32, cell_height as f32));
    }

    pub fn update_glyph_cache(&mut self, config: &Config, font_size_delta: i8) {
        let cache = &mut self.glyph_cache;
        self.renderer.with_loader(|mut api| {
            let _ = cache.update_font_size(config.font(), font_size_delta, &mut api);
        });

        let metrics = cache.font_metrics();
        self.size_info.cell_width = (metrics.average_advance + config.font().offset().x as f64) as f32;
        self.size_info.cell_height = (metrics.line_height + config.font().offset().y as f64) as f32;
    }

    #[inline]
    pub fn resize_channel(&self) -> mpsc::Sender<(u32, u32)> {
        self.tx.clone()
    }

    pub fn window(&mut self) -> &mut Window {
        &mut self.window
    }

    /// Process pending resize events
    pub fn handle_resize(
        &mut self,
        terminal: &mut MutexGuard<Term>,
        config: &Config,
        items: &mut [&mut OnResize]
    ) {
        // Resize events new_size and are handled outside the poll_events
        // iterator. This has the effect of coalescing multiple resize
        // events into one.
        let mut new_size = None;

        // Take most recent resize event, if any
        while let Ok(sz) = self.rx.try_recv() {
            new_size = Some(sz);
        }

        if terminal.font_size_modifier != self.font_size_modifier {
            // Font size modification detected

            self.font_size_modifier = terminal.font_size_modifier;
            self.update_glyph_cache(config, terminal.font_size_modifier);

            if new_size == None {
                // Force a resize to refresh things
                new_size = Some((self.size_info.width as u32,
                                 self.size_info.height as u32));
            }
        }

        // Receive any resize events; only call gl::Viewport on last
        // available
        if let Some((w, h)) = new_size.take() {
            self.size_info.width = w as f32;
            self.size_info.height = h as f32;

            let size = &self.size_info;
            terminal.resize(size);

            for item in items {
                item.on_resize(size)
            }

            self.window.resize(w, h);
            self.renderer.resize(w as i32, h as i32);
        }

    }

    /// Draw the screen
    ///
    /// A reference to Term whose state is being drawn must be provided.
    ///
    /// This call may block if vsync is enabled
    pub fn draw(&mut self, mut terminal: MutexGuard<Term>, config: &Config, selection: Option<&Selection>) {
        // Clear dirty flag
        terminal.dirty = !terminal.visual_bell.completed();

        if let Some(title) = terminal.get_next_title() {
            self.window.set_title(&title);
        }

        let size_info = *terminal.size_info();
        let visual_bell_intensity = terminal.visual_bell.intensity();

        let background_color = terminal.background_color();
        let background_color_changed = background_color != self.last_background_color;
        self.last_background_color = background_color;

        {
            let glyph_cache = &mut self.glyph_cache;

            // Draw grid
            {
                let _sampler = self.meter.sampler();

                // Make a copy of size_info since the closure passed here
                // borrows terminal mutably
                //
                // TODO I wonder if the renderable cells iter could avoid the
                // mutable borrow
                self.renderer.with_api(config, &size_info, visual_bell_intensity, |mut api| {
                    // Clear screen to update whole background with new color
                    if background_color_changed {
                        api.clear(background_color);
                    }

                    // Draw the grid
                    api.render_cells(terminal.renderable_cells(config, selection), glyph_cache);
                });
            }

            // Draw render timer
            if self.render_timer {
                let timing = format!("{:.3} usec", self.meter.average());
                let color = Rgb { r: 0xd5, g: 0x4e, b: 0x53 };
                self.renderer.with_api(config, &size_info, visual_bell_intensity, |mut api| {
                    api.render_string(&timing[..], glyph_cache, color);
                });
            }
        }

        // Unlock the terminal mutex; following call to swap_buffers() may block
        drop(terminal);
        self.window
            .swap_buffers()
            .expect("swap buffers");

        // Clear after swap_buffers when terminal mutex isn't held. Mesa for
        // some reason takes a long time to call glClear(). The driver descends
        // into xcb_connect_to_fd() which ends up calling __poll_nocancel()
        // which blocks for a while.
        //
        // By keeping this outside of the critical region, the Mesa bug is
        // worked around to some extent. Since this doesn't actually address the
        // issue of glClear being slow, less time is available for input
        // handling and rendering.
        self.renderer.with_api(config, &size_info, visual_bell_intensity, |api| {
            api.clear(background_color);
        });
    }

    pub fn get_window_id(&self) -> Option<usize> {
        self.window.get_window_id()
    }

    /// Adjust the XIM editor position according to the new location of the cursor
    pub fn update_ime_position(&mut self, terminal: &Term) {
        use index::{Point, Line, Column};
        use term::SizeInfo;
        let Point{line: Line(row), col: Column(col)} = terminal.cursor().point;
        let SizeInfo{cell_width: cw,
                    cell_height: ch,
                    padding_x: px,
                    padding_y: py, ..} = *terminal.size_info();
        let nspot_y = (py + (row + 1) as f32 * ch) as i16;
        let nspot_x = (px + col as f32 * cw) as i16;
        self.window().send_xim_spot(nspot_x, nspot_y);
    }
}
<commit_msg>Fix render issues on macOS (#845)<commit_after>// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! The display subsystem including window management, font rasterization, and
//! GPU drawing.
use std::sync::mpsc;

use parking_lot::{MutexGuard};

use Rgb;
use cli;
use config::Config;
use font::{self, Rasterize};
use meter::Meter;
use renderer::{self, GlyphCache, QuadRenderer};
use selection::Selection;
use term::{Term, SizeInfo};

use window::{self, Size, Pixels, Window, SetInnerSize};

#[derive(Debug)]
pub enum Error {
    /// Error with window management
    Window(window::Error),

    /// Error dealing with fonts
    Font(font::Error),

    /// Error in renderer
    Render(renderer::Error),
}

impl ::std::error::Error for Error {
    fn cause(&self) -> Option<&::std::error::Error> {
        match *self {
            Error::Window(ref err) => Some(err),
            Error::Font(ref err) => Some(err),
            Error::Render(ref err) => Some(err),
        }
    }

    fn description(&self) -> &str {
        match *self {
            Error::Window(ref err) => err.description(),
            Error::Font(ref err) => err.description(),
            Error::Render(ref err) => err.description(),
        }
    }
}

impl ::std::fmt::Display for Error {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        match *self {
            Error::Window(ref err) => err.fmt(f),
            Error::Font(ref err) => err.fmt(f),
            Error::Render(ref err) => err.fmt(f),
        }
    }
}

impl From<window::Error> for Error {
    fn from(val: window::Error) -> Error {
        Error::Window(val)
    }
}

impl From<font::Error> for Error {
    fn from(val: font::Error) -> Error {
        Error::Font(val)
    }
}

impl From<renderer::Error> for Error {
    fn from(val: renderer::Error) -> Error {
        Error::Render(val)
    }
}

/// The display wraps a window, font rasterizer, and GPU renderer
pub struct Display {
    window: Window,
    renderer: QuadRenderer,
    glyph_cache: GlyphCache,
    render_timer: bool,
    rx: mpsc::Receiver<(u32, u32)>,
    tx: mpsc::Sender<(u32, u32)>,
    meter: Meter,
    font_size_modifier: i8,
    size_info: SizeInfo,
    last_background_color: Rgb,
}

/// Can wakeup the render loop from other threads
pub struct Notifier(window::Proxy);

/// Types that are interested in when the display is resized
pub trait OnResize {
    fn on_resize(&mut self, size: &SizeInfo);
}

impl Notifier {
    pub fn notify(&self) {
        self.0.wakeup_event_loop();
    }
}

impl Display {
    pub fn notifier(&self) -> Notifier {
        Notifier(self.window.create_window_proxy())
    }

    pub fn update_config(&mut self, config: &Config) {
        self.render_timer = config.render_timer();
    }

    /// Get size info about the display
    pub fn size(&self) -> &SizeInfo {
        &self.size_info
    }

    pub fn new(
        config: &Config,
        options: &cli::Options,
    ) -> Result<Display, Error> {
        // Extract some properties from config
        let render_timer = config.render_timer();

        // Create the window where Alacritty will be displayed
        let mut window = Window::new(&options.title)?;

        // get window properties for initializing the other subsytems
        let size = window.inner_size_pixels()
            .expect("glutin returns window size");
        let dpr = window.hidpi_factor();

        info!("device_pixel_ratio: {}", dpr);

        // Create renderer
        let mut renderer = QuadRenderer::new(&config, size)?;

        let (glyph_cache, cell_width, cell_height) =
            Self::new_glyph_cache(&window, &mut renderer, config, 0)?;

        // Resize window to specified dimensions
        let dimensions = options.dimensions()
            .unwrap_or_else(|| config.dimensions());
        let width = cell_width as u32 * dimensions.columns_u32();
        let height = cell_height as u32 * dimensions.lines_u32();
        let size = Size { width: Pixels(width), height: Pixels(height) };
        info!("set_inner_size: {}", size);

        let viewport_size = Size {
            width: Pixels(width + 2 * config.padding().x as u32),
            height: Pixels(height + 2 * config.padding().y as u32),
        };
        window.set_inner_size(&viewport_size);
        renderer.resize(viewport_size.width.0 as _, viewport_size.height.0 as _);
        info!("Cell Size: ({} x {})", cell_width, cell_height);

        let size_info = SizeInfo {
            width: viewport_size.width.0 as f32,
            height: viewport_size.height.0 as f32,
            cell_width: cell_width as f32,
            cell_height: cell_height as f32,
            padding_x: config.padding().x.floor(),
            padding_y: config.padding().y.floor(),
        };

        // Channel for resize events
        //
        // macOS has a callback for getting resize events, the channel is used
        // to queue resize events until the next draw call. Unfortunately, it
        // seems that the event loop is blocked until the window is done
        // resizing. If any drawing were to happen during a resize, it would
        // need to be in the callback.
        let (tx, rx) = mpsc::channel();

        // Clear screen
        let background_color = config.colors().primary.background;
        renderer.with_api(config, &size_info, 0. /* visual bell intensity */, |api| {
            api.clear(background_color);
        });

        Ok(Display {
            window: window,
            renderer: renderer,
            glyph_cache: glyph_cache,
            render_timer: render_timer,
            tx: tx,
            rx: rx,
            meter: Meter::new(),
            font_size_modifier: 0,
            size_info: size_info,
            last_background_color: background_color,
        })
    }

    fn new_glyph_cache(window : &Window, renderer : &mut QuadRenderer,
                       config: &Config, font_size_delta: i8)
        -> Result<(GlyphCache, f32, f32), Error>
    {
        let font = config.font().clone().with_size_delta(font_size_delta as f32);
        let dpr = window.hidpi_factor();
        let rasterizer = font::Rasterizer::new(dpr, config.use_thin_strokes())?;

        // Initialize glyph cache
        let glyph_cache = {
            info!("Initializing glyph cache");
            let init_start = ::std::time::Instant::now();

            let cache = renderer.with_loader(|mut api| {
                GlyphCache::new(rasterizer, &font, &mut api)
            })?;

            let stop = init_start.elapsed();
            let stop_f = stop.as_secs() as f64 + stop.subsec_nanos() as f64 / 1_000_000_000f64;
            info!("Finished initializing glyph cache in {}", stop_f);

            cache
        };

        // Need font metrics to resize the window properly. This suggests to me the
        // font metrics should be computed before creating the window in the first
        // place so that a resize is not needed.
        let metrics = glyph_cache.font_metrics();
        let cell_width = (metrics.average_advance + font.offset().x as f64) as u32;
        let cell_height = (metrics.line_height + font.offset().y as f64) as u32;

        return Ok((glyph_cache, cell_width as f32, cell_height as f32));
    }

    pub fn update_glyph_cache(&mut self, config: &Config, font_size_delta: i8) {
        let cache = &mut self.glyph_cache;
        self.renderer.with_loader(|mut api| {
            let _ = cache.update_font_size(config.font(), font_size_delta, &mut api);
        });

        let metrics = cache.font_metrics();
        self.size_info.cell_width = ((metrics.average_advance + config.font().offset().x as f64) as f32).floor();
        self.size_info.cell_height = ((metrics.line_height + config.font().offset().y as f64) as f32).floor();
    }

    #[inline]
    pub fn resize_channel(&self) -> mpsc::Sender<(u32, u32)> {
        self.tx.clone()
    }

    pub fn window(&mut self) -> &mut Window {
        &mut self.window
    }

    /// Process pending resize events
    pub fn handle_resize(
        &mut self,
        terminal: &mut MutexGuard<Term>,
        config: &Config,
        items: &mut [&mut OnResize]
    ) {
        // Resize events new_size and are handled outside the poll_events
        // iterator. This has the effect of coalescing multiple resize
        // events into one.
        let mut new_size = None;

        // Take most recent resize event, if any
        while let Ok(sz) = self.rx.try_recv() {
            new_size = Some(sz);
        }

        if terminal.font_size_modifier != self.font_size_modifier {
            // Font size modification detected

            self.font_size_modifier = terminal.font_size_modifier;
            self.update_glyph_cache(config, terminal.font_size_modifier);

            if new_size == None {
                // Force a resize to refresh things
                new_size = Some((self.size_info.width as u32,
                                 self.size_info.height as u32));
            }
        }

        // Receive any resize events; only call gl::Viewport on last
        // available
        if let Some((w, h)) = new_size.take() {
            self.size_info.width = w as f32;
            self.size_info.height = h as f32;

            let size = &self.size_info;
            terminal.resize(size);

            for item in items {
                item.on_resize(size)
            }

            self.window.resize(w, h);
            self.renderer.resize(w as i32, h as i32);
        }

    }

    /// Draw the screen
    ///
    /// A reference to Term whose state is being drawn must be provided.
    ///
    /// This call may block if vsync is enabled
    pub fn draw(&mut self, mut terminal: MutexGuard<Term>, config: &Config, selection: Option<&Selection>) {
        // Clear dirty flag
        terminal.dirty = !terminal.visual_bell.completed();

        if let Some(title) = terminal.get_next_title() {
            self.window.set_title(&title);
        }

        let size_info = *terminal.size_info();
        let visual_bell_intensity = terminal.visual_bell.intensity();

        let background_color = terminal.background_color();
        let background_color_changed = background_color != self.last_background_color;
        self.last_background_color = background_color;

        {
            let glyph_cache = &mut self.glyph_cache;

            // Draw grid
            {
                let _sampler = self.meter.sampler();

                // Make a copy of size_info since the closure passed here
                // borrows terminal mutably
                //
                // TODO I wonder if the renderable cells iter could avoid the
                // mutable borrow
                self.renderer.with_api(config, &size_info, visual_bell_intensity, |mut api| {
                    // Clear screen to update whole background with new color
                    if background_color_changed {
                        api.clear(background_color);
                    }

                    // Draw the grid
                    api.render_cells(terminal.renderable_cells(config, selection), glyph_cache);
                });
            }

            // Draw render timer
            if self.render_timer {
                let timing = format!("{:.3} usec", self.meter.average());
                let color = Rgb { r: 0xd5, g: 0x4e, b: 0x53 };
                self.renderer.with_api(config, &size_info, visual_bell_intensity, |mut api| {
                    api.render_string(&timing[..], glyph_cache, color);
                });
            }
        }

        // Unlock the terminal mutex; following call to swap_buffers() may block
        drop(terminal);
        self.window
            .swap_buffers()
            .expect("swap buffers");

        // Clear after swap_buffers when terminal mutex isn't held. Mesa for
        // some reason takes a long time to call glClear(). The driver descends
        // into xcb_connect_to_fd() which ends up calling __poll_nocancel()
        // which blocks for a while.
        //
        // By keeping this outside of the critical region, the Mesa bug is
        // worked around to some extent. Since this doesn't actually address the
        // issue of glClear being slow, less time is available for input
        // handling and rendering.
        self.renderer.with_api(config, &size_info, visual_bell_intensity, |api| {
            api.clear(background_color);
        });
    }

    pub fn get_window_id(&self) -> Option<usize> {
        self.window.get_window_id()
    }

    /// Adjust the XIM editor position according to the new location of the cursor
    pub fn update_ime_position(&mut self, terminal: &Term) {
        use index::{Point, Line, Column};
        use term::SizeInfo;
        let Point{line: Line(row), col: Column(col)} = terminal.cursor().point;
        let SizeInfo{cell_width: cw,
                    cell_height: ch,
                    padding_x: px,
                    padding_y: py, ..} = *terminal.size_info();
        let nspot_y = (py + (row + 1) as f32 * ch) as i16;
        let nspot_x = (px + col as f32 * cw) as i16;
        self.window().send_xim_spot(nspot_x, nspot_y);
    }
}
<|endoftext|>


<commit_before>//! Traits, implementations, and macros related to logging timely events.

extern crate time;

use std::cell::RefCell;
use std::io::Write;
use std::fs::File;

use ::Data;

use timely_communication::Allocate;
use ::progress::timestamp::RootTimestamp;
use ::progress::nested::product::Product;

use dataflow::scopes::root::Root;
use dataflow::Scope;
use dataflow::operators::capture::{EventWriter, Event, EventPusher};

use abomonation::Abomonation;

/// Logs `record` in `logger` if logging is enabled.
pub fn log<T: Logger>(logger: &'static ::std::thread::LocalKey<T>, record: T::Record) {
    if cfg!(feature = "logging") {
        logger.with(|x| x.log(record));
    }
}

/// Logging methods
pub trait Logger {
    /// The type of loggable record.
    type Record;
    /// Adds `record` to the log.
    fn log(&self, record: Self::Record);
    /// Called with some frequency; behavior unspecified.
    fn flush(&self);
}

pub struct EventStreamLogger<T: Data, S: Write> {
    buffer: RefCell<Vec<(T,u64)>>,
    stream: RefCell<Option<EventWriter<Product<RootTimestamp, u64>, (T,u64), S>>>,
    last_time: RefCell<u64>,
}

impl<T: Data, S: Write> Logger for EventStreamLogger<T, S> {
    type Record = T;
    #[inline]
    fn log(&self, record: T) {
        self.buffer.borrow_mut().push((record, time::precise_time_ns()));
    }
    fn flush(&self) {
        // TODO : sends progress update even if nothing happened.
        // TODO : consider a minimum interval from prior update to
        // TODO : cut down on the amount on logging, at the expense
        // TODO : of freshness on the side of the reader.
        if let Some(ref mut writer) = *self.stream.borrow_mut() {
            let time = time::precise_time_ns();
            if self.buffer.borrow().len() > 0 {
                writer.push(Event::Messages(RootTimestamp::new(time), self.buffer.borrow().clone()));
            }
            writer.push(Event::Progress(vec![(RootTimestamp::new(*self.last_time.borrow()),-1), (RootTimestamp::new(time), 1)]));
            *self.last_time.borrow_mut() = time;
            self.buffer.borrow_mut().clear();
        }
        else {
            panic!("logging file not initialized!!!!");
        }
    }
}

impl<T: Data, S: Write> EventStreamLogger<T, S> {
    fn new() -> EventStreamLogger<T, S> {
        EventStreamLogger {
            buffer: RefCell::new(Vec::new()),
            stream: RefCell::new(None),
            last_time: RefCell::new(0),
        }
    }
    fn set(&self, stream: S) {
        let mut stream = EventWriter::new(stream);
        stream.push(Event::Progress(vec![(RootTimestamp::new(0), 1)]));
        *self.stream.borrow_mut() = Some(stream);
    }
}

impl<T: Data, S: Write> Drop for EventStreamLogger<T, S> {
    fn drop(&mut self) {
        if let Some(ref mut writer) = *self.stream.borrow_mut() {
            if self.buffer.borrow().len() > 0 {
                let time = time::precise_time_ns();
                writer.push(Event::Messages(RootTimestamp::new(time), self.buffer.borrow().clone()));
            }
            writer.push(Event::Progress(vec![(RootTimestamp::new(*self.last_time.borrow()),-1)]));
        }
        else {
            panic!("logging file not initialized!!!!");
        }
    }
}

/// Initializes logging; called as part of `Root` initialization.
pub fn initialize<A: Allocate>(root: &mut Root<A>) {

    OPERATES.with(|x| x.set(File::create(format!("logs/operates-{}.abom", root.index())).unwrap()));
    CHANNELS.with(|x| x.set(File::create(format!("logs/channels-{}.abom", root.index())).unwrap()));
    MESSAGES.with(|x| x.set(File::create(format!("logs/messages-{}.abom", root.index())).unwrap()));
    PROGRESS.with(|x| x.set(File::create(format!("logs/progress-{}.abom", root.index())).unwrap()));
    SCHEDULE.with(|x| x.set(File::create(format!("logs/schedule-{}.abom", root.index())).unwrap()));
    GUARDED_MESSAGE.with(|x| x.set(File::create(format!("logs/guarded_message-{}.abom", root.index())).unwrap()));
    GUARDED_PROGRESS.with(|x| x.set(File::create(format!("logs/guarded_progress-{}.abom", root.index())).unwrap()));
}

/// Flushes logs; called by `Root::step`.
pub fn flush_logs() {
    OPERATES.with(|x| x.flush());
    CHANNELS.with(|x| x.flush());
    PROGRESS.with(|x| x.flush());
    MESSAGES.with(|x| x.flush());
    SCHEDULE.with(|x| x.flush());
    GUARDED_MESSAGE.with(|x| x.flush());
    GUARDED_PROGRESS.with(|x| x.flush());
}

thread_local!(pub static OPERATES: EventStreamLogger<OperatesEvent, File> = EventStreamLogger::new());
thread_local!(pub static CHANNELS: EventStreamLogger<ChannelsEvent, File> = EventStreamLogger::new());
thread_local!(pub static PROGRESS: EventStreamLogger<ProgressEvent, File> = EventStreamLogger::new());
thread_local!(pub static MESSAGES: EventStreamLogger<MessagesEvent, File> = EventStreamLogger::new());
thread_local!(pub static SCHEDULE: EventStreamLogger<ScheduleEvent, File> = EventStreamLogger::new());
thread_local!(pub static GUARDED_MESSAGE: EventStreamLogger<bool, File> = EventStreamLogger::new());
thread_local!(pub static GUARDED_PROGRESS: EventStreamLogger<bool, File> = EventStreamLogger::new());

#[derive(Debug, Clone)]
/// The creation of an `Operate` implementor.
pub struct OperatesEvent {
    /// Worker-unique identifier for the operator.
    pub id: usize,
    /// Sequence of nested scope identifiers indicating the path from the root to this instance.
    pub addr: Vec<usize>,
    /// A helpful name.
    pub name: String,
}

unsafe_abomonate!(OperatesEvent : addr, name);

#[derive(Debug, Clone)]
/// The creation of a channel between operators.
pub struct ChannelsEvent {
    /// Worker-unique identifier for the channel
    pub id: usize,
    /// Sequence of nested scope identifiers indicating the path from the root to this instance.
    pub scope_addr: Vec<usize>,
    /// Source descriptor, indicating operator index and output port.
    pub source: (usize, usize),
    /// Target descriptor, indicating operator index and input port.
    pub target: (usize, usize),
}

unsafe_abomonate!(ChannelsEvent : id, scope_addr, source, target);

#[derive(Debug, Clone)]
/// Send or receive of progress information.
pub struct ProgressEvent {
    /// `true` if the event is a send, and `false` if it is a receive.
    pub is_send: bool,
    /// Sequence of nested scope identifiers indicating the path from the root to this instance.
    pub addr: Vec<usize>,
    /// List of message updates, containing Target descriptor, timestamp as string, and delta.
    pub messages: Vec<(usize, usize, String, i64)>,
    /// List of capability updates, containing Source descriptor, timestamp as string, and delta.
    pub internal: Vec<(usize, usize, String, i64)>,
}

unsafe_abomonate!(ProgressEvent : is_send, addr, messages, internal);

#[derive(Debug, Clone)]
/// Message send or receive event
pub struct MessagesEvent {
    /// `true` if send event, `false` if receive event.
    pub is_send: bool,
    /// Channel identifier
    pub channel: usize,
    /// Source worker index.
    pub source: usize,
    /// Target worker index.
    pub target: usize,
    /// Message sequence number.
    pub seq_no: usize,
    /// Number of typed records in the message.
    pub length: usize,
}

unsafe_abomonate!(MessagesEvent);

#[derive(Debug, Clone)]
/// Operator start or stop.
pub struct ScheduleEvent {
    /// Worker-unique identifier for the operator, linkable to the identifiers in `OperatesEvent`.
    pub id: usize,
    /// `true` if the operator is starting, `false` if it is stopping.
    pub is_start: bool,
}

unsafe_abomonate!(ScheduleEvent : id, is_start);
<commit_msg>logging timestamps batches of messages with least timestamp rather than greatest<commit_after>//! Traits, implementations, and macros related to logging timely events.

extern crate time;

use std::cell::RefCell;
use std::io::Write;
use std::fs::File;

use ::Data;

use timely_communication::Allocate;
use ::progress::timestamp::RootTimestamp;
use ::progress::nested::product::Product;

use dataflow::scopes::root::Root;
use dataflow::Scope;
use dataflow::operators::capture::{EventWriter, Event, EventPusher};

use abomonation::Abomonation;

/// Logs `record` in `logger` if logging is enabled.
pub fn log<T: Logger>(logger: &'static ::std::thread::LocalKey<T>, record: T::Record) {
    if cfg!(feature = "logging") {
        logger.with(|x| x.log(record));
    }
}

/// Logging methods
pub trait Logger {
    /// The type of loggable record.
    type Record;
    /// Adds `record` to the log.
    fn log(&self, record: Self::Record);
    /// Called with some frequency; behavior unspecified.
    fn flush(&self);
}

pub struct EventStreamLogger<T: Data, S: Write> {
    buffer: RefCell<Vec<(T,u64)>>,
    stream: RefCell<Option<EventWriter<Product<RootTimestamp, u64>, (T,u64), S>>>,
    last_time: RefCell<u64>,
}

impl<T: Data, S: Write> Logger for EventStreamLogger<T, S> {
    type Record = T;
    #[inline]
    fn log(&self, record: T) {
        self.buffer.borrow_mut().push((record, time::precise_time_ns()));
    }
    fn flush(&self) {
        // TODO : sends progress update even if nothing happened.
        // TODO : consider a minimum interval from prior update to
        // TODO : cut down on the amount on logging, at the expense
        // TODO : of freshness on the side of the reader.
        if let Some(ref mut writer) = *self.stream.borrow_mut() {
            let time = time::precise_time_ns();
            if self.buffer.borrow().len() > 0 {
                writer.push(Event::Messages(RootTimestamp::new(*self.last_time.borrow()), self.buffer.borrow().clone()));
            }
            writer.push(Event::Progress(vec![(RootTimestamp::new(*self.last_time.borrow()),-1), (RootTimestamp::new(time), 1)]));
            *self.last_time.borrow_mut() = time;
            self.buffer.borrow_mut().clear();
        }
        else {
            panic!("logging file not initialized!!!!");
        }
    }
}

impl<T: Data, S: Write> EventStreamLogger<T, S> {
    fn new() -> EventStreamLogger<T, S> {
        EventStreamLogger {
            buffer: RefCell::new(Vec::new()),
            stream: RefCell::new(None),
            last_time: RefCell::new(0),
        }
    }
    fn set(&self, stream: S) {
        let mut stream = EventWriter::new(stream);
        stream.push(Event::Progress(vec![(RootTimestamp::new(0), 1)]));
        *self.stream.borrow_mut() = Some(stream);
    }
}

impl<T: Data, S: Write> Drop for EventStreamLogger<T, S> {
    fn drop(&mut self) {
        if let Some(ref mut writer) = *self.stream.borrow_mut() {
            if self.buffer.borrow().len() > 0 {
                writer.push(Event::Messages(RootTimestamp::new(*self.last_time.borrow()), self.buffer.borrow().clone()));
            }
            writer.push(Event::Progress(vec![(RootTimestamp::new(*self.last_time.borrow()),-1)]));
        }
        else {
            panic!("logging file not initialized!!!!");
        }
    }
}

/// Initializes logging; called as part of `Root` initialization.
pub fn initialize<A: Allocate>(root: &mut Root<A>) {

    OPERATES.with(|x| x.set(File::create(format!("logs/operates-{}.abom", root.index())).unwrap()));
    CHANNELS.with(|x| x.set(File::create(format!("logs/channels-{}.abom", root.index())).unwrap()));
    MESSAGES.with(|x| x.set(File::create(format!("logs/messages-{}.abom", root.index())).unwrap()));
    PROGRESS.with(|x| x.set(File::create(format!("logs/progress-{}.abom", root.index())).unwrap()));
    SCHEDULE.with(|x| x.set(File::create(format!("logs/schedule-{}.abom", root.index())).unwrap()));
    GUARDED_MESSAGE.with(|x| x.set(File::create(format!("logs/guarded_message-{}.abom", root.index())).unwrap()));
    GUARDED_PROGRESS.with(|x| x.set(File::create(format!("logs/guarded_progress-{}.abom", root.index())).unwrap()));
}

/// Flushes logs; called by `Root::step`.
pub fn flush_logs() {
    OPERATES.with(|x| x.flush());
    CHANNELS.with(|x| x.flush());
    PROGRESS.with(|x| x.flush());
    MESSAGES.with(|x| x.flush());
    SCHEDULE.with(|x| x.flush());
    GUARDED_MESSAGE.with(|x| x.flush());
    GUARDED_PROGRESS.with(|x| x.flush());
}

thread_local!(pub static OPERATES: EventStreamLogger<OperatesEvent, File> = EventStreamLogger::new());
thread_local!(pub static CHANNELS: EventStreamLogger<ChannelsEvent, File> = EventStreamLogger::new());
thread_local!(pub static PROGRESS: EventStreamLogger<ProgressEvent, File> = EventStreamLogger::new());
thread_local!(pub static MESSAGES: EventStreamLogger<MessagesEvent, File> = EventStreamLogger::new());
thread_local!(pub static SCHEDULE: EventStreamLogger<ScheduleEvent, File> = EventStreamLogger::new());
thread_local!(pub static GUARDED_MESSAGE: EventStreamLogger<bool, File> = EventStreamLogger::new());
thread_local!(pub static GUARDED_PROGRESS: EventStreamLogger<bool, File> = EventStreamLogger::new());

#[derive(Debug, Clone)]
/// The creation of an `Operate` implementor.
pub struct OperatesEvent {
    /// Worker-unique identifier for the operator.
    pub id: usize,
    /// Sequence of nested scope identifiers indicating the path from the root to this instance.
    pub addr: Vec<usize>,
    /// A helpful name.
    pub name: String,
}

unsafe_abomonate!(OperatesEvent : addr, name);

#[derive(Debug, Clone)]
/// The creation of a channel between operators.
pub struct ChannelsEvent {
    /// Worker-unique identifier for the channel
    pub id: usize,
    /// Sequence of nested scope identifiers indicating the path from the root to this instance.
    pub scope_addr: Vec<usize>,
    /// Source descriptor, indicating operator index and output port.
    pub source: (usize, usize),
    /// Target descriptor, indicating operator index and input port.
    pub target: (usize, usize),
}

unsafe_abomonate!(ChannelsEvent : id, scope_addr, source, target);

#[derive(Debug, Clone)]
/// Send or receive of progress information.
pub struct ProgressEvent {
    /// `true` if the event is a send, and `false` if it is a receive.
    pub is_send: bool,
    /// Sequence of nested scope identifiers indicating the path from the root to this instance.
    pub addr: Vec<usize>,
    /// List of message updates, containing Target descriptor, timestamp as string, and delta.
    pub messages: Vec<(usize, usize, String, i64)>,
    /// List of capability updates, containing Source descriptor, timestamp as string, and delta.
    pub internal: Vec<(usize, usize, String, i64)>,
}

unsafe_abomonate!(ProgressEvent : is_send, addr, messages, internal);

#[derive(Debug, Clone)]
/// Message send or receive event
pub struct MessagesEvent {
    /// `true` if send event, `false` if receive event.
    pub is_send: bool,
    /// Channel identifier
    pub channel: usize,
    /// Source worker index.
    pub source: usize,
    /// Target worker index.
    pub target: usize,
    /// Message sequence number.
    pub seq_no: usize,
    /// Number of typed records in the message.
    pub length: usize,
}

unsafe_abomonate!(MessagesEvent);

#[derive(Debug, Clone)]
/// Operator start or stop.
pub struct ScheduleEvent {
    /// Worker-unique identifier for the operator, linkable to the identifiers in `OperatesEvent`.
    pub id: usize,
    /// `true` if the operator is starting, `false` if it is stopping.
    pub is_start: bool,
}

unsafe_abomonate!(ScheduleEvent : id, is_start);
<|endoftext|>